]> www.fi.muni.cz Git - aoc2021.git/blob - 32.pl
Day 16: pretty straightforward parser
[aoc2021.git] / 32.pl
1 #!/usr/bin/perl -w
2
3 use v5.16;
4
5 chomp(my $packet = <>);
6 $packet =~ s/./sprintf("%04b", hex $&)/ge if $packet =~ /[2-9A-F]/;
7
8 sub get_b (\$$) {
9         my ($ppack, $bits) = @_;
10         my $rv;
11         $$ppack =~ s/.{$bits}/$rv=eval"0b$&";''/e;
12         # say "get_b $bits=$rv";
13         return $rv;
14 }
15
16 my $ver_sum;
17 my $result;
18 sub parse {
19         my $pp = shift;
20
21         my $l = length $pp;
22         my $ver = get_b($pp, 3);
23         $ver_sum += $ver;
24         my $typ = get_b($pp, 3);
25
26         if ($typ == 4) {
27                 my $num = 0;
28                 while (get_b($pp, 1)) {
29                         $num *= 16;
30                         $num += get_b($pp, 4);
31                 }
32                 $num *= 16;
33                 $num += get_b($pp, 4);
34                 $result .= "$num,";
35         } else {
36                 $result .= "op($typ,";
37                 my $li = get_b($pp, 1);
38                 if ($li) {
39                         my $subp = get_b($pp, 11);
40                         for (1 .. $subp) {
41                                 my $l1 = parse($pp);
42                                 $pp =~ s/.{$l1}//;
43                         }
44                 } else {
45                         my $subl = get_b($pp, 15);
46                         my $s = substr($pp, 0, $subl);
47                         $pp =~ s/.{$subl}//;
48                         while ($subl) {
49                                 my $l1 = parse($s);
50                                 $s =~ s/.{$l1}//;
51                                 $subl -= $l1;
52                         }
53                 }
54                 $result .= "),";
55         }
56         return $l - length($pp);
57 }
58
59 use List::Util qw(sum product min max);
60
61 sub op {
62         my ($id, @rest) = @_;
63         if ($id == 0) {
64                 return sum @rest;
65         } elsif ($id == 1) {
66                 return product @rest;
67         } elsif ($id == 2) {
68                 return min @rest;
69         } elsif ($id == 3) {
70                 return max @rest;
71         } elsif ($id == 5) {
72                 return $rest[0] > $rest[1] ? 1 : 0;
73         } elsif ($id == 6) {
74                 return $rest[0] < $rest[1] ? 1 : 0;
75         } elsif ($id == 7) {
76                 return $rest[0] == $rest[1] ? 1 : 0;
77         } 
78 }
79
80 parse($packet);
81 say $result, ' = ', eval $result;
82