aoc2021

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

day04-1.pl (4669B) - 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     printf "playing number %2d\n", $number;
     55     foreach my $board (@$boards) {       # $board is ref to board array
     56         foreach my $row (@$board) {      # $row is ref to board row array
     57             foreach my $column (@$row) { # $column is element of row array
     58                 if ($column == $number) {
     59                     $state->{$board}{$row}{$column} = 1;
     60                 }
     61             }
     62         }
     63     }
     64 }
     65 
     66 # for debugging purposes only
     67 sub print_board_state {
     68     my ($boards, $state) = @_;
     69     foreach my $board (@$boards) {       # $board is ref to board array
     70         foreach my $row (@$board) {      # $row is ref to board row array
     71             foreach my $column (@$row) { # $column is element of row array
     72                 print "$board\t$row\t";
     73                 if ($state->{$board}{$row}{$column} == 1) {
     74                     printf "-> %2d <-\n", $column;
     75                 } else {
     76                     printf "   %2d\n", $column;
     77                 }
     78             }
     79         }
     80     }
     81 }
     82 
     83 sub check_for_winner {
     84     my ($boards, $state) = @_;
     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                 #say "found row winner";
     95                 return $board;
     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                 #say "found column winner";
    109                 return $board;
    110             }
    111         }
    112     }
    113     return 0; # no winner found
    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 
    138 # $winner_found plays double duty.  When equal to 0, it means that
    139 # we haven't yet found a winning board.  When we do, the subroutine
    140 # check_for_winner returns a reference to the array of the winning
    141 # board which we can then submit to calculate_score.
    142 my $winner_found = 0;
    143 
    144 until ($winner_found) {
    145     $turn++;
    146     printf "turn: %2d, ", $turn;
    147     $number = shift( @numbers );
    148     play_turn($number, \@boards, \%state);
    149     $winner_found = check_for_winner(\@boards, \%state);
    150     unless (@numbers) { # if we run out of numbers
    151         say "Out of numbers.  No winner found.";
    152         last;
    153     }
    154 }
    155 my $score = calculate_score($number, $winner_found, \%state);
    156 say "winning score is $score";