p3-util

Download the raw code.

# This is my favorite problem of the five.
# I plan to write a talk around this, to show off this cool feature.

class InExRange {
    has $.type; # Is + or - for inclusion or exclusion.
    has $.range;
    method new ( $type, $start, $stop ) {
        my $range = $start .. $stop;
        self.bless: *, :$type, :$range;
    }
    # Int, because smartmatch against range in silently
    # buggy if LHS is accidentally Str.
    method in_range ( Int $num ) {
        given self.type {
            return ? ( $num  ~~ self.range ) when '+';
            return ? ( $num !~~ self.range ) when '-';
            die "Can't happen";
        }
    }
}

grammar Range::Grammar {
    token TOP   {  \n* <expr>+                         }
    token start {  \d+                                 }
    token stop  {  \d+                                 }
    token type  {  <[+\-]>                             }
    rule  expr  {  <type> '[' <start> '..' <stop> ']'  }
}

class Range::Actions {
    method TOP  ( $/ ) { make $<expr>».ast }
    method expr ( $/ ) { make InExRange.new: ~$<type>, +$<start>, +$<stop> }
}

my ( $ranges_line, $num ) = $*IN.lines;

$num ~~ /\d+/
    or say 'invalid input' and exit;

my $match = Range::Grammar.parse( $ranges_line, actions => Range::Actions.new )
    or say 'no' and exit;

my @ranges = $match.ast.list;
say all(@ranges).in_range($num.Int) ?? 'yes' !! 'no';

Readability

Util likes to glom together the declarations in classes a bit more than I do, but that's OK. It only really "affects" the first class; with the grammar and the second class, it looks fine.

Consistency

Lines 11 and 12 mention a bug in (i presume) Rakudo, but I've seen no corresponding bug report. (Correct me if I'm wrong.) Too bad, could have been some honour in reporting a bug along with your code submission.

Zero-status exit on faulty condition (line 38)... people couldn't use die because of the constraints base-test put up. The one on line 41 is fine.

Clarity of intent

Range::Grammar names the rules not after what they contain, but after their semantic use. Kudos.

The method on line 13 could have been called a number of things, but I'm pretty sure in_range wasn't the best choice. Isn't something inside of an excluding range "in range"? Not according to this method.

Algorithmic efficiency

Fast, but wrong.

Line 44 uses a junction to join up the results. It thus commits the error of ignoring the order of the ranges (and thus the part of the problem description that said "Inclusions and exclusions are performed from left to right.").

Idiomatic use of Perl 6

It's nice to see grammars and actions being used this way. make $<expr>».ast on line 31 is very expressive.

Brevity

This one also has the build-up feel to it. The solution is short and sweet, and yet it contains a grammar and two classes.