diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2019-07-14 13:09:59 +0100 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2019-07-14 13:09:59 +0100 |
| commit | 0f531cb9e0bd3c41bef47c5645d6ba25f77c9730 (patch) | |
| tree | 12f82ec02c9406f0e48c4192c531a283e3f68b94 /challenge-016 | |
| parent | f61185a0238f14a02308a06440e20c2b3556a967 (diff) | |
| download | perlweeklychallenge-club-0f531cb9e0bd3c41bef47c5645d6ba25f77c9730.tar.gz perlweeklychallenge-club-0f531cb9e0bd3c41bef47c5645d6ba25f77c9730.tar.bz2 perlweeklychallenge-club-0f531cb9e0bd3c41bef47c5645d6ba25f77c9730.zip | |
- Added solutions by Athanasius.
Diffstat (limited to 'challenge-016')
| -rw-r--r-- | challenge-016/athanasius/blog.txt | 1 | ||||
| -rw-r--r-- | challenge-016/athanasius/perl5/ch-1.pl | 44 | ||||
| -rw-r--r-- | challenge-016/athanasius/perl5/ch-2.pl | 111 | ||||
| -rw-r--r-- | challenge-016/athanasius/perl6/ch-1.p6 | 28 | ||||
| -rw-r--r-- | challenge-016/athanasius/perl6/ch-2.p6 | 109 |
5 files changed, 293 insertions, 0 deletions
diff --git a/challenge-016/athanasius/blog.txt b/challenge-016/athanasius/blog.txt new file mode 100644 index 0000000000..f60d4bc7dc --- /dev/null +++ b/challenge-016/athanasius/blog.txt @@ -0,0 +1 @@ +http://blogs.perl.org/users/athanasius/2019/07/perl-weekly-challenge-016.html diff --git a/challenge-016/athanasius/perl5/ch-1.pl b/challenge-016/athanasius/perl5/ch-1.pl new file mode 100644 index 0000000000..b6789357a8 --- /dev/null +++ b/challenge-016/athanasius/perl5/ch-1.pl @@ -0,0 +1,44 @@ +use strict; +use warnings; +use Const::Fast; +use constant DEBUG => 0; + +const my $GUESTS => 100; + +MAIN: +{ + my $pie = 1; + my $max_guest = 1; + my $max_piece = 1 / $GUESTS; + my $sum = $max_piece if DEBUG; + $pie -= $max_piece; + + printf("\nGuest %*d gets %43.40f%% of the original pie\n", + length $GUESTS, $max_guest, $max_piece * 100) if DEBUG; + + for my $guest (2 .. $GUESTS) + { + my $piece = ($guest / $GUESTS) * $pie; + $pie -= $piece; + + if (DEBUG) + { + printf "Guest %*d gets %43.40f%% of the original pie\n", + length $GUESTS, $guest, $piece * 100; + $sum += $piece; + } + + if ($piece > $max_piece) + { + $max_piece = $piece; + $max_guest = $guest; + } + } + + printf "\nGuest %d of %d gets the largest piece, which is " . + "%.2f%% of the original pie\n", $max_guest, $GUESTS, + $max_piece * 100; + + printf("\nCheck: sum of pieces = %.13f%%\n", $sum * 100) + if DEBUG; +} diff --git a/challenge-016/athanasius/perl5/ch-2.pl b/challenge-016/athanasius/perl5/ch-2.pl new file mode 100644 index 0000000000..c61a6f3d1c --- /dev/null +++ b/challenge-016/athanasius/perl5/ch-2.pl @@ -0,0 +1,111 @@ +use strict; +use warnings; +use Const::Fast; +use Crypt::Misc qw( decode_b58b ); +use Digest::SHA; + +const my $DEFAULT_ADDR => '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2'; +const my %ADDR_FORMATS => (1 => 'P2PKH', 3 => 'P2SH', + bc1 => 'Bech32'); +const my $INVALID_CHARS => qr{([^1-9A-HJ-NP-Za-km-z])}; +const my $MAX_CHARS => 35; +const my $MIN_CHARS => 26; +const my $SHA_ALGORITHM => 256; +const my $TAB => ' '; + +MAIN: +{ + my $address = $ARGV[0] // $DEFAULT_ADDR; + + print "\nBitcoin address: \"$address\"\n"; + + if (my $error = validate_format($address, \my $format)) + { + print "${TAB}Format validation FAILED: $error\n"; + } + elsif ($format eq 'Bech32') + { + print "${TAB}Bech32 format not currently supported\n"; + } + else + { + print "${TAB}Format is \"$format\"\n"; + + if ($error = validate_chars($address)) + { + print "${TAB}Character validation FAILED: $error\n"; + } + elsif (validate_checksum($address)) + { + print "${TAB}Checksum validation PASSED\n"; + } + else + { + print "${TAB}Checksum validation FAILED\n"; + } + } +} + +sub validate_format +{ + my ($address, $format) = @_; + my $error; + + for my $prefix (keys %ADDR_FORMATS) + { + if ($address =~ qr/^$prefix/) + { + $$format = $ADDR_FORMATS{$prefix}; + last; + } + } + + unless (defined $$format) + { + my $len = substr($address, 0, 1) eq 'b' ? + substr($address, 1, 1) eq 'c' ? 3 : 2 : 1; + $error = 'invalid prefix "' . substr($address, 0, $len) . + '", unknown format'; + } + + return $error; +} + +sub validate_chars +{ + my ($address) = @_; + my $chars = length $address; + my $error; + + if ($chars < $MIN_CHARS) + { + $error = "invalid length $chars (minimum is $MIN_CHARS)"; + } + elsif ($chars > $MAX_CHARS) + { + $error = "invalid length $chars (maximum is $MAX_CHARS)"; + } + elsif ($address =~ $INVALID_CHARS) + { + $error = "invalid character \"$1\""; + } + + return $error; +} + +sub validate_checksum +{ + my ($address) = @_; + my $rawdata = decode_b58b($address); # Base58 to bytes + my $hexdata = unpack 'H*', $rawdata; # Bytes to hex + my $checksum1 = substr $hexdata, -8; # Checksum 1 in hex + my $payload = substr $hexdata, 0, -8; # Payload in hex + my $sha_obj = Digest::SHA->new($SHA_ALGORITHM); + $sha_obj->add(pack 'H*', $payload); # Hex to bytes + my $digest1 = $sha_obj->hexdigest; # 1st digest in hex + $sha_obj->add(pack 'H*', $digest1); # hex to bytes + my $digest2 = $sha_obj->hexdigest; # 2nd digest in hex + my $checksum2 = substr $digest2, 0, 8; # Checksum 2 in hex + + return $checksum1 eq $checksum2; # Compare checksums +} diff --git a/challenge-016/athanasius/perl6/ch-1.p6 b/challenge-016/athanasius/perl6/ch-1.p6 new file mode 100644 index 0000000000..6e66ce3648 --- /dev/null +++ b/challenge-016/athanasius/perl6/ch-1.p6 @@ -0,0 +1,28 @@ +use v6; + +my UInt constant $GUESTS = 100; + +sub MAIN() +{ + my Real $pie = 1; + my UInt $max-guest = 1; + my Real $max-piece = 1 / $GUESTS; + $pie -= $max-piece; + + for 2 .. $GUESTS -> UInt $guest + { + my Real $piece = ($guest / $GUESTS) * $pie; + $pie -= $piece; + + if ($piece > $max-piece) + { + $max-piece = $piece; + $max-guest = $guest; + } + } + + my Real $max-piece-pc = $max-piece * 100; + + say "\nGuest $max-guest of $GUESTS gets the largest piece, ", + "which is $max-piece-pc.round(0.01)% of the original pie"; +} diff --git a/challenge-016/athanasius/perl6/ch-2.p6 b/challenge-016/athanasius/perl6/ch-2.p6 new file mode 100644 index 0000000000..6df7a7752a --- /dev/null +++ b/challenge-016/athanasius/perl6/ch-2.p6 @@ -0,0 +1,109 @@ +use v6; +use experimental :pack; +use Crypt::Misc:from<Perl5> <decode_b58b>; +use Digest::SHA256::Native; + +my Sub $decode_b58b := &Crypt::Misc::decode_b58b; + +my constant %ADDR-FORMATS = + (1 => 'P2PKH', 3 => 'P2SH', bc1 => 'Bech32'); +my Str constant $DEFAULT-ADDR = + '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2'; +my Regex constant $INVALID-CHARS = + rx{ ( <-[1..9A..HJ..NP..Za..km..z]> ) }; +my UInt constant $MAX-CHARS = 35; +my UInt constant $MIN-CHARS = 26; +my Str constant $TAB = ' '; + +sub MAIN(Str:D $address = $DEFAULT-ADDR) +{ + print "\nBitcoin address: \"$address\"\n"; + my Str:D $format = ''; + + if my $error = validate-format($address, $format) + { + print "{$TAB}Format validation FAILED: $error\n"; + } + elsif $format eq 'Bech32' + { + print "{$TAB}Bech32 format not currently supported\n"; + } + else + { + print "{$TAB}Format is \"$format\"\n"; + + if $error = validate-chars($address) + { + print "{$TAB}Character validation FAILED: $error\n"; + } + elsif validate-checksum($address) + { + print "{$TAB}Checksum validation PASSED\n"; + } + else + { + print "{$TAB}Checksum validation FAILED\n"; + } + } +} + +sub validate-format(Str:D $address, Str:D $format is rw) +{ + my Str $error; + + for keys %ADDR-FORMATS -> Str $prefix + { + if $address ~~ /^$prefix/ + { + $format = %ADDR-FORMATS{$prefix}; + last; + } + } + + unless $format + { + my UInt $len = $address.substr(0, 1) eq 'b' ?? + $address.substr(1, 1) eq 'c' ?? 3 !! 2 !! 1; + + $error = 'invalid prefix "' ~ $address.substr(0, $len) ~ + '", unknown format'; + } + + return $error; +} + +sub validate-chars(Str:D $address) +{ + my $chars = $address.chars; + my Str $error; + + if $chars < $MIN-CHARS + { + $error = "invalid length $chars (minimum is $MIN-CHARS)"; + } + elsif $chars > $MAX-CHARS + { + $error = "invalid length $chars (maximum is $MAX-CHARS)"; + } + elsif $address ~~ $INVALID-CHARS + { + $error = "invalid character \"$0\""; + } + + return $error; +} + +sub validate-checksum(Str:D $address) +{ + my Blob[uint8] $raw-data = $decode_b58b($address); + my Str $hex-data = $raw-data.unpack('H*'); + my Str $hex-checksum1 = $hex-data.substr(*-8); + my Str $hex-payload = $hex-data.substr(0, *-8); + my Blob[uint8] $raw-payload = pack('H*', $hex-payload); + my Str $hex-digest1 = sha256-hex($raw-payload); + my Blob[uint8] $raw_digest1 = pack('H*', $hex-digest1); + my Str $hex-digest2 = sha256-hex($raw_digest1); + my Str $hex-checksum2 = $hex-digest2.substr(0, 8); + + return $hex-checksum1 eq $hex-checksum2; +} |
