From f9ba0f0d5382a406b2200cc7d35282a538437e7a Mon Sep 17 00:00:00 2001 From: Ryan Thompson Date: Thu, 19 Dec 2019 03:55:22 -0600 Subject: Week 039 solutions --- challenge-039/ryan-thompson/perl5/ch-1.pl | 45 ++++++++++++++++ challenge-039/ryan-thompson/perl5/ch-2.pl | 88 +++++++++++++++++++++++++++++++ challenge-039/ryan-thompson/perl6/ch-1.p6 | 47 +++++++++++++++++ challenge-039/ryan-thompson/perl6/ch-2.p6 | 67 +++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100755 challenge-039/ryan-thompson/perl5/ch-1.pl create mode 100755 challenge-039/ryan-thompson/perl5/ch-2.pl create mode 100644 challenge-039/ryan-thompson/perl6/ch-1.p6 create mode 100644 challenge-039/ryan-thompson/perl6/ch-2.p6 diff --git a/challenge-039/ryan-thompson/perl5/ch-1.pl b/challenge-039/ryan-thompson/perl5/ch-1.pl new file mode 100755 index 0000000000..3f1198ab28 --- /dev/null +++ b/challenge-039/ryan-thompson/perl5/ch-1.pl @@ -0,0 +1,45 @@ +#!/usr/bin/env perl +# +# ch-1.pl - Light tracker +# +# Ryan Thompson +# +# Assumption: All times are in the same 00:00 - 23:59 day + +use 5.010; +use warnings; +use strict; + +my %on; # Minutes during which the lights were definitely on + +for () { + # I'll demonstrate a full parse, here, but you could also + # do with a much simpler regex or even split in this case. + /^\s* + \d+\)\s+ # Line number + (? \w+)\s+ # Guest's name + IN: \s+ + (? \d\d):(? \d\d)\s+ # Time in + OUT:\s+ + (? \d\d):(? \d\d)\s* # Time out + $/x or die "Invalid input format: $_"; + + my $in_min = $+{in_hh} * 60 + $+{in_mm}; + my $out_min = $+{out_hh} * 60 + $+{out_mm}; + + $on{$_}++ for $in_min .. $out_min; +} + +say scalar keys %on; + +__DATA__ +0) Ryan IN: 03:25 OUT: 04:20 +1) Alex IN: 09:10 OUT: 09:45 +2) Arnold IN: 09:15 OUT: 09:33 +3) Bob IN: 09:22 OUT: 09:55 +4) Charlie IN: 09:25 OUT: 10:05 +5) Steve IN: 09:33 OUT: 10:01 +6) Roger IN: 09:44 OUT: 10:12 +7) David IN: 09:57 OUT: 10:23 +8) Neil IN: 10:01 OUT: 10:19 +9) Chris IN: 10:10 OUT: 11:00 diff --git a/challenge-039/ryan-thompson/perl5/ch-2.pl b/challenge-039/ryan-thompson/perl5/ch-2.pl new file mode 100755 index 0000000000..1acaf85e30 --- /dev/null +++ b/challenge-039/ryan-thompson/perl5/ch-2.pl @@ -0,0 +1,88 @@ +#!/usr/bin/env perl +# +# ch-2.pl - Extensible RPN calculator +# +# Usage: ch-2.pl '5 r= 2 r ^ 4 ×' # Calculate area of circle with r=5 +# ch-2.pl 'π cos' # Calculate cos(π) +# +# Ryan Thompson + +use 5.010; +use warnings; +use strict; +no warnings 'uninitialized'; +use Scalar::Util 'looks_like_number'; # Core + +# Support UTF8 on output, input (@ARGV), and within the source itself +binmode STDOUT, ':utf8'; +binmode STDERR, ':utf8'; +use Encode 'decode_utf8'; +@ARGV = map { decode_utf8($_, 1) } @ARGV; +use utf8; + +my @stack; # RPN stack +my %op; # Operators dispatch +my %vars; # User-defined namespace + +# Convenience subs to install operations with commonly desired arity +sub nullary(&$) { my ($code, $op) = @_; op_install($code, $op, 0) } +sub unary(&$) { my ($code, $op) = @_; op_install($code, $op, 1) } +sub binary(&$) { my ($code, $op) = @_; op_install($code, $op, 2) } + +# Install binary and unary operators. +# Easy to add more. +binary { $_[0] + $_[1] } '+'; +binary { $_[0] - $_[1] } '-'; +binary { $_[0] * $_[1] } '*'; +binary { $_[0] / $_[1] } '/'; +binary { $_[0] **$_[1] } '^'; +binary { $_[0] % $_[1] } '%'; +unary { } 'pop'; + +unary { my $n = 1; $n *= $_ for 1..pop; $n } '!'; +unary { sin($_[0]) / cos($_[0]) } 'tan'; +unary \&CORE::sin, 'sin'; +unary \&CORE::cos, 'cos'; +unary \&CORE::abs, 'abs'; +unary { 1 / pop } 'inv'; +unary { - pop } 'neg'; + +# Constants are effectively nullary operators +nullary { 3.14159265359 } 'π'; + +# OK, now we're just showing off... 5 x= assigns the value 5 to variable x +for my $var ('a'..'z') { + unary { $vars{$var} = $_[0]; return () } "$var="; + nullary { $vars{$var} } $var; +} + +# Aliases are trivially supported +$op{'×'} = $op{'*'}; +$op{'÷'} = $op{'/'}; +$op{'−'} = $op{'-'}; +$op{mod} = $op{'%'}; # Whatever you like. +$op{Pi} = $op{'π'}; + +die "Usage: $0 'atom ...'\nOperators: @{[ sort keys %op ]}\n" unless @ARGV; + +# The main loop is just a lookup in our dispatch table +for ( map { split } @ARGV ) { + push @stack, looks_like_number($_) ? $_ + : exists $op{$_} ? $op{$_}->() + : die "Unknown operator: `$_'\n"; +} + +die "Too many values left on stack: <" . join(',',@stack) .">" if @stack > 1; +say @stack; + +# A generic installer that supports any arity. Called by nullary(), +# unary(), and binary(), but can be used on its own if need be. +sub op_install { + my ($code, $op, $arity) = @_; + $op{$op} = sub { + die "Stack: @{[ 0+@stack ]} < $arity" if @stack < $arity; + my @operands; + push @operands, pop @stack for 1..$arity; + $code->(@operands); + } +} diff --git a/challenge-039/ryan-thompson/perl6/ch-1.p6 b/challenge-039/ryan-thompson/perl6/ch-1.p6 new file mode 100644 index 0000000000..832aac5f83 --- /dev/null +++ b/challenge-039/ryan-thompson/perl6/ch-1.p6 @@ -0,0 +1,47 @@ +#!/usr/bin/env perl6 + +# ch-1.p6 - Light tracker, with grammars because why not +# +# Ryan Thompson + +#| Grammar for one of the data-lines() +grammar TimeData { + rule TOP { ")" "IN:"