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";