aoc2021

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

commit 2247d9305702f1804f846070d00a05aa3e2a1fa1
parent 71b0c0e84554c0a236fbb9fe3547774452bb2f5a
Author: Samir Parikh <noreply@samirparikh.com>
Date:   Mon,  6 Dec 2021 20:21:40 +0000

add day04-2.pl

Diffstat:
Aday04-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";