aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-079/juliodcs/perl/ch-1.pl62
-rw-r--r--challenge-079/juliodcs/perl/ch-2.pl75
-rw-r--r--challenge-079/juliodcs/raku/ch-1.raku38
-rw-r--r--challenge-079/juliodcs/raku/ch-2.raku88
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;
+}