From 164bfa12b037c6af747e57f98c79e67db31fda43 Mon Sep 17 00:00:00 2001 From: Noud Aldenhoven Date: Tue, 24 Sep 2019 17:22:51 +0200 Subject: Solutions to challenge 027 problem 1 and 2 in Perl 6 by Noud --- challenge-027/noud/perl6/ch-1.p6 | 52 ++++++++++++++++++++++++++++++++++++++++ challenge-027/noud/perl6/ch-2.p6 | 41 +++++++++++++++++++++++++++++++ challenge-027/noud/perl6/exm.p6 | 6 +++++ 3 files changed, 99 insertions(+) create mode 100644 challenge-027/noud/perl6/ch-1.p6 create mode 100644 challenge-027/noud/perl6/ch-2.p6 create mode 100644 challenge-027/noud/perl6/exm.p6 diff --git a/challenge-027/noud/perl6/ch-1.p6 b/challenge-027/noud/perl6/ch-1.p6 new file mode 100644 index 0000000000..4e17f3819b --- /dev/null +++ b/challenge-027/noud/perl6/ch-1.p6 @@ -0,0 +1,52 @@ +# Write a script to find the intersection of two straight lines. The +# co-ordinates of the two lines should be provided as command line parameter. +# For example: +# +# The two ends of Line 1 are represented as co-ordinates (a,b) and (c,d). +# The two ends of Line 2 are represented as co-ordinates (p,q) and (r,s). +# +# The script should print the co-ordinates of point of intersection of the +# above two lines. + +# Computational geometry is always difficult, because there are so many border +# cases you have to take into account. I hope I covered all of them. +sub line_intersection(($x1, $y1), ($x2, $y2), ($x3, $y3), ($x4, $y4)) { + if (($x1 == $x2 and $y1 == $y2) or ($x3 == $x4 and $y3 == $y4)) { + die "Input doesn't represent two lines."; + } + my $disc = ($x1 - $x2) * ($y3 - $y4) - ($y1 - $y2) * ($x3 - $x4); + if ($disc == 0) { + if ($x1 == $x2 and $x2 == $x3 and $x3 == $x4) { + # Lines coincide vertically. Return one coinciding point. + return ($x1, $y1); + } + if ($y1 == $y2 and $y2 == $y3 and $y3 == $y4) { + # Lines coincide horizontally. Return one coinciding point. + return ($x1, $y1); + } + if (($y1 - $x1) * ($x4 - $x2) == ($y2 - $x2) * ($x3 - $x1)) { + # Lines coincide diagonally. Return one coinciding point. + return ($x1, $y1); + } + # If the discriminant is zero, the two lines are parallel to each + # other. Therefore, depending on your definitions the lines don't + # intersect, or they intersect at infinity, introducing a + # non-Euclidian geometry. I choose the latter. + return Inf; + } + # Discriminant is non-zero, hence there is one intersecting point. + return ((($x1 * $y2 - $y1 * $x2) * ($x3 - $x4) + - ($x3 * $y4 - $y3 * $x4) * ($x1 - $x2)) / $disc, + (($x1 * $y2 - $y1 * $x2) * ($y3 - $y4) + - ($x3 * $y4 - $y3 * $x4) * ($y1 - $y2)) / $disc); +} + +line_intersection((-1, -1), (1, 1), (1, -1), (-1, 1)).say; +line_intersection((0, 0), (1, 1), (1, 0), (2, 1)).say; +line_intersection((0, 0), (1, 1), (2, 2), (3, 3)).say; +try { + line_intersection((1, 1), (1, 1), (2, 2), (3, 3)).say; +} +if $! { + say "Expected error, because the input doesn't represent a line."; +} diff --git a/challenge-027/noud/perl6/ch-2.p6 b/challenge-027/noud/perl6/ch-2.p6 new file mode 100644 index 0000000000..1d1ad3232e --- /dev/null +++ b/challenge-027/noud/perl6/ch-2.p6 @@ -0,0 +1,41 @@ +# Write a script that allows you to capture/display historical data. It could +# be an object or a scalar. For example +# +# my $x = 10; $x = 20; $x -= 5; +# +# After the above operations, it should list $x historical value in order. + +# I hope I don't get banned from the Perl Weekly Challenge club for using EVAL +# in this problem. ;) +use MONKEY-SEE-NO-EVAL; + +my @variables = (); +my $pattern = /my\s*\$(\w+)/; + +my $exec_prog = ""; +for 'exm.p6'.IO.lines -> $line { + my @line_var = ($line ~~ $pattern).values; + if (@line_var.elems > 0) { + @variables = (|(@line_var), |(@variables)); + } + $exec_prog = "$exec_prog $line"; + # After every line update %var_hash_ with the current variable values. + for @variables -> $x { + $exec_prog = "$exec_prog \%var_hash_\.push: ($x => \$$x)\;"; + } +} + +my %var_hash_; +EVAL $exec_prog; # https://xkcd.com/292/ +for %var_hash_.kv -> $var, @hist { + print("$var = ("); + my $last = @hist[0]; + print("$last"); + for @hist[1..*] -> $next { + if ($last != $next) { + print(", $next"); + $last = $next; + } + } + print(")\n"); +} diff --git a/challenge-027/noud/perl6/exm.p6 b/challenge-027/noud/perl6/exm.p6 new file mode 100644 index 0000000000..caef08a250 --- /dev/null +++ b/challenge-027/noud/perl6/exm.p6 @@ -0,0 +1,6 @@ +my $x = 10; +$x += 5; +my $y = 20; +$x -= 10; +$y = $x + $y; +$x /= 5; -- cgit From 8d5490a332ed12af6a6a338392a787c0bdd63661 Mon Sep 17 00:00:00 2001 From: Noud Aldenhoven Date: Tue, 24 Sep 2019 22:03:56 +0200 Subject: Corrected challenge 2 so the tools splits on semicolon --- challenge-027/noud/perl6/ch-2.p6 | 4 ++-- challenge-027/noud/perl6/exm.p6 | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/challenge-027/noud/perl6/ch-2.p6 b/challenge-027/noud/perl6/ch-2.p6 index 1d1ad3232e..0d7e6d9f8f 100644 --- a/challenge-027/noud/perl6/ch-2.p6 +++ b/challenge-027/noud/perl6/ch-2.p6 @@ -13,12 +13,12 @@ my @variables = (); my $pattern = /my\s*\$(\w+)/; my $exec_prog = ""; -for 'exm.p6'.IO.lines -> $line { +for 'exm.p6'.IO.slurp.split(";") -> $line { my @line_var = ($line ~~ $pattern).values; if (@line_var.elems > 0) { @variables = (|(@line_var), |(@variables)); } - $exec_prog = "$exec_prog $line"; + $exec_prog = "$exec_prog $line\;"; # After every line update %var_hash_ with the current variable values. for @variables -> $x { $exec_prog = "$exec_prog \%var_hash_\.push: ($x => \$$x)\;"; diff --git a/challenge-027/noud/perl6/exm.p6 b/challenge-027/noud/perl6/exm.p6 index caef08a250..ba00280a6e 100644 --- a/challenge-027/noud/perl6/exm.p6 +++ b/challenge-027/noud/perl6/exm.p6 @@ -1,6 +1,3 @@ -my $x = 10; -$x += 5; -my $y = 20; -$x -= 10; -$y = $x + $y; +my $x = 10; $x += 5; +my $y = 20; $x -= 10; $y = $x + $y; $x /= 5; -- cgit From c74c50b388288882019291f29434f96f2e3413ee Mon Sep 17 00:00:00 2001 From: Noud Aldenhoven Date: Wed, 25 Sep 2019 10:46:24 +0200 Subject: Several updates, documentation, and fixes for challenge 2 For example, I can run exercise one through this script: > perl6 ch-2.p6 ch-1.p6 (0 0) (0 0) (0 0) Expected error, because the input doesn't represent a line. Variables history: disc = (8, 0) --- challenge-027/noud/perl6/ch-2.p6 | 67 ++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/challenge-027/noud/perl6/ch-2.p6 b/challenge-027/noud/perl6/ch-2.p6 index 0d7e6d9f8f..9b6b316e31 100644 --- a/challenge-027/noud/perl6/ch-2.p6 +++ b/challenge-027/noud/perl6/ch-2.p6 @@ -5,37 +5,56 @@ # # After the above operations, it should list $x historical value in order. +# The idea behind this solution is to first extract all defined variables +# from the original script. After that we create a hash %var_hash_ that +# updates the current values of each of the defined variables after each +# semicolon. The new script is executed using the dangerous EVAL method. +# +# Usage: +# perl6 ch-2.p6 filename-of-script.p6 + # I hope I don't get banned from the Perl Weekly Challenge club for using EVAL # in this problem. ;) use MONKEY-SEE-NO-EVAL; -my @variables = (); -my $pattern = /my\s*\$(\w+)/; - -my $exec_prog = ""; -for 'exm.p6'.IO.slurp.split(";") -> $line { - my @line_var = ($line ~~ $pattern).values; - if (@line_var.elems > 0) { - @variables = (|(@line_var), |(@variables)); +sub MAIN(Str $filename) { + # Collect all variables in program. + my @variables = (); + for $filename.IO.slurp.split(";") -> $line { + my @line_var = ($line ~~ /my\s*\$(\w+)/).values; + if (@line_var.elems > 0) { + @variables = (|(@line_var), |(@variables)); + } } - $exec_prog = "$exec_prog $line\;"; - # After every line update %var_hash_ with the current variable values. - for @variables -> $x { - $exec_prog = "$exec_prog \%var_hash_\.push: ($x => \$$x)\;"; + + my $exec_prog = ""; + for $filename.IO.slurp.split(";") -> $line { + $exec_prog = "$exec_prog $line\;"; + # After every line update %var_hash_ with the current variable values. + for @variables -> $x { + $exec_prog = "$exec_prog + if (not DYNAMIC::<\$$x> === Nil) \{ + \%var_hash_\.push: ($x => DYNAMIC::<\$$x>)\; \}\;"; + } } -} -my %var_hash_; -EVAL $exec_prog; # https://xkcd.com/292/ -for %var_hash_.kv -> $var, @hist { - print("$var = ("); - my $last = @hist[0]; - print("$last"); - for @hist[1..*] -> $next { - if ($last != $next) { - print(", $next"); - $last = $next; + my %var_hash_; + EVAL $exec_prog; # https://xkcd.com/292/ + + say "Variables history:"; + for %var_hash_.kv -> $var, @hist { + my @hist_ = @hist.grep({ not $_.^name === "Any" }); + if (@hist_.elems > 0) { + print("$var = ("); + my $last = @hist_[0]; + print("$last"); + for @hist_[1..*] -> $next { + if ($last != $next) { + print(", $next"); + $last = $next; + } + } + print(")\n"); } } - print(")\n"); } -- cgit