]> www.fi.muni.cz Git - aoc.git/blobdiff - 2021/32.pl
Moved 2021 to a subdir
[aoc.git] / 2021 / 32.pl
diff --git a/2021/32.pl b/2021/32.pl
new file mode 100755 (executable)
index 0000000..390c25d
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp(my $data = <>);
+# Accept also a binary string instead of hexadecimal one:
+$data =~ s/./sprintf("%04b", hex $&)/ge if $data =~ /[2-9A-F]/;
+
+sub chop_bits {
+       my ($bits) = @_;
+       my $rv;
+       $data =~ s/.{$bits}/$rv = eval "0b$&"; ''/e;
+       # say "chop_bits($bits) = $rv";
+       return $rv;
+}
+
+my $ver_sum;
+my $result;
+
+sub parse {
+       $ver_sum += chop_bits(3);
+       my $type = chop_bits(3);
+
+       if ($type == 4) {
+               my $num = 0;
+               my $more;
+               do {
+                       $more = chop_bits(1);
+                       $num *= 16;
+                       $num += chop_bits(4);
+               } while ($more);
+               $result .= "$num,";
+       } else {
+               $result .= "op$type(";
+               if (chop_bits(1)) {
+                       my $subparts = chop_bits(11);
+                       parse() for 1 .. $subparts;
+               } else {
+                       my $sublen = chop_bits(15);
+                       my $len = length $data;
+                       parse() while $len - length($data) < $sublen;
+               }
+               $result .= "),";
+       }
+}
+
+use List::Util qw(sum product min max);
+
+sub op0 { sum @_; }
+sub op1 { product @_; }
+sub op2 { min @_; }
+sub op3 { max @_; }
+sub op5 { $_[0] >  $_[1] ? 1 : 0 }
+sub op6 { $_[0] <  $_[1] ? 1 : 0 }
+sub op7 { $_[0] == $_[1] ? 1 : 0 }
+
+parse();
+
+say "versions = $ver_sum";
+say $result, ' = ', eval $result;
+