p2-matthias

use v6;

# sliding-window() with possibility to adjust the sliding-speed:
sub sliding-window(@scenery, \$width, \$speed) {
gather for 0, \$speed  ...^  * > +@scenery - \$width  -> \$pos {
take @scenery[ \$pos .. \$pos + \$width - 1 ];
}
}

my regex number { '-'? \d+ '.' \d+ }
my  @polygon  = \$*IN.get.comb: /<&number>/;
my (\$px, \$py) = \$*IN.get.comb: /<&number>/;

if +@polygon < 6 || +@polygon % 2  or  ! defined (\$px && \$py) {
say 'invalid input';
exit;
}

# now, let us count the intersections of a straight line going down from the
# point in question, and the polygon's edges.

@polygon.push: @polygon[0,1];           # so that we get the Pn->P1 edge
my \$intersections = 0;
my \$ON_OUTLINE    = 0;                  # should be: my constant \$ON_OUTLINE

for sliding-window(@polygon, 4, 2) -> \$ax, \$ay, \$bx, \$by {
next if \$ay & \$by  >  \$py           # skip upper edges
or \$ax & \$bx  <  \$px           # skip left edges
or \$ax & \$bx  >  \$px;          # skip right edges

# function representing the edge: Ey(x) = mx + b

if \$bx - \$ax -> \$dx {
my \$m = (\$by - \$ay) / \$dx;
my \$b = \$ay - \$m * \$ax;

given \$m * \$px + \$b {
when * <  \$py { ++\$intersections }
when * == \$py {
\$intersections = \$ON_OUTLINE;
last;
}
}
}
elsif \$ay | \$by  >  \$py {
\$intersections = \$ON_OUTLINE;
last;
}
}

say \$intersections % 2 ?? 'yes' !! 'no';

Clearly laid out. Names are either understandable or explained.

Consistency

It wasn't required anywhere, but exiting with a non-zero status would be preferable if the reason for exiting is invalid input. People didn't use die because of the constraints base-test put up; but doing a normal exit still feels wrongish.

Clarity of intent

The cases in the main loop are not well explained, but at least fairly easy to follow.

This solution stores coordinates flat inside an array, staggering x and y coordinates. It's less of a data structure overhead than the other solutions, but no less worthy of a comment.

Algorithmic efficiency

Not much of a concern in this problem. The solution is clearly linear on the number of points.

Idiomatic use of Perl 6

Generally nice use of junctions to simplify condition expressions in this one.

TimToady++ pointed out a nice Perl 6 idiom that I stared at but managed to miss: the if \$bx - \$ax -> \$dx { ... } on line 33. Clearly an appropriate use of the lambda arrow.

The semantics of the regex number on line 10... is already provided by STD and Rakudo as dec_number (except for the minus sign). Notice how dec_number also considers two cases of decimal numbers that number doesn't. It's my personal opinion, but reinventing parsing wheels should be fairly stigmatized.

Brevity

The solution is nice and short.