aoc2021

Advent of Code 2021 solutions in Perl.
git clone git://git.samirparikh.com/aoc2021
Log | Files | Refs | README

day04-2.pl (4827B) - raw


      1 #!/usr/bin/env perl
      2 
      3 use strict;
      4 use warnings;
      5 use v5.22;
      6 
      7 sub get_filehandle {
      8     if (@ARGV !=1) {
      9         die "Usage: $0 [input-filename]";
     10     }
     11     my $input_filename = $ARGV[0];
     12     open my $filehandle, '<', $input_filename or
     13         die "Could not open input file $input_filename: $!";
     14     return $filehandle;
     15 }
     16 
     17 sub get_numbers {
     18     my $fh = shift;
     19     chomp( my $numbers = ( <$fh> ) );
     20     return (split( ",", $numbers));
     21 }
     22 
     23 sub initialize_boards {
     24     my $fh = shift;
     25     chomp( my @input = ( <$fh> ) );
     26     my (@boards, @new_board);
     27     foreach (@input) {
     28         if (/\A\s*\Z/) {
     29             push(@boards, [@new_board]) if (@new_board);
     30             @new_board = ();
     31         } else {
     32             push(@new_board, [split]);
     33         }
     34     }
     35     push(@boards, \@new_board);
     36     return (@boards);
     37 }
     38 
     39 sub initialize_state {
     40     my %state;
     41     my $boards = shift;
     42     foreach my $board (@$boards) {
     43         foreach my $row (@$board) {
     44             foreach my $column (@$row) {
     45                 $state{$board}{$row}{$column} = 0;
     46             }
     47         }
     48     }
     49     return %state;
     50 }
     51 
     52 sub play_turn {
     53     my ($number, $boards, $state) = @_;
     54     foreach my $board (@$boards) {       # $board is ref to board array
     55         foreach my $row (@$board) {      # $row is ref to board row array
     56             foreach my $column (@$row) { # $column is element of row array
     57                 if ($column == $number) {
     58                     $state->{$board}{$row}{$column} = 1;
     59                 }
     60             }
     61         }
     62     }
     63 }
     64 
     65 # for debugging purposes only
     66 sub print_board_state {
     67     my ($boards, $state) = @_;
     68     foreach my $board (@$boards) {       # $board is ref to board array
     69         foreach my $row (@$board) {      # $row is ref to board row array
     70             foreach my $column (@$row) { # $column is element of row array
     71                 print "$board\t$row\t";
     72                 if ($state->{$board}{$row}{$column} == 1) {
     73                     printf "-> %2d <-\n", $column;
     74                 } else {
     75                     printf "   %2d\n", $column;
     76                 }
     77             }
     78         }
     79     }
     80 }
     81 
     82 sub check_for_winner {
     83     my ($boards, $state) = @_;
     84     my @winning_board_ref;
     85 # check for row wins
     86     foreach my $board (@$boards) {       # $board is ref to board array
     87         foreach my $row (@$board) {      # $row is ref to board row array
     88             my $total = 0;
     89             foreach my $column (@$row) { # $column is the actual value of
     90                                          # the number in @$row
     91                 $total += $state->{$board}{$row}{$column};
     92             }
     93             if ($total == 5) {
     94                 push (@winning_board_ref, $board);
     95                 last;
     96             }
     97         }
     98 # for each board, iterate through each column (0 .. 4)
     99         foreach (0 .. 4) {
    100             my $total = 0;
    101             foreach my $row (@$board) {
    102 # here, $_ represents the index within the array @$row.  Because the hash key
    103 # stores the actual value, we need to deference $row (which is an array
    104 # reference) and then look up the value stored in the index $_
    105                 $total += $state->{$board}{$row}{$row->[$_]};
    106             }
    107             if ($total == 5) {
    108                 push (@winning_board_ref, $board);
    109                 last;
    110             }
    111         }
    112     }
    113     return @winning_board_ref;
    114 }
    115 
    116 sub calculate_score {
    117     my ($number, $board, $state) = @_;
    118     my $score = 0;
    119     foreach my $row (@$board) {     # $row is ref to board row array
    120         foreach my $column (@$row) { # $column is element of row array
    121             if ($state->{$board}{$row}{$column} == 0) {
    122                 $score += $column;
    123             }
    124         }
    125     }
    126     return $score *= $number;
    127 }
    128 
    129 # Advent of Code 2021 Day 04 Part 1
    130 # initialize game variables
    131 my $filehandle  = get_filehandle();
    132 my @numbers     = get_numbers($filehandle);
    133 my $number;
    134 my @boards      = initialize_boards($filehandle);
    135 my %state       = initialize_state(\@boards);
    136 my $turn = 0;
    137 my @winner_found;
    138 my $final_board;
    139 
    140 while ( scalar ( @boards ) ) {
    141     @winner_found = ();
    142     $turn++;
    143     $number = shift( @numbers );
    144     printf "turn: %2d, playing number %2d\n", $turn, $number;
    145     play_turn($number, \@boards, \%state);
    146     @winner_found = check_for_winner(\@boards, \%state);
    147     if ( @winner_found ) {
    148         say "found a winning board";
    149         say "we had ", scalar(@boards), " boards";
    150         foreach my $winning_board (@winner_found) {
    151             @boards = grep { $_ ne $winning_board } @boards;
    152         }
    153         say "we now have ", scalar(@boards), " boards";
    154     }
    155     unless (@numbers) { # if we run out of numbers
    156         say "Out of numbers.  No winner found.";
    157         exit;
    158     }
    159     $final_board = $boards[0] if ( scalar( @boards ) == 1 );
    160 }
    161 my $score = calculate_score($number, $final_board, \%state);
    162 say "winning score is $score";