Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- use strict;
- use warnings;
- # To remove warnings that 32+bit binary numbers converted by oct aren't portable
- no warnings 'portable';
- use List::Util qw(sum product min max);
- $| = 1;
- my $part1 = 0;
- my %operations = (
- 0 => sub { sum @_ },
- 1 => sub { product @_ },
- 2 => sub { min @_ },
- 3 => sub { max @_ },
- 5 => sub { int($_[0] > $_[1]) },
- 6 => sub { int($_[0] < $_[1]) },
- 7 => sub { int($_[0] == $_[1]) }
- );
- # Read input as string of binary digits (yes, we're going BASIC-style!)
- chomp( $_ = <> );
- my $input;
- foreach my $nyb (split //) {
- $input .= sprintf( "%04b", hex($nyb) );
- }
- # Read an integer of len bits from front of input
- sub read_int_field (\$$) {
- my ($input, $len) = @_;
- return (oct("0b" . substr( $$input, 0, $len, '' )));
- }
- # Read an extended literal integer from front of input
- sub read_literal (\$) {
- my $input = shift;
- my $extend;
- my $val = '';
- do {
- $extend = substr( $$input, 0, 1, '' );
- $val .= substr( $$input, 0, 4, '' );
- } until (!$extend);
- return (oct( "0b$val" ));
- }
- # Read the next pack from the front of input
- sub process_next_packet (\$) {
- my $input = shift;
- my $ret;
- # read in 6-bit header info
- my $version = &read_int_field( $input, 3 );
- my $type = &read_int_field( $input, 3 );
- $part1 += $version;
- if ($type == 4) {
- # literal value
- $ret = &read_literal( $input );
- } else {
- # operation on sub-packets
- my $len_type = substr( $$input, 0, 1, '' );
- # to collect values from sub-packets
- my @vals;
- if ($len_type == 0) {
- # process sub-packets from next len bits
- my $len = &read_int_field( $input, 15 );
- my $sub = substr( $$input, 0, $len, '' );
- push( @vals, &process_packets( \$sub ) );
- } else {
- # process num packets
- my $num = &read_int_field( $input, 11 );
- foreach (1 .. $num) {
- push( @vals, &process_next_packet( $input ) );
- }
- }
- # execute operation of type on values collected
- $ret = &{$operations{$type}}( @vals );
- }
- return ($ret);
- }
- # Loop to read multiple packets from a string (at the top layer this should be just 1)
- sub process_packets (\$) {
- my $input = shift;
- my @val = ();
- while ($$input && $$input != 0) {
- push( @val, &process_next_packet( $input ) );
- }
- return (@val);
- }
- # Part 2 should be just one value, but we'll display all we collect to detect bugs!
- print "Part 2: ", join(', ', &process_packets( \$input )), "\n";
- print "Part 1: $part1\n";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement