aboutsummaryrefslogtreecommitdiff
path: root/challenge-027
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2019-09-29 05:31:12 +0100
committerGitHub <noreply@github.com>2019-09-29 05:31:12 +0100
commit421c4ba8e1ec2f6373802f4165c8e9e80153dfb5 (patch)
tree1ba36a3d3b7c23c26db3707f8a8292dd013a4623 /challenge-027
parentc764a06d2d2f9cb77c058faaed5f0bf614059614 (diff)
parent9395599b5d764982a6421c3e87527a35d395af61 (diff)
downloadperlweeklychallenge-club-421c4ba8e1ec2f6373802f4165c8e9e80153dfb5.tar.gz
perlweeklychallenge-club-421c4ba8e1ec2f6373802f4165c8e9e80153dfb5.tar.bz2
perlweeklychallenge-club-421c4ba8e1ec2f6373802f4165c8e9e80153dfb5.zip
Merge pull request #676 from jmaslak/joelle-27-1-1
Joelle's solution to 27.1 in Perl 6
Diffstat (limited to 'challenge-027')
-rwxr-xr-xchallenge-027/joelle-maslak/perl6/ch-1.p6174
1 files changed, 174 insertions, 0 deletions
diff --git a/challenge-027/joelle-maslak/perl6/ch-1.p6 b/challenge-027/joelle-maslak/perl6/ch-1.p6
new file mode 100755
index 0000000000..4a711c64b1
--- /dev/null
+++ b/challenge-027/joelle-maslak/perl6/ch-1.p6
@@ -0,0 +1,174 @@
+#!/usr/bin/env perl6
+use v6;
+
+use StrictClass;
+
+# This program finds the intersection of two lines. While the word
+# "ends" is used, I'm instead assuming that these are true mathematical
+# lines, not line segments, so the intersection point may not be between
+# the two points that define the line.
+#
+# The first thing we need to do is to find the slope of each line.
+#
+# Edge case 1: If either line is not fully defined, we return an error.
+# This happens if both points are the same.
+#
+# Edge case 2: A vertical line can't be defined by the standard y = A × x₁ + C
+# equation. In this case we handle it differently, see below. We use ∞
+# for the slope in this case.
+#
+# To find the slope (of non-vertical lines), it's just rise / run, which is
+# easy to calculate. For the constant, we need to solve this:
+# y = Ax + C
+# A given point will define x and y, while the slope defines A, so we just
+# solve for C. THus:
+# C = y - Ax;
+#
+# If we have two equations: y₁ = A₁ × x₁ + C₁
+# y₂ = A₂ × x₂ + C₂
+#
+# We can find the intersection:
+# 1) If slope is identical, and constants differ, NO INTERSECTION
+# 2) If slope is identical, and constants are the same, this is the
+# same line.
+# 3) If the slope is infinite of either line, just solve the other
+# equation to determine y for that value of x.
+# 4) Otherwise, we're looking for the point where x₁=x₂ and y₁=y₂
+# Thus, we can rewrite the equations as:
+# y = A₁ × x + C₁
+# y = A₂ × x + C₂
+# We can solve this system for x:
+# A₁ × x + C₁ = A₂ × x + C₂
+# Rewritten:
+# A₁ × x - A₂ × x = C₂ - C₁
+# Rewritten:
+# (A₁ - A₂) × x = C₂ - C₁
+# x = (C₂ - C₁) ÷ (A₁ - A₂)
+# Once we have x, we can solve for y by plugging into either of the
+# original equations.
+#
+
+class Point does StrictClass {
+ has Real:D $.x is rw is required;
+ has Real:D $.y is rw is required;
+
+ method from-string(Str:D $point-str is copy -->Point:D) {
+ $point-str ~~ s:s/^ '(' [.*] ')' $/$0/; # Remove parens
+ my (Real:D $x, Real:D $y) = $point-str.split(',').map( +* );
+
+ return Point.new(:$x, :$y);
+
+ CATCH {
+ # We must have been passed a bad point
+ die "$point-str is an invalid point definition";
+ }
+ }
+}
+
+class Line does StrictClass {
+ has Real:D $.slope is rw is required;
+ has Point:D $.point is rw is required; # Any valid point on the line
+
+ method solve-for-x(Real:D $y -->Real:D) {
+ # Vertical line exception
+ return $.point.x if $.slope == ∞;
+
+ # Horizontal line exception
+ if $.slope == 0 {
+ die "Cannot solve for $y" if $.point.y ≠ $y;
+ }
+
+ return ($y - self.y-offset) ÷ $.slope;
+ }
+
+ method solve-for-y(Real:D $x -->Real:D) {
+ # Horizontal line exception
+ return $.point.y if $.slope == 0;
+
+ # Vertical line exception
+ if $.slope == ∞ {
+ die "Cannot solve for $x" if $.point.x ≠ $x;
+ }
+
+ # Lines between horizontal and ertical
+ return $.slope × $x + self.y-offset;
+ }
+
+ method y-offset(-->Real:D) {
+ # Vertical line exception
+ return ∞ if $.slope == ∞;
+
+ # Non-vertical lines
+ return $.point.y - $.slope × $.point.x;
+ }
+
+ method intersection(Line:D $line -->Point:D) {
+ die "Lines are the same" if self eqv $line;
+ die "Lines do not intersect" if self.slope == $line.slope;
+
+ # If either line is vertical
+ if self.slope == ∞ {
+ return Point.new(:x(self.point.x), :y($line.solve-for-y(self.point.x)));
+ } elsif $line.slope == ∞ {
+ return Point.new(:x($line.point.x), :y(self.solve-for-y($line.point.x)));
+ }
+
+ # We're finding a normal intersection
+ my $x = ($line.y-offset - self.y-offset) ÷ (self.slope - $line.slope);
+ my $y = self.solve-for-y($x);
+
+ return Point.new(:$x, :$y);
+ }
+
+ # We need an eqv that works
+ CORE::<&infix:<eqv>>.add_dispatchee(
+ multi sub infix:<eqv> (Line:D $line1, Line:D $line2 -->Bool) {
+ return False if $line1.slope ≠ $line2.slope;
+
+ # Are both vertical?
+ if $line1.slope == ∞ and $line2.slope == ∞ {
+ return $line1.point.x == $line2.point.x;
+ }
+
+ # All other lines
+ return $line1.point.y == $line2.solve-for-y($line1.point.x);
+ }
+ );
+
+ method from-points(Point:D $point1, Point:D $point2 -->Line:D) {
+ # Handle same point
+ die "Lines must be defined with two different points" if $point1 eqv $point2;
+
+ # Handle vertical line exception
+ return Line.new(:point($point1), :slope(∞)) if $point1.x == $point2.x;
+
+ # Handle other lines.
+ my $slope = ($point1.y - $point2.y) ÷ ($point1.x - $point2.x);
+ return Line.new(:point($point1), :$slope);
+ }
+}
+
+# point1 and point2 define a line. You can determine which line by the
+# letter
+sub MAIN(Str:D $point1a, Str:D $point2a, Str:D $point1b, $point2b) {
+ my $line1 = Line.from-points(
+ Point.from-string($point1a),
+ Point.from-string($point2a),
+ );
+ my $line2 = Line.from-points(
+ Point.from-string($point1b),
+ Point.from-string($point2b),
+ );
+
+ if $line1 eqv $line2 {
+ say "The two lines are the same";
+ } elsif $line1.slope == $line2.slope {
+ say "The two lines don't intersect";
+ } else {
+ my $intersection = $line1.intersection($line2);
+ say "The lines intersect at ({ $intersection.x },{ $intersection.y })";
+ }
+
+ return;
+}
+