Move solutions out of the source itself
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-12-03 20:47:53 +01:00
parent 5c86431824
commit 68583b1b84
22 changed files with 71 additions and 69 deletions

63
data/Y21/day1/Day1.php Normal file
View File

@ -0,0 +1,63 @@
<?php
namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution;
final class Day1 extends Solution
{
public static null|int|string $part1ExampleResult = 7;
public static null|int|string $part1Result = 1688;
public static null|int|string $part2ExampleResult = 5;
public static null|int|string $part2Result = 1728;
#[\Override]
public function part1(array $data): int
{
$previous = null;
$increases = 0;
/** @var int $current */
foreach ($data as $current) {
if ($previous !== null && $previous < $current) {
++$increases;
}
$previous = $current;
}
return $increases;
}
#[\Override]
public function part2(array $data): int
{
$previousSum = null;
$increases = 0;
/**
* @var int $index
* @var int $indexValue
*/
foreach ($data as $index => $indexValue) {
// If no 'next' indexes are available, skip.
if (!isset($data[$index + 1], $data[$index + 2])) {
continue;
}
// Calculate the sum of the current value and the next two.
$newSum = $indexValue + (int) $data[$index + 1] + (int) $data[$index + 2];
if ($previousSum !== null && $previousSum < $newSum) {
++$increases;
}
$previousSum = $newSum;
}
return $increases;
}
}

77
data/Y21/day2/Day2.php Normal file
View File

@ -0,0 +1,77 @@
<?php
namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution;
final class Day2 extends Solution
{
public static null|int|string $part1ExampleResult = 150;
public static null|int|string $part1Result = 1_654_760;
public static null|int|string $part2ExampleResult = 900;
public static null|int|string $part2Result = 1_956_047_400;
#[\Override]
public function part1(array $data): int
{
$depth = 0;
$horizontal = 0;
foreach ($data as $current) {
/**
* @var string $direction
* @var int $distance
*/
[$direction, $distance] = explode(' ', $current);
match ($direction) {
'forward' => $horizontal += $distance,
'down' => $depth += $distance,
'up' => $depth -= $distance,
default => null,
};
}
return $depth * $horizontal;
}
#[\Override]
public function part2(array $data): int
{
$aim = 0;
$depth = 0;
$horizontal = 0;
foreach ($data as $current) {
/**
* @var string $direction
* @var int $distance
*/
[$direction, $distance] = explode(' ', $current);
// Can't use 'match' here because of the multiple expressions for 'forward'.
switch ($direction) {
case 'forward':
$horizontal += $distance;
$depth += $distance * $aim;
break;
case 'down':
$aim += $distance;
break;
case 'up':
$aim -= $distance;
break;
}
}
return $horizontal * $depth;
}
}

39
data/Y21/day3/Day3.php Normal file
View File

@ -0,0 +1,39 @@
<?php
namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution;
final class Day3 extends Solution
{
public static null|int|string $part1ExampleResult = 198;
public static null|int|string $part1Result = 3_309_596;
#[\Override]
public function part1(array $data): int
{
$bits = [];
foreach ($data as $binary) {
$split = str_split($binary);
foreach ($split as $position => $value) {
$bits[$position][] = $value;
}
}
$gammaRate = '';
$epsilonRate = '';
foreach ($bits as $bit) {
$zeros = array_filter($bit, static fn ($value): bool => $value === '0');
$ones = array_filter($bit, static fn ($value): bool => $value === '1');
$gammaRate .= ($ones > $zeros) ? '1' : '0';
$epsilonRate .= ($ones < $zeros) ? '1' : '0';
}
return (int) (bindec($gammaRate) * bindec($epsilonRate));
}
}

191
data/Y21/day4/Day4.php Normal file
View File

@ -0,0 +1,191 @@
<?php
namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution;
final class Day4 extends Solution
{
public static null|int|string $part1ExampleResult = 4512;
public static null|int|string $part1Result = 60368;
public static null|int|string $part2ExampleResult = 1924;
public static null|int|string $part2Result = 17435;
#[\Override]
public function part1(array $data): int|string
{
return $this->playBingo($data, firstWins: true);
}
#[\Override]
public function part2(array $data): int|string
{
return $this->playBingo($data, firstWins: false);
}
/**
* @param int[] $winningCard
*
* @psalm-param array<int, array<array-key, bool|int>|string> $winningCard
*/
private function calculateScore(array $winningCard, int $number): int
{
$return = [];
array_walk_recursive($winningCard, static function (bool $value, int $key) use (&$return): void {
$return[$key] = $value;
});
$unusedNumbers = array_keys(array_filter($return, static fn (bool $value): bool => !$value));
return (int) array_sum($unusedNumbers) * $number;
}
/**
* @param non-empty-string $separator
*
* @return int[]
*
* @psalm-return array<int, int>
*/
private function explodeNumbers(string $numberList, string $separator): array
{
return array_map(
static fn ($value): int => (int) $value,
array_filter(
explode($separator, $numberList),
static fn (string $value): bool => $value !== ''
)
);
}
/**
* @param string[] $data
*/
private function playBingo(array $data, bool $firstWins = true): int|string
{
$numbers = $this->explodeNumbers(array_shift($data) ?? '', ',');
$cards = $this->setupCards($data);
$finishedCards = [];
// Call the numbers.
foreach ($numbers as $number) {
/**
* @var int $cardIndex
* @var int[] $cardRows
*/
foreach ($cards as $cardIndex => $cardRows) {
if (isset($finishedCards[$cardIndex])) {
continue;
}
/**
* @var int $cardRowIndex
* @var int[] $cardRow
*/
foreach ($cardRows as $cardRowIndex => $cardRow) {
if (isset($cardRow[$number])) {
$cards[$cardIndex][$cardRowIndex][$number] = true;
}
}
}
$winningCards = $this->checkCards($cards, $finishedCards);
if ($winningCards === []) {
continue;
}
foreach ($winningCards as $winningCard) {
$lastWinningCard = $cards[$winningCard];
$lastWinNumber = $number;
$finishedCards[$winningCard] = true;
if ($firstWins) {
return $this->calculateScore($lastWinningCard, $number);
}
}
}
if (isset($lastWinningCard, $lastWinNumber)) {
return $this->calculateScore($lastWinningCard, $lastWinNumber);
}
return 'Computer says no...';
}
/**
* @param string[] $data
*
* @return ((false|int)[]|string)[][]
*
* @psalm-return array<int, array<int, array<false|int>|string>>
*/
private function setupCards(array $data): array
{
$cards = array_chunk($data, 5);
foreach ($cards as $card => $rows) {
$cards[$card] = array_map(fn ($value): array => $this->explodeNumbers($value, ' '), $rows);
foreach ($cards[$card] as $row => $number) {
$cards[$card][$row] = array_fill_keys(array_values($number), false);
}
}
return $cards;
}
/**
* @return int[]
*
* @psalm-return list<int>
*/
private function checkCards(array $cards, array $finishedCards): array
{
$winningCards = [];
// Check rows
/**
* @var int $cardIndex
* @var int[] $rows
*/
foreach ($cards as $cardIndex => $rows) {
if (isset($finishedCards[$cardIndex])) {
continue;
}
/** @var int[] $row */
foreach ($rows as $row) {
if ($this->arrayHasSingleValue($row, true)) {
$winningCards[] = $cardIndex;
}
}
// Get the vertical numbers.
$colValues = [];
for ($rowIndex = 0; $rowIndex < 5; ++$rowIndex) {
for ($colIndex = 0; $colIndex < 5; ++$colIndex) {
if (!isset($colValues[$colIndex])) {
$colValues[$colIndex] = [];
}
$colValues[$colIndex] += array_slice((array) $rows[$rowIndex], $colIndex, 1, preserve_keys: true);
}
}
// See if there's a bingo on the vertical numbers.
foreach ($colValues as $colIndex => $colValue) {
if ($this->arrayHasSingleValue($colValue, true)) {
$winningCards[] = $cardIndex;
}
}
}
return $winningCards;
}
private function arrayHasSingleValue(array $array, bool $value): bool
{
return count(array_unique($array)) === 1 && end($array) === $value;
}
}

89
data/Y21/day6/Day6.php Normal file
View File

@ -0,0 +1,89 @@
<?php
namespace trizz\AdventOfCode\Y21;
use JetBrains\PhpStorm\Immutable;
use trizz\AdventOfCode\Solution;
final class Day6 extends Solution
{
public static null|int|string $part1ExampleResult = 5934;
public static null|int|string $part1Result = 350917;
public static null|int|string $part2ExampleResult = 26_984_457_539;
public static null|int|string $part2Result = 1_592_918_715_629;
/**
* @var int[]
*
* @psalm-param array{int: int}
*/
#[Immutable] private array $startState = [
8 => 0,
7 => 0,
6 => 0,
5 => 0,
4 => 0,
3 => 0,
2 => 0,
1 => 0,
0 => 0,
];
#[\Override]
public function part1(array $data): int
{
return $this->processPuzzle(80, $data[0]);
}
#[\Override]
public function part2(array $data): int
{
return $this->processPuzzle(256, $data[0]);
}
/**
* @param int[] $state
*
* @psalm-param array{int: int} $state
*/
private function processDay(array $state): array
{
$newState = $state;
/**
* @var int $key
* @var int $stateValue
*/
foreach ($state as $key => $stateValue) {
$newKey = $key - 1;
if ($newKey < 0) {
$newState[8] = $stateValue;
$newKey = 6;
}
$newState[$key] -= $stateValue;
$newState[$newKey] += $stateValue;
}
return $newState;
}
private function processPuzzle(int $numberOfDays, string $data): int
{
$state = $this->startState;
array_map(static function (string $stateValue) use (&$state): void {
++$state[(int) $stateValue];
}, explode(',', $data));
for ($day = 0; $day < $numberOfDays; ++$day) {
$state = $this->processDay($state);
}
return (int) array_sum($state);
}
}

57
data/Y21/day7/Day7.php Normal file
View File

@ -0,0 +1,57 @@
<?php
namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution;
final class Day7 extends Solution
{
public static null|int|string $part1ExampleResult = 37;
public static null|int|string $part1Result = 344297;
public static null|int|string $part2ExampleResult = 168;
public static null|int|string $part2Result = 97_164_301;
#[\Override]
public function part1(array $data): int
{
return $this->calculateFuel($data[0], forPart2: false);
}
#[\Override]
public function part2(array $data): int
{
return $this->calculateFuel($data[0], forPart2: true);
}
private function calculateFuel(string $data, bool $forPart2 = false): int
{
$crabs = array_map(static fn (string $crab): int => (int) $crab, explode(',', $data));
/** @var array<int, int> $fuelPerPosition */
$fuelPerPosition = [];
$minCrab = min($crabs);
$maxCrab = max($crabs);
for ($position = $minCrab; $position <= $maxCrab; ++$position) {
foreach ($crabs as $crab) {
if (!isset($fuelPerPosition[$position])) {
$fuelPerPosition[$position] = 0;
}
$consumption = abs($position - $crab);
if ($forPart2) {
$consumption = $consumption * ($consumption + 1) / 2;
}
$fuelPerPosition[$position] += $consumption;
}
}
return (int) min($fuelPerPosition);
}
}

129
data/Y21/day8/Day8.php Normal file
View File

@ -0,0 +1,129 @@
<?php
namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution;
use trizz\AdventOfCode\Utils\Arr;
use trizz\AdventOfCode\Utils\Str;
final class Day8 extends Solution
{
public static null|int|string $part1ExampleResult = 26;
public static null|int|string $part1Result = 397;
public static null|int|string $part2ExampleResult = 61229;
public static null|int|string $part2Result = 1_027_422;
private array $digitPatterns;
private array $patternDigits;
#[\Override]
public function part1(array $data): int
{
$values = array_map(
static fn ($item): int => strlen((string) $item),
Arr::flatten(
array_map(
static fn ($item): array => explode(' ', (string) $item),
array_map(
static fn ($item): string => explode(' | ', (string) $item)[1],
$data
)
)
)
);
return count(array_intersect($values, [2, 4, 3, 7]));
}
#[\Override]
public function part2(array $data): int|string
{
$sequences = [];
foreach ($data as $line) {
$item = explode(' | ', $line);
$sequences[] = [
'patterns' => array_map(Str::sort(...), explode(' ', $item[0])),
'shown' => array_map(Str::sort(...), explode(' ', $item[1])),
];
}
$results = [];
foreach ($sequences as $sequence) {
$this->mapDigits($sequence['patterns']);
$output = '';
foreach ($sequence['shown'] as $pattern) {
$output .= $this->patternDigits[$pattern];
}
$results[] = (int) $output;
}
return array_sum($results);
}
/**
* @param array $patterns
*
* Code based on (sorry, didn't have a clue to solve this one, so I needed some inspiration):
*
* @see https://github.com/MueR/adventofcode/blob/master/src/AdventOfCode2021/Day08/Day08.php
*/
public function mapDigits(array $patterns): void
{
/** @noinspection PackedHashtableOptimizationInspection */
$findDigit = [
// 1 is the only one with 2 segments
1 => static fn (string $pattern): bool => strlen($pattern) === 2,
// 7 is the only one with 3 segments
7 => static fn (string $pattern): bool => strlen($pattern) === 3,
// 4 is the only one with 4 segments
4 => static fn (string $pattern): bool => strlen($pattern) === 4,
// 8 is the only one with 7 segments
8 => static fn (string $pattern): bool => strlen($pattern) === 7,
// 9 is 6 segments, matches segments for 4
9 => fn (string $pattern): bool => strlen($pattern) === 6 && Str::matchesAll(
$pattern,
$this->digitPatterns[4] ?? ''
),
// 0 is 6 segments, matching 1's segments (9 is already out)
0 => fn (string $pattern): bool => strlen($pattern) === 6 && Str::matchesAll(
$pattern,
$this->digitPatterns[1] ?? ''
),
// 6 is 6 segments, the only one left
6 => static fn (string $pattern): bool => strlen($pattern) === 6,
// 3 is 5 segments and matches 1's segments
3 => fn (string $pattern): bool => strlen($pattern) === 5 && Str::matchesAll(
$pattern,
$this->digitPatterns[1] ?? ''
),
// 5 is 5 segments, and 9 has all the segments of 5
5 => fn (string $pattern): bool => strlen($pattern) === 5 && Str::matchesAll(
$this->digitPatterns[9] ?? '',
$pattern
),
// 2 is the only one remaining
2 => static fn (string $pattern): bool => true,
];
foreach ($findDigit as $digit => $test) {
foreach ($patterns as $key => $pattern) {
if (!$test($pattern)) {
continue;
}
unset($patterns[$key]);
$this->patternDigits[$pattern] = $digit;
$this->digitPatterns[$digit] = $pattern;
break;
}
}
}
}