2024-12-01 11:30:31 +01:00

183 lines
4.9 KiB
PHP

<?php
namespace trizz\AdventOfCode\Y23;
use trizz\AdventOfCode\Solution;
final class Day3 extends Solution
{
public static null|int|string $part1ExampleResult = 4361;
public static null|int|string $part1Result = 539637;
public static null|int|string $part2ExampleResult = 467835;
public static null|int|string $part2Result = 82_818_007;
/**
* @var string[][]
*/
private array $matrix = [];
#[\Override]
public function part1(array $data): int
{
$this->createMatrix($data);
$score = 0;
foreach ($this->matrix as $row => $line) {
foreach (array_keys($line) as $col) {
$numbers = $this->checkLocation($row, $col);
$top = (int) $this->processNumbers($numbers['top'], sum: true);
$bottom = (int) $this->processNumbers($numbers['bottom'], sum: true);
if ($numbers === []) {
continue;
}
if (empty($numbers['left'])) {
continue;
}
if (empty($numbers['right'])) {
continue;
}
$score += $top + $bottom + max($numbers['left']) + max($numbers['right']);
}
}
return $score;
}
#[\Override]
public function part2(array $data): int
{
$this->createMatrix($data);
$score = 0;
foreach ($this->matrix as $row => $line) {
foreach (array_keys($line) as $col) {
if ($this->matrix[$row][$col] !== '*') {
continue;
}
$numbers = $this->checkLocation($row, $col);
$top = (array) $this->processNumbers($numbers['top']);
$bottom = (array) $this->processNumbers($numbers['bottom']);
if ($numbers === []) {
continue;
}
if (empty($numbers['left'])) {
continue;
}
if (empty($numbers['right'])) {
continue;
}
$left = max($numbers['left']);
$right = max($numbers['right']);
$filteredResults = array_filter(array_values(array_merge_recursive($top, $bottom, [$left, $right])));
if (count($filteredResults) !== 2) {
continue;
}
$score += array_product($filteredResults);
}
}
return (int) $score;
}
/**
* @param int[] $numbers
*
* @return int|int[]
*/
private function processNumbers(array $numbers, bool $sum = false): array|int
{
$result = [];
if ($numbers[0] !== 0 && $numbers[1] === 0 && $numbers[2] !== 0) {
$result[] = $numbers[0];
$result[] = $numbers[2];
} elseif ($numbers !== []) {
$result[] = max($numbers);
}
if ($sum) {
return array_sum($result);
}
return $result;
}
/**
* @param string[] $data
*/
private function createMatrix(array $data): void
{
$this->matrix = array_map(static fn ($line): array => str_split((string) $line), $data);
}
/**
* @return array<string, array<int,int>>
*/
private function checkLocation(int $row, int $col): array
{
$current = $this->matrix[$row][$col] ?? '.';
if ($current === '.' || ctype_digit($current)) {
return ['top' => [0, 0, 0], 'left' => [0], 'right' => [0], 'bottom' => [0, 0, 0]];
}
$numbers = array_fill_keys(['top', 'left', 'right', 'bottom'], []);
$positions = [
'top' => [[$row - 1, $col - 1], [$row - 1, $col], [$row - 1, $col + 1]],
'left' => [[$row, $col - 1]],
'right' => [[$row, $col + 1]],
'bottom' => [[$row + 1, $col - 1], [$row + 1, $col], [$row + 1, $col + 1]],
];
foreach ($positions as $direction => $coords) {
foreach ($coords as $coord) {
$numbers[$direction][] = (int) $this->getNumber(...$coord);
}
}
return $numbers;
}
private function getNumber(int $row, int $col, ?string $direction = null): ?string
{
$number = $this->matrix[$row][$col] ?? null;
if ($number === null || $number === '.' || !ctype_digit($number)) {
return null;
}
$toLeft = null;
$toRight = null;
if ($direction === null || $direction === 'left') {
$toLeft = $this->getNumber($row, $col - 1, 'left');
}
if ($direction === null || $direction === 'right') {
$toRight = $this->getNumber($row, $col + 1, 'right');
}
if ($toLeft !== null) {
$number = $toLeft.$number;
}
if ($toRight !== null) {
return $number.$toRight;
}
return $number;
}
}