diff options
59 files changed, 3151 insertions, 1566 deletions
diff --git a/challenge-096/jaldhar-h-vyas/blog.txt b/challenge-096/jaldhar-h-vyas/blog.txt new file mode 100644 index 0000000000..c87e41fff8 --- /dev/null +++ b/challenge-096/jaldhar-h-vyas/blog.txt @@ -0,0 +1 @@ +https://www.braincells.com/perl/2021/02/perl_weekly_challenge_week_96.html diff --git a/challenge-096/jaldhar-h-vyas/perl/ch-1.sh b/challenge-096/jaldhar-h-vyas/perl/ch-1.sh new file mode 100755 index 0000000000..5beec9b643 --- /dev/null +++ b/challenge-096/jaldhar-h-vyas/perl/ch-1.sh @@ -0,0 +1 @@ +perl -E 'say join q{ }, (reverse @ARGV);' $@
\ No newline at end of file diff --git a/challenge-096/jaldhar-h-vyas/perl/ch-2.pl b/challenge-096/jaldhar-h-vyas/perl/ch-2.pl new file mode 100755 index 0000000000..3114d70648 --- /dev/null +++ b/challenge-096/jaldhar-h-vyas/perl/ch-2.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl +use 5.020; +use warnings; +use English qw/ -no_match_vara /; + +sub usage { + print<<"-USAGE-"; +Usage: + $PROGRAM_NAME <from> <to> + + <from> string to convert from + <to> string to convert to +-USAGE- + exit 0; +} + +sub min { + return (sort { $a <=> $b } @_)[0]; +} + +sub levenshtein { + my ($from, $to) = @_; + my $fromLength = length $from; + my $toLength = length $to; + + if ($toLength == 0) { + return $fromLength; + } + + if ($fromLength == 0) { + return $toLength; + } + + my $fromTail = substr($from, 1, $fromLength - 1); + my $toTail = substr($to, 1, $toLength - 1); + + if (substr($from, 0, 1) eq substr($to, 0, 1)) { + return levenshtein($fromTail, $toTail); + } + + return 1 + min( + levenshtein($from, $toTail), # Insert + levenshtein($fromTail, $to), # Remove + levenshtein($fromTail, $toTail) # Replace + ); +} + +if (scalar @ARGV < 2) { + usage(); +} + +say levenshtein($ARGV[0], $ARGV[1]); diff --git a/challenge-096/jaldhar-h-vyas/raku/ch-1.sh b/challenge-096/jaldhar-h-vyas/raku/ch-1.sh new file mode 100755 index 0000000000..9c33ad4bd2 --- /dev/null +++ b/challenge-096/jaldhar-h-vyas/raku/ch-1.sh @@ -0,0 +1 @@ +raku -e '@*ARGS.reverse.join(q{ }).say;' $@
\ No newline at end of file diff --git a/challenge-096/jaldhar-h-vyas/raku/ch-2.raku b/challenge-096/jaldhar-h-vyas/raku/ch-2.raku new file mode 100755 index 0000000000..33b152b7c6 --- /dev/null +++ b/challenge-096/jaldhar-h-vyas/raku/ch-2.raku @@ -0,0 +1,34 @@ +#!/usr/bin/raku + +sub levenshtein(Str $from, Str $to) { + my $fromLength = $from.chars; + my $toLength = $to.chars; + + if $toLength == 0 { + return $fromLength; + } + + if $fromLength == 0 { + return $toLength; + } + + my $fromTail = $from.substr(1, $fromLength - 1); + my $toTail = $to.substr(1, $toLength - 1); + + if $from.substr(0, 1) eq $to.substr(0, 1) { + return levenshtein($fromTail, $toTail); + } + + return 1 + ( + levenshtein($from, $toTail), # Insert + levenshtein($fromTail, $to), # Remove + levenshtein($fromTail, $toTail) # Replace + ).min; +} + +sub MAIN( + Str $S1, #= string to convert from + Str $S2, #= string to convert to +) { + say levenshtein($S1, $S2); +}
\ No newline at end of file diff --git a/challenge-100/dave-jacoby/blog.txt b/challenge-100/dave-jacoby/blog.txt new file mode 100644 index 0000000000..b064b34fee --- /dev/null +++ b/challenge-100/dave-jacoby/blog.txt @@ -0,0 +1 @@ +https://jacoby.github.io/2021/02/16/turning-over-a-new-digit-perl-weekly-challenge-100.html diff --git a/challenge-100/dave-jacoby/node/ch-2.js b/challenge-100/dave-jacoby/node/ch-2.js new file mode 100644 index 0000000000..5f023375c6 --- /dev/null +++ b/challenge-100/dave-jacoby/node/ch-2.js @@ -0,0 +1,45 @@ +"use strict"; + +var input = []; +input.push([[1], [2, 4], [6, 4, 9], [5, 1, 7, 2]]); +input.push([[3], [3, 1], [5, 2, 3], [4, 3, 1, 3]]); + +for (let i = 0; i < input.length; i++) { + triangle_sum(input[i]); +} + +function triangle_sum(input) { + let results = triangle(input, 0, 0, []).sort(function(a, b) { return a - b }); + console.log(input); + console.log(results[0]); + console.log(""); +} + +function triangle(input, x, y, path) { + if (x > 5) { + return; + } + let output = []; + + if ("undefined" === typeof input[x]) { + output.push(path.reduce((a, b) => a + b, 0)); + } else { + let v = input[x][y]; + let next_path = [...path]; + next_path.push(v); + + output.push(...triangle(input, x + 1, y, next_path)); + output.push(...triangle(input, x + 1, y + 1, next_path)); + } + return output; +} + + +// [ [ 1 ], [ 2, 4 ], [ 6, 4, 9 ], [ 5, 1, 7, 2 ] ] +// 8 +// +// [ [ 3 ], [ 3, 1 ], [ 5, 2, 3 ], [ 4, 3, 1, 3 ] ] +// 7 + + + diff --git a/challenge-100/dave-jacoby/perl/ch-1.pl b/challenge-100/dave-jacoby/perl/ch-1.pl new file mode 100644 index 0000000000..df96c5ef42 --- /dev/null +++ b/challenge-100/dave-jacoby/perl/ch-1.pl @@ -0,0 +1,70 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use feature qw{ say postderef signatures state }; +no warnings qw{ experimental::postderef experimental::signatures }; + +# You are given a time (12 hour / 24 hour). +# +# Write a script to convert the given time from 12 hour format to 24 hour format and vice versa. +# +# Ideally we expect a one-liner. + +my @times = + sort { $b =~ /m/ <=> $a =~ /m/ } + sort + + ( + '5:14', '05:15 pm', '05:15pm', '05:15 am', '05:15am', '17:15', + '19:15', '07:15 pm', '07:15pm', '12:00am', '12:00pm', '00:00', + '12:00', '24:00', '7:7am', '7:7pm' + ); + +for my $time (@times) { + say join "\t", '', $time, ' <=> ', switch_time($time); + say ''; +} + +# 12pm is noon +# 12am is midnight +sub switch_time ( $time ) { + my $out = ''; + + # 12-hour time + if ( $time =~ /m$/mix ) { + my ( $hr, $min, $ampm ) = $time =~ /(\d+):(\d+)\s*(am|pm|)/mix; + $out = join ':', + ( + $ampm eq 'am' + ? ( + $hr == 0 ? '00': $hr + ) + : ( + $hr == '12' + ? sprintf '%02d', + $min + : sprintf '%02d', + $hr + 12 + ) + ), + ( sprintf '%02d', $min ); + } + + # 24-hour time + else { + my ( $hr, $min ) = $time =~ /(\d+):(\d+)/mix; + $out = join '', + ( + $hr == 0 || $hr == 24 + ? 12 + : ( $hr > 12 ? $hr % 12 : $hr ) + ), + (':'), + ( sprintf '%02d', $min ), + ( $hr < 12 ? 'am' : 'pm' ); + } + return $out; +} + + diff --git a/challenge-100/dave-jacoby/perl/ch-2.pl b/challenge-100/dave-jacoby/perl/ch-2.pl new file mode 100644 index 0000000000..15d761b17f --- /dev/null +++ b/challenge-100/dave-jacoby/perl/ch-2.pl @@ -0,0 +1,48 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use feature qw{ say postderef signatures state }; +no warnings qw{ experimental::postderef experimental::signatures }; + +use List::Util qw{sum}; +use JSON; +my $json = JSON->new; +my $p = JSON->new->pretty->canonical; + +my @input; +push @input, [ [1], [ 2, 4 ], [ 6, 4, 9 ], [ 5, 1, 7, 2 ] ]; +push @input, [ [3], [ 3, 1 ], [ 5, 2, 3 ], [ 4, 3, 1, 3 ] ]; + +for my $input (@input) { + triangle_sum($input); +} + +sub triangle_sum ( $input ) { + my ($short) = + sort { $a->{sum} <=> $b->{sum} } triangle($input); + say qq{ sum: $short->{sum} }; + say q{ path: } . join ' ', $short->{path}->@*; + for my $i ( $input->@* ) { + say join ' ', ' ', $i->@*; + } + say ''; +} + +sub triangle ( $input, $x = 0, $y = 0, @path ) { + my @output; + + # if not a leaf, go left and right + if ( defined $input->[$x][$y] ) { + push @output, triangle( $input, $x + 1, $y, @path, $y ); + push @output, triangle( $input, $x + 1, $y + 1, @path, $y ); + } + + # if a leaf, find the sum, find the path, and return + else { + my @ind = map { $path[$_] } 0 .. $x - 1; + my $sum = sum map { $input->[$_][ $path[$_] ] } 0 .. $x - 1; + push @output, { sum => $sum, path => \@ind, }; + } + return @output; +} diff --git a/challenge-100/frankivo/scala/FunTime.scala b/challenge-100/frankivo/scala/FunTime.scala new file mode 100644 index 0000000000..97ae8f09a5 --- /dev/null +++ b/challenge-100/frankivo/scala/FunTime.scala @@ -0,0 +1,54 @@ +object FunTime {
+ val examples = Seq[String](
+ "07:04am",
+ "08:24pm",
+ "08:24am",
+ "09:39 am",
+ "08:24",
+ "11:59",
+ "12:00",
+ "12:01",
+ "12:34",
+ "13:37",
+ "20:24",
+ "18:04"
+ )
+
+ def getTime(time: String) : (Int, Int) = {
+ val h :: m :: _ = ("([0-9]{2})".r findAllIn time).toSeq
+ (h.toInt, m.toInt)
+ }
+
+ def makeTime(hour: Int, minute: Int, suffix: String = "") = {
+ "%02d:%02d%s".format(hour, minute, " " + suffix)
+ }
+
+ def to12H(time: String): String = {
+ val parsed = getTime(time)
+
+ val suffix = if (parsed._1 < 12) "am" else "pm"
+ val hour = if (parsed._1 > 12) parsed._1 - 12 else parsed._1
+
+ makeTime(hour, parsed._2, suffix)
+ }
+
+ def to24H(time: String): String = {
+ val parsed = getTime(time)
+ val hour = if (time.contains("pm")) parsed._1 + 12 else parsed._1
+
+ makeTime(hour, parsed._2)
+ }
+
+ def convert(time: String) : String = {
+ if (("(am|pm)$".r findFirstIn time).isDefined)
+ to24H(time)
+ else
+ to12H(time)
+ }
+
+ def main(args: Array[String]): Unit = {
+ examples
+ .map(convert)
+ .foreach(println)
+ }
+}
\ No newline at end of file diff --git a/challenge-100/frankivo/scala/TriangleSum.scala b/challenge-100/frankivo/scala/TriangleSum.scala new file mode 100644 index 0000000000..3ee251de13 --- /dev/null +++ b/challenge-100/frankivo/scala/TriangleSum.scala @@ -0,0 +1,21 @@ +object TriangleSum {
+ val examples = Seq(
+ "[1], [2,4], [6,4,9], [5,1,7,2]",
+ "[3], [3,1], [5,2,3], [4,3,1,3]"
+ )
+
+ // def parseExample(e: String) : Array[Array[Int]] = {
+ def parseExample(e: String) : Unit = {
+ e
+ .split(" ")
+ .map(_.replaceAll("""([\[\]])""", ""))
+ .map(_.split(", ").toString)
+ .foreach(println)
+ }
+
+ def main(args: Array[String]): Unit = {
+ examples
+ .take(1).map(parseExample)
+ // .foreach(println)
+ }
+}
\ No newline at end of file diff --git a/challenge-100/james-smith/perl/ch-1.pl b/challenge-100/james-smith/perl/ch-1.pl index e241822661..57352d1f30 100644 --- a/challenge-100/james-smith/perl/ch-1.pl +++ b/challenge-100/james-smith/perl/ch-1.pl @@ -6,6 +6,18 @@ use warnings; use feature qw(say); use Test::More; +is( ft( '05:15pm' ), '17:15' ); +is( ft( '05:15 pm' ), '17:15' ); +is( ft( '17:15' ), '05:15pm' ); +is( ft( '05:15am' ), '05:15' ); +is( ft( '05:15 am' ), '05:15' ); +is( ft( '05:15' ), '05:15am' ); +is( ft( '00:00' ), '12:00am' ); +is( ft( '12:00' ), '12:00pm' ); +is( ft( '24:00' ), '12:00pm' ); +is( ft( '12:00 am' ), '00:00' ); +is( ft( '12:00 pm' ), '12:00' ); + is( fun_time( '05:15pm' ), '17:15' ); is( fun_time( '05:15 pm' ), '17:15' ); is( fun_time( '17:15' ), '05:15pm' ); @@ -18,52 +30,56 @@ is( fun_time( '24:00' ), '12:00pm' ); is( fun_time( '12:00 am' ), '00:00' ); is( fun_time( '12:00 pm' ), '12:00' ); -is( fun_time_readable( '05:15pm' ), '17:15' ); -is( fun_time_readable( '05:15 pm' ), '17:15' ); -is( fun_time_readable( '17:15' ), '05:15pm' ); -is( fun_time_readable( '05:15am' ), '05:15' ); -is( fun_time_readable( '05:15 am' ), '05:15' ); -is( fun_time_readable( '05:15' ), '05:15am' ); -is( fun_time_readable( '00:00' ), '12:00am' ); -is( fun_time_readable( '12:00' ), '12:00pm' ); -is( fun_time_readable( '24:00' ), '12:00pm' ); -is( fun_time_readable( '12:00 am' ), '00:00' ); -is( fun_time_readable( '12:00 pm' ), '12:00' ); - done_testing(); ## 72 chars ############################################################ -## Just split so slightly more readable and fits on 72 char lines -sub fun_time { $_[0]=~s{(\d+):(\d+)\s*(\wm|)}{sprintf'%02d:%02d%s', - ($1%12||(12*!$3))+12*('pm'eq$3),$2,$3?'':$1>11?'pm':'am'}re; } +## Just split so slightly more readable and fits on 60 char lines +## Not nasty hack - we pop rather than shift as it saves 2 bytes! +## We assume that the minute portion will be two digits after the +## ":" then we don't need to check it.... + +## 110 bytes total - 102 inside the curly braces.. + +sub ft{pop=~s/(.+)(:..)\s*(.m|)/sprintf'%02d%s%s', +($1%12||(12*!$3))+12*('pm'eq$3),$2,$3?'':$1<12?'am':'pm'/re} ## This is more readable version with notes... -sub fun_time_readable { - return $_[0] =~ - s{ - ## Split into 3 parts, $1 - hours, $2 - minutes & $3 - am/pm - (\d+) : (\d+) \s* ( \wm | ) +sub fun_time { + return pop =~ + ## Note the nasty hack we pop rather than shift - that saves 2 bytes + ## in our golfdom.... + s/ + ## Split into 3 parts, $1 - hours, $2 - minutes & $3 - am-pm + (.+) (:..) \s* ( .m | ) ## We assume all strings are valid - so we don't have to anchor ## at both ends or worry what the 12hr clock sufficies are - ## am/pm & \wm is shorter than [ap]m + ## am-pm and .m is shorter than [ap]m + ## + ## We assume that the time will always have a : followed + ## 2 digits... ## - ## Note if we right (\wm)? the 3rd capture variable $3 is - ## sometimes undefined - better is to use ([ap]m|) which + ## Note if we right (.m)? the 3rd capture variable $3 is + ## sometimes undefined - better is to use (.m|) which ## matches the same way but $3 is now an empty string not ## undefined when we have a 24 hour clock time - } - { - sprintf '%02d:%02d%s', - ( $1%12 || (12*!$3) ) + 12*('pm'eq$3), + / + sprintf '%02d%s%s', + ( $1 % 12 || ( 12 * ! $3 ) ) + 12 * ( 'pm' eq $3 ), ## Get hour modulo 12.. ## From 24hr to 12hr clock we need to convert 00:?? to 12:?? ## From 12hr to 24hr clock it is pm we then need to add 12... + ## Note we use the "yoda condition" for the equals + ## 'pm'eq$3 + ## as this is a byte shorter than the more usual way of + ## writing inequalitys + ## $3 eq'pm' + ## as we don't need a space between the $3 & the eq... $2, ## The minutes is the easy bit just copy.. - $3 ? '' : $1>11 ? 'pm' : 'am' + $3 ? '' : $1 < 12 ? 'am' : 'pm' ## If we are converting from 12hr clock the third string is - ## empty - if not and the time is <12 we return am o/w pm - }rex; + ## empty - if not and the time is <12 we return am otherwise pm + /rex; } diff --git a/challenge-100/james-smith/perl/ch-2.pl b/challenge-100/james-smith/perl/ch-2.pl index 0b00be3ba6..46a05310f1 100644 --- a/challenge-100/james-smith/perl/ch-2.pl +++ b/challenge-100/james-smith/perl/ch-2.pl @@ -6,11 +6,36 @@ use warnings; use feature qw(say); use Test::More; -is( triangle_sum( [1],[2,4],[6,4,9],[5,1,7,2] ), 8 ); -is( triangle_sum( [3],[3,1],[5,2,3],[4,3,1,3] ), 7 ); +## A little check to see if the sum functions are +## non-destructive... +my @Q = ( [1],[2,4],[6,4,9],[5,1,7,2] ); +triangle_sum_1point5_liner( @Q ); +is( triangle_sum_1point5_liner( @Q ), 8 ); +@Q = ( [1],[2,4],[6,4,9],[5,1,7,2] ); +triangle_sum( @Q ); +is( triangle_sum( @Q ), 8 ); + +is( triangle_sum( [1],[2,4],[6,4,9],[5,1,7,2] ), 8 ); +is( triangle_sum( [3],[3,1],[5,2,3],[4,3,1,3] ), 7 ); +is( triangle_sum( [3],[3,1],[3,8,9],[4,3,1,3] ), 12 ); +is( triangle_sum( [2],[3,7],[8,5,6],[6,1,9,3] ), 11 ); +is( triangle_sum( [3],[6,4],[5,2,7],[9,1,8,6] ), 10 ); + +is( triangle_sum_1point5_liner( [1],[2,4],[6,4,9],[5,1,7,2] ), 8 ); +is( triangle_sum_1point5_liner( [3],[3,1],[5,2,3],[4,3,1,3] ), 7 ); +is( triangle_sum_1point5_liner( [3],[3,1],[3,8,9],[4,3,1,3] ), 12 ); +is( triangle_sum_1point5_liner( [2],[3,7],[8,5,6],[6,1,9,3] ), 11 ); +is( triangle_sum_1point5_liner( [3],[6,4],[5,2,7],[9,1,8,6] ), 10 ); done_testing(); +display_sum( [1],[2,4],[6,4,9],[5,1,7,2] ); +display_sum( [3],[3,1],[5,2,3],[4,3,1,3] ); +display_sum( [3],[3,1],[3,8,9],[4,3,1,3] ); +display_sum( [2],[3,7],[8,5,6],[6,1,9,3] ); +display_sum( [3],[6,4],[5,2,7],[9,1,8,6] ); + + ## 72 chars ############################################################ ## There are two directions you can go with this problem (up or down) @@ -21,13 +46,65 @@ done_testing(); ## repeating until the triangle only has a single cell the answer.. sub triangle_sum { - my @tri = @_; + my @tri = map{ [@{$_}] } @_; while(@tri>1) { ## Strip off base of triangle... my $b = pop @tri; ## Update new last line by adding smallest of it's "children" - $tri[-1][$_] += $b->[$b->[$_]<$b->[$_+1]?$_:$_+1] for 0..@tri-1; + $tri[-1][$_] += $b->[ + $b->[$_] < $b->[$_+1] ? $_ : $_+1 + ] for 0..@tri-1; } return $tri[0][0]; } +## First thing we do is make a deep copy of @_ as this like the +## previous function is destructive. @_ is an array of references +## and although manipulating @_ doesn't affect the variable passed +## in it does affect the contents of any references passed in. +## +## We can convert the inner for loop into a map... and pop the value +## of $b in the while clause so we can simplify this down to a single +## one line statement, with the return just returning the last +## element of $b - here we are using the implicit my $b & return +## +## so not quite a 1 liner - but close enough!! + +sub triangle_sum_1point5_liner { + @_ = map{ [@{$_}] } @_; ## Deep copy as destructive.. + @{$_[-1]} = map { + $_[-1][$_] + $b->[ $b->[$_] < $b->[$_+1] ? $_ : $_+1 ] + } 0..@_-1 while @{$b=pop @_}>1; + $b->[0]; +} + +## A subroutine to display the triangle indicating the route! +sub display_sum { + my @tri = map{ [@{$_}] } @_; ## Deep copy the triangle as the + ## search is destructive + my @route; ## For each node in the "current" bottom row, the route + ## is the list of indecies of the child nodes that make + ## up the "optimal" path + ## We use the implicit my on $b + while(@{$b = pop @tri}>1) { + ($tri[-1][$_],$route[$_]) = $b->[$_]<$b->[$_+1] + ? ( $tri[-1][$_] + $b->[$_], [$_, @{$route[$_ ]||[]}] ) + : ( $tri[-1][$_] + $b->[$_+1], [$_+1,@{$route[$_+1]||[]}] ) + foreach 0..@tri-1; + } + @route = (0,@{$route[0]}); ## We need to add the top node index + ## (always 0), at the same time we can + ## just take the first (only) + ## path out of the 2d route matrix; + print ## Assume all cell numbers are single digits... + '', |
