diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2020-09-24 19:20:57 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-09-24 19:20:57 +0100 |
| commit | 8b9fdd86970eea615af4efd02bbe017b87f1f4f0 (patch) | |
| tree | 98cfe541f94d86a65d96982829f2948f8b99dab9 /challenge-079 | |
| parent | bb930973179b42ab7b609191749bfc4ed2b3b5eb (diff) | |
| parent | ca7bab766928cad6fd56416a884553f4a0778480 (diff) | |
| download | perlweeklychallenge-club-8b9fdd86970eea615af4efd02bbe017b87f1f4f0.tar.gz perlweeklychallenge-club-8b9fdd86970eea615af4efd02bbe017b87f1f4f0.tar.bz2 perlweeklychallenge-club-8b9fdd86970eea615af4efd02bbe017b87f1f4f0.zip | |
Merge pull request #2369 from juliodcs/juliodcs-week79
add juliodcs week79 perl and raku solutions
Diffstat (limited to 'challenge-079')
| -rw-r--r-- | challenge-079/juliodcs/perl/ch-1.pl | 62 | ||||
| -rw-r--r-- | challenge-079/juliodcs/perl/ch-2.pl | 75 | ||||
| -rw-r--r-- | challenge-079/juliodcs/raku/ch-1.raku | 38 | ||||
| -rw-r--r-- | challenge-079/juliodcs/raku/ch-2.raku | 88 |
4 files changed, 263 insertions, 0 deletions
diff --git a/challenge-079/juliodcs/perl/ch-1.pl b/challenge-079/juliodcs/perl/ch-1.pl new file mode 100644 index 0000000000..5409ee8c5a --- /dev/null +++ b/challenge-079/juliodcs/perl/ch-1.pl @@ -0,0 +1,62 @@ +#!perl + +# This code is way longer than my initial approach: +# +# $total += count_ones to_binary $number-- while $number > 0; +# say $total % 1000000007; +# +# But at the same time it should be much faster +# since the cost is logarithmic +# +# Try me with big numbers! + +use strict; +use warnings; +use feature 'say'; +use experimental 'signatures'; + +use constant MODULE => 1000000007; +use constant INTEGER_LAST => 2**63 - 1; + +use constant W_ACCURATE => 'Warning: intermediate result > Integer\'last. Result *may* not be accurate!'; +use constant E_ACCURATE => 'Error: Number cannot be > Integer\'last'; +use constant E_NO_NUMBER => 'You need to submit a number'; + +sub length_bin($number) { + length sprintf '%b', $number; +} + +# Given a number, it calculates the flips of the most-significant-bit number +# e.g., ms-flips of 13 (1101) returns the number of flips for number 8 (1000) +sub ms_flips($number) { + return 1 if $number == 1; + 1 + ( length_bin($number) - 1 ) * 2**( length_bin($number) - 2 ); +} + +# Remove most significat bit and return number +sub next_number($number) { + $number - 2**( length_bin($number) - 1 ); +} + +sub calculate ( $number, $total = 0 ) { + if ( $number == 0 ) { + say {*STDERR} W_ACCURATE if $total > INTEGER_LAST; + return $total % MODULE; + } + + # All bits besides the first need extra flips + # extra flips are equal to the number itself + my $extra = $total == 0 ? 0 : $number; + + # Use tail call optimization + @_ = ( next_number($number), $total + ms_flips($number) + $extra ); + goto &calculate; +} + +my $number = shift // q(); + +die E_NO_NUMBER if $number !~ m{^\d+$}sxm; + +die E_ACCURATE if $number > INTEGER_LAST; + +say 'Result: ' . calculate($number); diff --git a/challenge-079/juliodcs/perl/ch-2.pl b/challenge-079/juliodcs/perl/ch-2.pl new file mode 100644 index 0000000000..453cb48010 --- /dev/null +++ b/challenge-079/juliodcs/perl/ch-2.pl @@ -0,0 +1,75 @@ +use strict; +use warnings; +use experimental 'signatures'; +use feature qw(say state); +use List::Util qw(max min reduce); + +use constant E_MUST_BE_POSITIVE => 'ERROR: All numbers must be > 0'; +use constant E_NO_DATA => 'ERROR: You need to input some numbers'; +use constant E_NUMERIC => 'ERROR: Only number allowed'; +use constant W_UNALIGNED_FOOTER => "WARNING: footer numbers may not be aligned\n"; + +sub calculate_water($histogram) { + + # Counting water with regex! Yay! + # https://regex101.com/r/Ph88Wi/1/ + my @matches = $histogram =~ m{ + (?: + [#] [ ] \K [ ] + | \G [ ] \K [ ] + ) + (?= [ ]*+ [#] ) # An ending block must exist + }sxmg; + scalar @matches; +} + +sub max_value { + state $max_value = max @ARGV; +} + +sub pad($str) { + sprintf '%' . length( max_value() ) . 's', $str; +} + +sub data_item ( $line, $x_val ) { + $line <= $ARGV[$x_val] ? q{ #} : q{ }; +} + +sub data_line($line) { + reduce { $a . data_item( $line, $b ) } + ( q{}, 0 .. @ARGV - 1 ); +} + +sub histogram_lines { + reduce { $a . sprintf "%s%s\n", pad($b), data_line($b) } + ( q{}, reverse 1 .. max_value() ); +} + +sub separator { + ( pad(q(-)) . q( -) x @ARGV ) . "\n"; +} + +sub footer { + sprintf pad(q( )) . "[%s]\n", join(q( ), @ARGV) +} + +## MAIN ## + +die E_NO_DATA if @ARGV == 0; +die E_NUMERIC if @ARGV != grep { m/^\d+$/ } @ARGV; +die E_MUST_BE_POSITIVE if ( min @ARGV ) < 1; + +my $histogram = histogram_lines(); + +say "\n"; + +use constant MAX_SINGLE_DIGIT => 9; +if (max_value() > MAX_SINGLE_DIGIT) { + say {*STDERR} W_UNALIGNED_FOOTER; +} + +print $histogram; +print separator(); +print footer(); + +say "\nTotal water: " . calculate_water($histogram); diff --git a/challenge-079/juliodcs/raku/ch-1.raku b/challenge-079/juliodcs/raku/ch-1.raku new file mode 100644 index 0000000000..1d120bc689 --- /dev/null +++ b/challenge-079/juliodcs/raku/ch-1.raku @@ -0,0 +1,38 @@ +# This code is way longer than my initial approach:
+#
+# $total += count_ones to_binary $number-- while $number > 0;
+# say $total % 1000000007;
+#
+# But at the same time it should be much faster
+# since the cost is logarithmic
+#
+# Try me with big numbers!
+
+constant \MODULE = 1000000007;
+
+# Given a number, it calculates the flips of the most-significant-bit number
+# e.g., ms-flips of 13 (1101) returns the number of flips for number 8 (1000)
+sub ms-flips(UInt:D \number) returns UInt:D {
+ number == 1 ?? 1 !! 1 + number.msb * 2 ** (number.msb - 1)
+}
+
+# Remove most significat bit and return number
+sub next-number(UInt:D \number) returns UInt:D {
+ number - 2 ** number.msb
+}
+
+sub calculate(UInt:D \number, UInt:D \accumulator = 0) returns UInt:D {
+ return accumulator % MODULE if number == 0;
+
+ # All bits besides the first need extra flips
+ # extra flips are equal to the number itself
+ my \extra-flips = accumulator == 0 ?? 0 !! number;
+ my \next-accumulator = accumulator + ms-flips(number) + extra-flips;
+
+ calculate next-number(number), next-accumulator
+}
+
+sub MAIN(UInt:D \number) returns Nil {
+ say 'Result: ' ~ calculate number;
+ return;
+}
diff --git a/challenge-079/juliodcs/raku/ch-2.raku b/challenge-079/juliodcs/raku/ch-2.raku new file mode 100644 index 0000000000..26097a7438 --- /dev/null +++ b/challenge-079/juliodcs/raku/ch-2.raku @@ -0,0 +1,88 @@ +class WaterHistogram {
+ subset Natural of UInt where * >= 1;
+
+ constant \W_UNALIGNED_FOOTER = "WARNING: footer numbers may not be aligned\n";
+
+ has Natural @!x-values;
+ has Str $!lines;
+
+ method !x-values is rw { @!x-values }
+ method !lines is rw { $!lines }
+
+ method new(*@list) {
+ my $self = WaterHistogram.bless;
+ $self!init: @list;
+ $self
+ }
+
+ method print-it returns Nil {
+ constant \MAX_SINGLE_DIGIT = 9;
+ if self!max-value > MAX_SINGLE_DIGIT {
+ $*ERR.say: W_UNALIGNED_FOOTER;
+ }
+
+ print self!lines;
+ print self!separator;
+ print self!footer;
+
+ return;
+ }
+
+ method count-water returns UInt:D {
+ # Counting water with Raku regex! Yay!
+ elems self!lines ~~ m:g/「 」 <after 「#」 「 」+> <before 「 」* 「#」>/
+ }
+
+ method !separator returns Str:D {
+ self!pad(「-」) ~ 「 -」 x self!x-values ~ "\n";
+ }
+
+ method !footer returns Str:D {
+ self!pad(「 」) ~ sprintf "[%s]\n", self!x-values.join: 「 」
+ }
+
+ method !init(*@list) returns Nil {
+ self!x-values = @list.map: *.Int;
+ self!lines = self!prepare-lines;
+ return;
+ }
+
+ method !prepare-lines returns Str:D {
+ sub add-lines(Str:D $acc, Natural:D $line) {
+ $acc ~ self!pad(~$line) ~ self!data-line($line) ~ "\n"
+ }
+
+ [[&add-lines]] 「」, self!max-value ... 1;
+ }
+
+ method !pad(Str:D $str) returns Str:D {
+ sprintf "%{self!max-value.chars}s", $str;
+ }
+
+ method !data-line(Natural:D $line) returns Str:D {
+ sub add-data-item(Str:D $acc, UInt:D $point-index) {
+ $acc ~ self!data-item( $line, $point-index )
+ }
+
+ [[&add-data-item]] 「」, |^self!x-values.elems
+ }
+
+ method !data-item($line, $x-index) {
+ $line <= self!x-values[$x-index] ?? 「 #」 !! 「 」
+ }
+
+ method !max-value returns Natural:D {
+ state Natural $max = self!x-values.max;
+ $max
+ }
+}
+
+sub MAIN(*@args) {
+ say "\n";
+
+ my $water-histogram = WaterHistogram.new: @args;
+
+ $water-histogram.print-it;
+
+ say "\nTotal water: " ~ $water-histogram.count-water;
+}
|
