commit 2247d9305702f1804f846070d00a05aa3e2a1fa1
parent 71b0c0e84554c0a236fbb9fe3547774452bb2f5a
Author: Samir Parikh <noreply@samirparikh.com>
Date: Mon, 6 Dec 2021 20:21:40 +0000
add day04-2.pl
Diffstat:
A | day04-2.pl | | | 172 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 172 insertions(+), 0 deletions(-)
diff --git a/day04-2.pl b/day04-2.pl
@@ -0,0 +1,172 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use v5.22;
+
+sub get_filehandle {
+ if (@ARGV !=1) {
+ die "Usage: $0 [input-filename]";
+ }
+ my $input_filename = $ARGV[0];
+ open my $filehandle, '<', $input_filename or
+ die "Could not open input file $input_filename: $!";
+ return $filehandle;
+}
+
+sub get_numbers {
+ my $fh = shift;
+ chomp( my $numbers = ( <$fh> ) );
+ return (split( ",", $numbers));
+}
+
+sub initialize_boards {
+ my $fh = shift;
+ chomp( my @input = ( <$fh> ) );
+ my (@boards, @new_board);
+ foreach (@input) {
+ if (/\A\s*\Z/) {
+ push(@boards, [@new_board]) if (@new_board);
+ @new_board = ();
+ } else {
+ push(@new_board, [split]);
+ }
+ }
+ push(@boards, \@new_board);
+ return (@boards);
+}
+
+sub initialize_state {
+ my %state;
+ my $boards = shift;
+ foreach my $board (@$boards) {
+ foreach my $row (@$board) {
+ foreach my $column (@$row) {
+ $state{$board}{$row}{$column} = 0;
+ }
+ }
+ }
+ return %state;
+}
+
+sub play_turn {
+ my ($number, $boards, $state) = @_;
+ foreach my $board (@$boards) { # $board is ref to board array
+ foreach my $row (@$board) { # $row is ref to board row array
+ foreach my $column (@$row) { # $column is element of row array
+ if ($column == $number) {
+ $state->{$board}{$row}{$column} = 1;
+ }
+ }
+ }
+ }
+}
+
+# for debugging purposes only
+sub print_board_state {
+ my ($boards, $state) = @_;
+ foreach my $board (@$boards) { # $board is ref to board array
+ foreach my $row (@$board) { # $row is ref to board row array
+ foreach my $column (@$row) { # $column is element of row array
+ print "$board\t$row\t";
+ if ($state->{$board}{$row}{$column} == 1) {
+ printf "-> %2d <-\n", $column;
+ } else {
+ printf " %2d\n", $column;
+ }
+ }
+ }
+ }
+}
+
+sub check_for_winner {
+ my ($boards, $state) = @_;
+ my @winning_board_ref;
+# check for row wins
+ foreach my $board (@$boards) { # $board is ref to board array
+ foreach my $row (@$board) { # $row is ref to board row array
+ my $total = 0;
+ foreach my $column (@$row) { # $column is the actual value of
+ # the number in @$row
+ $total += $state->{$board}{$row}{$column};
+ }
+ if ($total == 5) {
+ #say "found row winner";
+ push (@winning_board_ref, $board);
+ #return $board;
+ last;
+ }
+ }
+# for each board, iterate through each column (0 .. 4)
+ foreach (0 .. 4) {
+ my $total = 0;
+ foreach my $row (@$board) {
+# here, $_ represents the index within the array @$row. Because the hash key
+# stores the actual value, we need to deference $row (which is an array
+# reference) and then look up the value stored in the index $_
+ $total += $state->{$board}{$row}{$row->[$_]};
+ }
+ if ($total == 5) {
+ #say "found column winner";
+ push (@winning_board_ref, $board);
+ #return $board;
+ last;
+ }
+ }
+ }
+ return @winning_board_ref;
+}
+
+sub calculate_score {
+ my ($number, $board, $state) = @_;
+ my $score = 0;
+ foreach my $row (@$board) { # $row is ref to board row array
+ foreach my $column (@$row) { # $column is element of row array
+ if ($state->{$board}{$row}{$column} == 0) {
+ $score += $column;
+ }
+ }
+ }
+ return $score *= $number;
+}
+
+# Advent of Code 2021 Day 04 Part 1
+# initialize game variables
+my $filehandle = get_filehandle();
+my @numbers = get_numbers($filehandle);
+my $number;
+my @boards = initialize_boards($filehandle);
+my %state = initialize_state(\@boards);
+my $turn = 0;
+
+# $winner_found plays double duty. When equal to 0, it means that
+# we haven't yet found a winning board. When we do, the subroutine
+# check_for_winner returns a reference to the array of the winning
+# board which we can then submit to calculate_score.
+#my $winner_found = 0;
+my @winner_found;
+
+#until ($winner_found) {
+while ( scalar ( @boards ) > 1 ) {
+ @winner_found = ();
+ $turn++;
+ printf "turn: %2d, playing number %2d\n", $turn, $number;
+ $number = shift( @numbers );
+ play_turn($number, \@boards, \%state);
+ $winner_found = check_for_winner(\@boards, \%state);
+ if ( @winner_found ) {
+ say "found a winning board";
+ say "we had ", scalar(@boards), " boards";
+ foreach my $winning_board (@winner_found) {
+ @boards = grep { $_ ne $winning_board } @boards;
+ }
+ say "we now have ", scalar(@boards), " boards";
+ }
+ unless (@numbers) { # if we run out of numbers
+ say "Out of numbers. No winner found.";
+ #last;
+ exit;
+ }
+}
+my $score = calculate_score($number, $boards[0], %state);
+say "winning score is $score";