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