Quick actions

cmd+k|ctrl+k

Navigation

Languages

Advent of Code 2021, Day 16 Solutions

Snippet info

Language

Raku

Visibility

public

Author

seaker

Created

2021-12-17T08:42:17.726972Z

Updated

2021-12-17T08:42:46.7103Z

grammar Packet {
    regex TOP    { <packet> <padding> }
    regex packet { <version> <body> }

    token version { <[01]> ** 3 }
    token data    { <[01]> ** 4 }
    regex padding { '0'* }

    token sub-packets-length { <[01]> ** 15 }
    token sub-packets-number { <[01]> ** 11 }

    token length-header { '0' <sub-packets-length> || '1' <sub-packets-number> }

    proto regex body { * }
    token body:sym<literal> { '100' ['1' <data>]* '0' <data> }
    regex body:sym<sum>     { '000' <length-header> <packet>+? <?{ body-match-header($<length-header>.made, $<packet>) }> }
    regex body:sym<prod>    { '001' <length-header> <packet>+? <?{ body-match-header($<length-header>.made, $<packet>) }> }
    regex body:sym<min>     { '010' <length-header> <packet>+? <?{ body-match-header($<length-header>.made, $<packet>) }> }
    regex body:sym<max>     { '011' <length-header> <packet>+? <?{ body-match-header($<length-header>.made, $<packet>) }> }
    regex body:sym<gt>      { '101' <length-header> <packet> ** 2 <?{ body-match-header($<length-header>.made, $<packet>) }> }
    regex body:sym<lt>      { '110' <length-header> <packet> ** 2 <?{ body-match-header($<length-header>.made, $<packet>) }> }
    regex body:sym<eq>      { '111' <length-header> <packet> ** 2 <?{ body-match-header($<length-header>.made, $<packet>) }> }

    sub body-match-header(Hash:D \header, Array:D \packets --> Bool:D) {
        header<length>.defined                                ??
            header<length> == packets.map({ .Str.chars }).sum !!
            header<number> == packets.elems
    }
}

class PacketActions {
    method TOP($/)    { make $<packet>.made }
    method packet($/) { make %(versum => $<version>.made + $<body>.made<versum>, value => $<body>.made<value>) }

    method version($/) { make $/.Str.parse-base(2) }
    method data($/)    { make $/.Str.parse-base(2) }

    method sub-packets-length($/) { make $/.Str.parse-base(2) }
    method sub-packets-number($/) { make $/.Str.parse-base(2) }

    method length-header($/) {
        make $<sub-packets-length>.defined           ??
             %(length => $<sub-packets-length>.made) !!
             %(number => $<sub-packets-number>.made)
    }

    method body:sym<literal>($/) { make %(versum => 0, value => $<data>».made.reduce({ $^a * 16 + $^b })) }

    method body:sym<sum>($/)  { make %(versum => $<packet>.map({ .made<versum> }).sum, value => [+]   $<packet>.map({ .made<value> })) }
    method body:sym<prod>($/) { make %(versum => $<packet>.map({ .made<versum> }).sum, value => [*]   $<packet>.map({ .made<value> })) }
    method body:sym<min>($/)  { make %(versum => $<packet>.map({ .made<versum> }).sum, value => $<packet>.map({ .made<value> }).min) }
    method body:sym<max>($/)  { make %(versum => $<packet>.map({ .made<versum> }).sum, value => $<packet>.map({ .made<value> }).max) }
    method body:sym<gt>($/)   { make %(versum => $<packet>.map({ .made<versum> }).sum, value => +[>]  $<packet>.map({ .made<value> })) }
    method body:sym<lt>($/)   { make %(versum => $<packet>.map({ .made<versum> }).sum, value => +[<]  $<packet>.map({ .made<value> })) }
    method body:sym<eq>($/)   { make %(versum => $<packet>.map({ .made<versum> }).sum, value => +[==] $<packet>.map({ .made<value> })) }
}

sub solve(Str:D \hs) {
    my \ss = hs.comb».map({ $_.parse-base(16).fmt('%04b') }).join;
    Packet.parse(ss, :actions(PacketActions)).made
}

my \answer = solve($*IN.words[0]);
put 'part 1: ', answer<versum>;
put 'part 2: ', answer<value>;
INFO