Quick actions

cmd+k|ctrl+k

Navigation

Languages

AoC 2023, day 19

Snippet info

Language

Raku

Visibility

public

Author

seaker

Created

2023-12-19T08:43:22.442062Z

Updated

2023-12-19T09:19:07.189312Z

grammar Xmas {
    rule  TOP   { <name> '{' <work>+ % ',' '}' }
    token name  { <[a..z]>+ || 'A' || 'R' }
    rule  work  { <rate> <op> <value> ':' <name> || <name> }
    token rate  { <[xmas]> }
    token op    { '<' | '>' }
    token value { \d+ }
    rule  input { '{' <entry>+ % ',' '}' }
    rule  entry { <rate> '=' <value> }
}

class XmasActions {
    method TOP($/)  { make $<name>.made => ($<work>».made).Array }
    method name($/) { make ~$/ }
    method work($/) {
        my %h = 'next' => $<name>.made, ;
        with $<rate>.made {
            %h<rate>  = $<rate>.made;
            %h<op>    = $<op>.made;
            %h<value> = $<value>.made;
        }

        make %h
    }
    method rate($/)  { make ~$/ }
    method op($/)    { make ~$/ }
    method value($/) { make +$/ }
    method input($/) { make ($<entry>».made).Hash }
    method entry($/) { make $<rate>.made => $<value>.made }
}

my (%flows, $sum2);

put 'part 1: ', do with $*IN.split("\n\n") {
    %flows = .[0].lines.map({ Xmas.parse($_, :actions(XmasActions)).made });
    [+] (process-p1($_, %flows) for .[1].lines.map({ Xmas.parse($_, :rule<input>, :actions(XmasActions)).made }))
};

process-p2((:x(1..4000), :m(1..4000), :a(1..4000), :s(1..4000)).Hash, 'in', %flows);
put 'part 2: ', $sum2;

sub process-p1(%input, %flows) {
    my $fn = 'in';
    loop {
        for %flows{$fn}.Array -> $work {
            given $fn {
                when 'A' { return %input.map(*.value).sum; }
                when 'R' { return 0; }
            }
            with $work<op> {
                when '<' { { $fn = $work<next>; last; } if %input{$work<rate>} < $work<value>; }
                when '>' { { $fn = $work<next>; last; } if %input{$work<rate>} > $work<value>; }
            } else {
                $fn = $work<next>;
            }
        }
    }
}

sub process-p2(%ranges is copy, $fn_, %flows) {
    my $fn = $fn_;

    for %flows{$fn}.Array -> $work {
        given $fn {
            when 'A' { $sum2 += [*] %ranges.values.map(+*); return; }
            when 'R' { return; }
        }
        with $work<op> {
            my %ranges_ = %ranges;
            when '<' {
                with %ranges_{$work<rate>} -> $rr {
                    if $rr.min < $work<value> {
                        %ranges_{$work<rate>} = $rr.min .. $work<value> - 1;
                        process-p2(%ranges_, $work<next>, %flows);
                    }
                }
                with %ranges{$work<rate>} -> $rr {
                    $rr.max ≥ $work<value> ?? (%ranges{$work<rate>} = $work<value> .. $rr.max) !! return;
                }
            }
            when '>' {
                with %ranges_{$work<rate>} -> $rr {
                    if $rr.max > $work<value> {
                        %ranges_{$work<rate>} = max($rr.min, $work<value> + 1) .. $rr.max;
                        process-p2(%ranges_, $work<next>, %flows);
                    }
                }
                with %ranges{$work<rate>} -> $rr {
                    $rr.min ≤ $work<value> ?? (%ranges{$work<rate>} = $rr.min .. $work<value>) !! return;
                }
            }
        } else {
            process-p2(%ranges, $work<next>, %flows);
        }
    }
}
INFO