aboutsummaryrefslogtreecommitdiff
path: root/challenge-065
diff options
context:
space:
mode:
authorMohammad S Anwar <mohammad.anwar@yahoo.com>2020-06-21 22:46:05 +0100
committerMohammad S Anwar <mohammad.anwar@yahoo.com>2020-06-21 22:46:05 +0100
commitec35042be02428b9d1fbcae476a1077e2a4903a0 (patch)
tree56e63e620f75156e02fbef8bb44d71e4505eeae0 /challenge-065
parentdd4828f9891502c96741d3fd5f07023708d6fdcc (diff)
downloadperlweeklychallenge-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.pl94
-rw-r--r--challenge-065/colin-crain/perl/ch-2.pl192
-rw-r--r--challenge-065/colin-crain/raku/ch-1.p686
-rw-r--r--challenge-065/colin-crain/raku/ch-2.p6139
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;
+}