diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2020-06-21 22:46:05 +0100 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2020-06-21 22:46:05 +0100 |
| commit | ec35042be02428b9d1fbcae476a1077e2a4903a0 (patch) | |
| tree | 56e63e620f75156e02fbef8bb44d71e4505eeae0 /challenge-065 | |
| parent | dd4828f9891502c96741d3fd5f07023708d6fdcc (diff) | |
| download | perlweeklychallenge-club-ec35042be02428b9d1fbcae476a1077e2a4903a0.tar.gz perlweeklychallenge-club-ec35042be02428b9d1fbcae476a1077e2a4903a0.tar.bz2 perlweeklychallenge-club-ec35042be02428b9d1fbcae476a1077e2a4903a0.zip | |
- Added solutions by Colin Crain.
Diffstat (limited to 'challenge-065')
| -rw-r--r-- | challenge-065/colin-crain/perl/ch-1.pl | 94 | ||||
| -rw-r--r-- | challenge-065/colin-crain/perl/ch-2.pl | 192 | ||||
| -rw-r--r-- | challenge-065/colin-crain/raku/ch-1.p6 | 86 | ||||
| -rw-r--r-- | challenge-065/colin-crain/raku/ch-2.p6 | 139 |
4 files changed, 511 insertions, 0 deletions
diff --git a/challenge-065/colin-crain/perl/ch-1.pl b/challenge-065/colin-crain/perl/ch-1.pl new file mode 100644 index 0000000000..d7f7920428 --- /dev/null +++ b/challenge-065/colin-crain/perl/ch-1.pl @@ -0,0 +1,94 @@ +#! /opt/local/bin/perl +# +# digikey_values.pl +# +# TASK #1 › Digits Sum +# Submitted by: Mohammad S Anwar +# Tuned and Tweaked by: Ryan Thompson +# +# You are given two positive numbers $N and $S. +# +# Write a script to list all positive numbers having exactly +# $N digits where sum of all digits equals to $S. +# +# Example +# Input: +# +# $N = 2 +# $S = 4 +# +# Output: +# 13, 22, 31, 40 +# +# # # # # # # # # +# +# METHOD +# +# Perl has the wonderful ability to seamlessly glide between +# looking at individual digits as either raw glyphs or atomic +# numbers. In certain circumstances this peculiar eye is even +# extended to other, non-digit characters. As such we can +# assemble arbitrary digits, so as to positionally represent +# numbers, in exactly the same way we would do so with a +# pencil and paper. +# +# This ability to construct strings of digits and such, and +# then evaluate those strings as representing numbers, opens +# up all kinds of questions of arithmetic number theory. Not +# cleanly fitting into the more common sub-disciplines, one +# might call it positional number theory, or as I like to call +# it (after its poetic cognate), Concrete Number Theory. We +# are no longer looking at just the meaning of the number, but +# also how it looks on the page. +# +# To solve the challenge, we will need to construct a list of +# all numbers of a given positional length. For any given +# length, that list starts at a number constructed with a 1 +# and 0s to fill out the span, and ends with a string of 9s. +# We will need to make an exception of the numbers of length +# 1, that list spans from 0 to 9. We can then filter our list +# with a function that sums the digits to allow elements that +# match the desired value. To sum the digits, we take a number +# and break it apart as we would a string into non-positional +# digits again, iterating through the list produced and +# summing to a collector. We could bring in List::Util::sum to +# replace these two lines with one, but I hardly see the +# point. +# +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + + +use warnings; +use strict; +use feature ":5.26"; + +## ## ## ## ## MAIN: + +my ($digit_count, $target) = @ARGV; +$digit_count //= 4; +$target //= 25; + + +my $start = ($digit_count == 1 ? '0' : '1' ). ( '0' x ($digit_count - 1)); +my $end = '9' x $digit_count; + +my @result_set = grep { sum_digits($_) == $target } ($start..$end); + +if (@result_set) { + say $_ for @result_set; +} +else { + say "there are no numbers of length $digit_count whose digits sum to $target"; +} + +## ## ## ## ## SUBS: + +sub sum_digits { + my @digits = split //, $_[0]; + my $sum; + $sum += $_ for @digits; + return $sum; +} diff --git a/challenge-065/colin-crain/perl/ch-2.pl b/challenge-065/colin-crain/perl/ch-2.pl new file mode 100644 index 0000000000..3015d8a335 --- /dev/null +++ b/challenge-065/colin-crain/perl/ch-2.pl @@ -0,0 +1,192 @@ +#! /opt/local/bin/perl +# +# palindrome_thunderdome.pl +# +# TASK #2 › Palindrome Partition +# Submitted by: Mohammad S Anwar +# Looked Over by: Ryan Thompson +# +# You are given a string $S. Write a script print all possible +# partitions that gives Palindrome. Return -1 if none found. +# +# Please make sure, partition should not overlap. For example, +# for given string “abaab”, the partition “aba” and “baab” +# would not be valid, since they overlap. +# +# Example 1 +# Input: $S = 'aabaab' +# Ouput: 'aa', 'baab' +# Example 2 +# Input: $S = 'abbaba' +# Output: +# There are 2 possible solutions. +# a) 'abba' +# b) 'bb', 'aba' +# +# # # # # # +# +# METHOD +# +# First things first, we’re going to have to define some +# terms. I’d say on the face of it, the specification is +# ambiguous. So let’s break it down: we are asked for “all +# possible partitions that gives Palindrome“. In the +# examples given, the solutions find ways to split the +# string to reveal palindromes contained within, but some +# parts of the string are not included in the answer, +# suggesting that we are in fact being asked to find all +# sets of non-overlapping palindromes that can be found +# within the string. I also note there is also one +# additional solution to Example 1: +# +# aa aa +# +# which is not listed, but as far I understand fits the +# criteria, as the two aa groups do not reference the same +# characters in the string. So by “partition” we mean to +# divide into an ordered list of segments, and then select +# out those segments that are palindromes. Which leads to my +# second clarification, what is a palindrome? Technically +# any single letter is read the same backwards and forwards, +# and as such is, technically, a palindrome. But that, to +# use technical term, is stupid. So we won’t count them. The +# examples given, however, allow for two letter groupings, +# which I also consider a pretty degenerate form and not +# very interesting, but on this I will concede. I do think +# as the only reason we care at all about palindromes is +# because they’re interesting, so I think that’s a pretty +# powerful for excluding common double letters from the +# club. But no mind. +# +# So with our interpretation nailed down, we will proceed. +# +# Lets just go out and say I really wanted to do this with a +# single regex somehow, to parse the whole thing out using +# the RE sublanguage. I then realized that this is a tall +# order, that I didn’t have all week to think this over, and +# it’s not even necessarily even possible. So, one night +# when out on a walk, I thought up the process below, which +# is more of a hybrid approach. +# +# Browsing through the perl RE tutorial, I had wandered +# across a nice version of a regex to identify whether a +# given string is indeed a palindrome. But I didn’t like it, +# because I had a different idea in mind, and in the first +# place I was there to check the syntax for embedding a code +# block that evaluates to a regex on execution. But it was +# encouraging. In any case I found what I was looking for, +# and so made my own. +# +# There are two forms of code block, the first, +# +# (?:{ your_code_here }) +# +# allows the insertion of a logical test, or really any +# arbitrary piece of code, as part of the match process; +# this is a zero-width assertion that must evaluate to a +# true value to continue. +# +# The second form, +# +# (??:{ evaluation_becomes_part_of_the_match_expression } +# +# is what we want. I find the doubling of the ?? as +# analogous to the /ee doubled eval switch. First the code +# is run, the result is inserted in place into the regex and +# then the match evaluated. Ideal. +# +# The idea here is to match one or more characters and +# capture, then possibly a central pivot character, then +# reverse the captured string to check the match: instant +# palindrome. To do this the construct +# +# (.+).?(??:(reverse $1)) +# +# will do the job for us nicely. +# +# To find all the internal palindromes we will need to check +# each substring of at least two characters starting from +# each position in the original string. This is likely to be +# the most expensive operation, but we can constrain it a +# little to keep things manageable. We run the successful +# matches through a hash to keep the list elements unique. +# +# Once we have a master list of palindromes can construct +# individual sets of internal palindromes by recursively +# iterating through the list and passing $’ to the next +# function, adding to the chain until there are no more +# matches to be made. This familiar path walking exercise +# will produce all possible match sequences, so hence all +# ways to divide out internal palindromes, if we allow that +# some of the partitions are not to be counted in the result +# set. +# +# Which is what we decided earlier was what the challenge +# was asking for. +# +# +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + + +use warnings; +use strict; +use feature ":5.26"; + +## ## ## ## ## MAIN: + +my $string = prepare_input( @ARGV ); +$string ||= "aaabaaabaaa"; + +my @palins = all_palindromes($string); + +my $solutions = []; +get_lists( $string, [], $solutions, \@palins); + +for ($solutions->@*) { + say "$_->@*"; +} + +## ## ## ## ## SUBS: + +sub all_palindromes { +## extract every possible palindrome from the input string + my $string = shift; + my %palins; + my $target; + my $start = -1; + while ( $start++ < length($string)-2 ) { + for (2..length($string)-$start) { + $target = substr( $string, $start, $_); + if( $target =~ m/^(.+).?(??{reverse($1)})$/) { + $palins{$target}++; + } + } + } + return sort keys %palins; +} + +sub get_lists { +## recursively walk lists of combinations of palindrome matches + my ($string, $list, $solutions, $palins, ) = @_; + my $joined = join '|', $palins->@*; + if ($string !~ /$joined/) { + push $solutions->@*, $list; + return; + } + for ( $palins->@* ) { + if ($string =~ /$_/) { + my @list = ( $list->@*, $_ ); + get_lists( $', \@list, $solutions, $palins); + } + } +} + +sub prepare_input { + $_ = join '', @_; + s/\W//g; + s/_//g; + return lc; +} diff --git a/challenge-065/colin-crain/raku/ch-1.p6 b/challenge-065/colin-crain/raku/ch-1.p6 new file mode 100644 index 0000000000..0aa53d6f76 --- /dev/null +++ b/challenge-065/colin-crain/raku/ch-1.p6 @@ -0,0 +1,86 @@ +#!/usr/bin/env perl6 +# +# +# digikey_values.raku +# +# TASK #1 › Digits Sum +# Submitted by: Mohammad S Anwar +# Tuned and Tweaked by: Ryan Thompson +# +# You are given two positive numbers $N and $S. +# +# Write a script to list all positive numbers having exactly +# $N digits where sum of all digits equals to $S. +# +# Example +# Input: +# +# $N = 2 +# $S = 4 +# +# Output: +# 13, 22, 31, 40 +# +# # # # # # # # # +# +# METHOD +# +# Perl and Raku have the wonderful ability to seamlessly +# glide between looking at individual digits as either raw +# glyphs or atomic numbers. In certain circumstances this +# peculiar eye is even extended to other, non-digit +# characters. As such we can assemble arbitrary digits, so +# as to positionally represent numbers, in exactly the same +# way we would do so with a pencil and paper. +# +# This ability to construct strings of digits and such, and +# then evaluate those strings as representing numbers, opens +# up all kinds of questions of arithmetic number theory. Not +# cleanly fitting into the more common sub-disciplines, one +# might call it positional number theory, or as I like to +# call it (after its poetic cognate), Concrete Number +# Theory. We are no longer looking at just the meaning of +# the number, but also how it looks on the page. +# +# To solve the challenge, we will need to construct a list +# of all numbers of a given positional length. For any given +# length, that list resembles a range like 1000..9999, which +# can be compuuted with +# +# ($digits-1)**10...($digits**10)-1 +# +# There is undeniably a beautiful symmetry in that +# statement. We will also need to make an exception of the +# numbers of length 1, that list spans from 0 to 9, but it's +# easier to just allow for the single edge case digits=1 and +# target=0. We can accomplish this very clearly using a +# give/when construct. +# +# We can then filter our list with a function that sums the +# digits to allow elements that match the desired value. To +# sum the digits, we take a number and break it apart as we +# would a string into non-positional digits again, iterating +# through the list produced and summing to a collector. We +# could bring use the [+] metaoperator, which I do so love +# doing, but have opted this time to use .sum, for no +# particular reason other than it was made especially to do +# this. +# +# Machines want to be used. It's good to spread the love +# around. +# +# 2020 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + + +sub MAIN (Int:D $digits = 4, Int:D $total = 19 ) { + + my @result_set = grep { ($_.comb.sum) == $total }, (10**($digits-1)..10**$digits-1); + + given @result_set { + when .list.elems > 0 { .say for @result_set } + when $digits == 1 and $total == 0 { say 0 } + say "no numbers of length $digits sum to $total"; ## default + } +} diff --git a/challenge-065/colin-crain/raku/ch-2.p6 b/challenge-065/colin-crain/raku/ch-2.p6 new file mode 100644 index 0000000000..ea7555af5a --- /dev/null +++ b/challenge-065/colin-crain/raku/ch-2.p6 @@ -0,0 +1,139 @@ +#!/usr/bin/env perl6 + +# palindrome_thunderdome.raku +# +# TASK #2 › Palindrome Partition +# Submitted by: Mohammad S Anwar +# Looked Over by: Ryan Thompson +# +# You are given a string $S. Write a script print all possible +# partitions that gives Palindrome. Return -1 if none found. +# +# Please make sure, partition should not overlap. For example, +# for given string “abaab”, the partition “aba” and “baab” +# would not be valid, since they overlap. +# +# Example 1 +# Input: $S = 'aabaab' +# Ouput: 'aa', 'baab' +# Example 2 +# Input: $S = 'abbaba' +# Output: +# There are 2 possible solutions. +# a) 'abba' +# b) 'bb', 'aba' +# +# # # # # # +# +# METHOD +# +# First things first, we’re going to have to define some +# terms. I’d say on the face of it, the specification is +# ambiguous. So let’s break it down: we are asked for “all +# possible partitions that gives Palindrome“. In the +# examples given, the solutions find ways to split the +# string to reveal palindromes contained within, but some +# parts of the string are not included in the answer, +# suggesting that we are in fact being asked to find all +# sets of non-overlapping palindromes that can be found +# within the string. I also note there is also one +# additional solution to Example 1: +# +# aa aa +# +# which is not listed, but as far I understand fits the +# criteria, as the two aa groups do not reference the same +# characters in the string. So by “partition” we mean to +# divide into an ordered list of segments, and then select +# out those segments that are palindromes. Which leads to my +# second clarification, what is a palindrome? Technically +# any single letter is read the same backwards and forwards, +# and as such is, technically, a palindrome. But that, to +# use technical term, is stupid. So we won’t count them. The +# examples given, however, allow for two letter groupings, +# which I also consider a pretty degenerate form and not +# very interesting, but on this I will concede. I do think +# as the only reason we care at all about palindromes is +# because they’re interesting, so I think that’s a pretty +# powerful for excluding common double letters from the +# club. But no mind. +# +# So with our interpretation nailed down, we will proceed. +# +# In Raku side, the get_all_palindromes() routine is straightforward +# with the :exhaustive adjective. Oddly, calling +# .Str on the .list of @matches produces a list containing +# one element of a stringification of all the matches +# separated by spaces, rather than providing access to the +# matches as a list of strings. A one might easily imagine +# this would be a hard bug to catch, as the printed +# representation of the lists are the same, and you would be +# right. As always, dd, with it’s nicely verbose output, is +# your friend. We can then call .unique before returning. +# +# The special variables $&, $` and $' are replaced by $/, +# the current match object, which knows all kinds of things +# about itself. This includes the parts of the original +# string before and after, which are accessed with +# $/.prematch and $/.postmatch. Another thing to notice is +# again we need pointy brackets within the regex we have +# constructed in order to get proper variable interpretation +# for our joined up string of palindrome options. +# +# Once we have a master list of palindromes can construct +# individual sets of internal palindromes by recursively +# iterating through the list and passing $’ to the next +# function, adding to the chain until there are no more +# matches to be made. This familiar path walking exercise +# will produce all possible match sequences, so hence all +# ways to divide out internal palindromes, if we allow that +# some of the partitions are not to be counted in the result +# set. +# +# Which is what we decided earlier was what the challenge +# was asking for. + +# 2020 colin crain +##################################### + + + +sub MAIN( *@input ) { + my $string = process_input(@input); + $string ||= "aaaBBaacXXyz"; ## default processed input + my @palins = get_all_palindromes($string); + + my @solutions; + get_lists($string, [], @solutions, @palins); + + .put for @solutions; +} + +sub get_all_palindromes ( $string ) { + my @matches = $string ~~ m:ex/ (.+) {} .? "{$0.flip}" /; + my @list = @matches.map: {.Str}; + return @list.unique; +} + +sub get_lists ($string, @list, @solutions, @palins) { +## recursively walk lists of combinations of palindrome matches + + my $joined = @palins.join: '||'; + unless $string ~~ m/<$joined>/ { + @solutions.push: @list; + return; + } + for ( @palins) -> $item { + if ($string ~~ m/$item/) { + my @newlist = @list; + @newlist.push: $item ; + get_lists( $/.postmatch, @newlist, @solutions, @palins); + } + } +} + +sub process_input ( @input ) { + my $string = @input.join; + $string ~~ s:g/\W//; + return $string; +} |
