class Point { has Real $.x = 0; has Real $.y = 0; method Str(--> Str) { try { "<$.x, $.y>" } or "undefined" } } class Line { has Point $.p; has Point $.q; multi method new(Point $p, Point $q) { self.bless(:$p, :$q) } multi method new(Point :$p, Point :$q) { self.bless(:$p, :$q) } } sub intersection(Line $l1, Line $l2) is export { my $a1 = $l1.q.y - $l1.p.y; my $b1 = $l1.p.x - $l1.q.x; my $c1 = $a1 * $l1.p.x + $b1 * $l1.p.y; my $a2 = $l2.q.y - $l2.p.y; my $b2 = $l2.p.x - $l2.q.x; my $c2 = $a2 * $l2.p.x + $b2 * $l2.p.y; my $delta = $a1 * $b2 - $a2 * $b1; return Point.new( :x(($b2 * $c1 - $b1 * $c2) / $delta), :y(($a1 * $c2 - $a2 * $c1) / $delta) ) } sub manhattan-distance(Point $p, Point $q) is export { abs($p.x - $q.x) + abs($p.y - $q.y) } class Wire is export { has Point @.points; submethod new(Str $input) { my @movements = $input.split(','); my @points; my $x = 0; my $y = 0; for @movements -> $move { if $move ~~ /$ = [ <[ UDLR ]> ] $ = [ \d+]/ { given $ { when "U" { $y += $.Int } when "D" { $y += -$.Int } when "L" { $x += -$.Int } when "R" { $x += $.Int } } @points.append: Point.new(:$x, :$y); } } self.bless(:@points); } method segments { @.points[0..^*-1] Z @.points[1..*] } method lines { gather for self.segments -> $s { take Line.new($s[0], $s[1]); } } }