advent_of_code_2021/day_4/part_2.php

120 lines
2.6 KiB
PHP
Raw Permalink Normal View History

2021-12-06 16:47:24 +01:00
<?php
// prepare numbers and grids
$parts = explode("\n\n", file_get_contents('./input.txt'));
$numbers = array_map('intval', explode(',', array_shift($parts)));
$grids = array_map(static function($part) { return explode("\n", $part); }, $parts);
array_walk_recursive($grids, static function (&$grid) {
if (is_string($grid)) {
$grid = array_map(static function($g) {
return 0;
}, array_flip(array_map('trim', str_split($grid, 3))));
}
});
/**
* Marks cell as done
*
* @param array $grids
* @param int $number
*/
function modify_grids(array &$grids, int $number)
{
foreach ($grids as $i_grid => $grid) {
foreach ($grid as $i_row => $row) {
foreach ($row as $cell => $cell_val) {
if ($cell === $number) {
$grids[$i_grid][$i_row][$cell] = 1;
}
}
}
}
}
/**
* List all unmarked cell from a grid
*
* @param array $grid
*
* @return array
*/
function get_unmarked_from(array $grid): array
{
$unmarked = [];
foreach ($grid as $row) {
$unmarked = array_merge($unmarked, array_keys(array_filter($row, static function($cell) {
return $cell === 0;
})));
}
return $unmarked;
}
/**
* Check if a grid is winning
*
* @param array $grids
*
* @return bool|array
*/
function check_grids(array &$grids): bool|array
{
$result = false;
foreach ($grids as $i => $grid) {
if (check_lines($grid)) {
if (count($grids) === 1) return $grid;
unset($grids[$i]);
$result = true;
}
$rotated_grid = [];
$i = 0;
while (!empty($grid)) {
foreach ($grid as $j => $row) {
$rotated_grid[$i][array_key_last($row)] = array_pop($row);
$grid[$j] = $row;
if (empty($row)) unset($grid[$j]);
}
$i++;
}
if (check_lines($rotated_grid)) {
if (count($rotated_grid) === 1) return $grid;
unset($grids[$i]);
$result = true;
}
}
return $result;
}
/**
* Check if a line is all done
*
* @param array $grid
*
* @return bool|array
*/
function check_lines(array $grid): bool|array
{
foreach ($grid as $row) {
if (array_sum($row) === 5) {
return true;
}
}
return false;
}
foreach ($numbers as $number) {
modify_grids($grids, (int)$number);
$count = count($grids);
$test = check_grids($grids);
if ($count === 1 && $test) {
$grid = get_unmarked_from(is_array($test) ? $test : current($grids));
echo array_sum($grid) * $number;
break;
}
}