Apply rector, phpstan and php-cs-fixer
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Tristan 2022-11-29 19:52:02 +01:00
parent f35c24d35d
commit b07b0b2ae8
Signed by: trizz
SSH Key Fingerprint: SHA256:Xsd2dTN+ZC3OZWfvuKIDMQ/1lWicuINSEPgRQw/CJT8
22 changed files with 869 additions and 1105 deletions

View File

@ -9,22 +9,29 @@ steps:
- composer install - composer install
- name: phpstan - name: phpstan
image: php:8 image: php:8.1
depends_on: depends_on:
- install - install
commands: commands:
- vendor/bin/phpstan analyse - vendor/bin/phpstan analyse
- name: rector
image: php:8.1
depends_on:
- install
commands:
- vendor/bin/rector process --dry-run
- name: phpunit - name: phpunit
image: php:8 image: php:8.1
depends_on: depends_on:
- install - install
commands: commands:
- vendor/bin/phpunit - vendor/bin/phpunit
- name: style check - name: style check
image: php:8 image: php:8.1
depends_on: depends_on:
- install - install
commands: commands:
- PHP_CS_FIXER_IGNORE_ENV=true vendor/bin/php-cs-fixer fix - vendor/bin/php-cs-fixer fix

View File

@ -14,7 +14,6 @@ return $config
'phpdoc_order' => true, 'phpdoc_order' => true,
'ordered_class_elements' => true, 'ordered_class_elements' => true,
'multiline_whitespace_before_semicolons' => false, 'multiline_whitespace_before_semicolons' => false,
'no_superfluous_phpdoc_tags' => false,
'phpdoc_annotation_without_dot' => false, 'phpdoc_annotation_without_dot' => false,
'phpdoc_types_order' => [ 'phpdoc_types_order' => [
'null_adjustment' => 'always_last', 'null_adjustment' => 'always_last',

54
Taskfile.yaml Normal file
View File

@ -0,0 +1,54 @@
# https://taskfile.dev
version: '3'
vars:
PHP_IMAGE: php:8.1
tasks:
default:
cmds:
- task --list-all
silent: true
check:
cmds:
- task: echo_title
vars: {TITLE: Running php-cs-fixer...}
- task: style
- task: echo_title
vars: {TITLE: Running phpstan...}
- task: phpstan
- task: echo_title
vars: { TITLE: Running rector... }
- task: rector
- task: echo_title
vars: {TITLE: Running phpunit}
- task: phpunit
style:
cmds:
- php vendor/bin/php-cs-fixer fix
silent: true
phpstan:
cmds:
- php vendor/bin/phpstan --configuration=./phpstan.neon analyse
silent: true
rector:
cmds:
- php vendor/bin/rector process
silent: true
phpunit:
cmds:
- php vendor/bin/phpunit
silent: true
echo_title:
silent: true
cmds:
- echo ------------------------
- echo {{.TITLE}}
- echo ------------------------

10
aoc
View File

@ -7,11 +7,15 @@ use Symfony\Component\Console\Application;
use trizz\AdventOfCode\ExecuteDay; use trizz\AdventOfCode\ExecuteDay;
use trizz\AdventOfCode\Puzzle; use trizz\AdventOfCode\Puzzle;
(new CollisionProvider)->register(); (new CollisionProvider())->register();
$application = new Application(); $application = new Application('Advent of Code by trizz');
$application->add(new Puzzle()); $application->add(new Puzzle());
$application->add(new ExecuteDay()); $application->add(new ExecuteDay());
$application->run(); try {
$application->run();
} catch (Exception $e) {
echo $e->getMessage();
}

View File

@ -12,16 +12,17 @@
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"ext-mbstring": "*", "ext-mbstring": "*",
"symfony/console": "^5", "cebe/markdown": "^1.2",
"cebe/markdown": "^1.2"
"phppkg/cli-markdown": "^2.0", "phppkg/cli-markdown": "^2.0",
"symfony/console": "^6"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^3.3", "friendsofphp/php-cs-fixer": "^3.3",
"jetbrains/phpstorm-attributes": "^1.0", "jetbrains/phpstorm-attributes": "^1.0",
"nunomaduro/collision": "^5.10", "nunomaduro/collision": "^6",
"phpstan/phpstan": "^1.2", "phpstan/phpstan": "^1.2",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"rector/rector": "^0.14.8",
"symfony/var-dumper": "^6.0" "symfony/var-dumper": "^6.0"
}, },
"autoload": { "autoload": {
@ -34,11 +35,6 @@
"Tests\\": "tests/" "Tests\\": "tests/"
} }
}, },
"scripts": {
"test": "vendor/bin/phpunit",
"style": "PHP_CS_FIXER_IGNORE_ENV=true vendor/bin/php-cs-fixer fix",
"phpstan": "vendor/bin/phpstan analyse"
},
"config": { "config": {
"sort-packages": true, "sort-packages": true,
"optimize-autoloader": true "optimize-autoloader": true

1552
composer.lock generated

File diff suppressed because it is too large Load Diff

56
phpstan-baseline.neon Normal file
View File

@ -0,0 +1,56 @@
parameters:
ignoreErrors:
-
message: "#^Method trizz\\\\AdventOfCode\\\\Y21\\\\Day4\\:\\:arrayHasSingleValue\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day4.php
-
message: "#^Method trizz\\\\AdventOfCode\\\\Y21\\\\Day4\\:\\:checkCards\\(\\) has parameter \\$cards with no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day4.php
-
message: "#^Method trizz\\\\AdventOfCode\\\\Y21\\\\Day4\\:\\:checkCards\\(\\) has parameter \\$finishedCards with no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day4.php
-
message: "#^Parameter \\#1 \\$array of function array_values expects array, array\\<mixed, int\\|false\\>\\|string given\\.$#"
count: 1
path: src/Y21/Day4.php
-
message: "#^Parameter \\#1 \\$numberList of method trizz\\\\AdventOfCode\\\\Y21\\\\Day4\\:\\:explodeNumbers\\(\\) expects string, array\\<mixed, int\\|false\\>\\|string given\\.$#"
count: 1
path: src/Y21/Day4.php
-
message: "#^Method trizz\\\\AdventOfCode\\\\Y21\\\\Day6\\:\\:processDay\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day6.php
-
message: "#^Parameter \\#1 \\$state of method trizz\\\\AdventOfCode\\\\Y21\\\\Day6\\:\\:processDay\\(\\) expects array\\{int\\: int\\}, array given\\.$#"
count: 1
path: src/Y21/Day6.php
-
message: "#^Method trizz\\\\AdventOfCode\\\\Y21\\\\Day7\\:\\:calculateFuel\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#"
count: 1
path: src/Y21/Day7.php
-
message: "#^Method trizz\\\\AdventOfCode\\\\Y21\\\\Day8\\:\\:mapDigits\\(\\) has parameter \\$patterns with no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day8.php
-
message: "#^Property trizz\\\\AdventOfCode\\\\Y21\\\\Day8\\:\\:\\$digitPatterns type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day8.php
-
message: "#^Property trizz\\\\AdventOfCode\\\\Y21\\\\Day8\\:\\:\\$patternDigits type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Y21/Day8.php

View File

@ -3,3 +3,6 @@ parameters:
paths: paths:
- src - src
- tests - tests
includes:
- phpstan-baseline.neon

33
rector.php Normal file
View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths(
[
__DIR__.'/src',
__DIR__.'/tests',
]
);
// register a single rule
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
// define sets of rules
$rectorConfig->sets(
[
LevelSetList::UP_TO_PHP_81,
SetList::CODE_QUALITY,
SetList::CODING_STYLE,
SetList::TYPE_DECLARATION_STRICT,
SetList::NAMING,
SetList::PRIVATIZATION,
SetList::EARLY_RETURN,
]
);
};

View File

@ -7,19 +7,14 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class ExecuteDay extends Command final class ExecuteDay extends Command
{ {
protected int $day; private int $day;
private int $year;
protected int $year;
/**
* @var string The title.
*/
private string $title; private string $title;
/**
* Configure the command.
*/
protected function configure(): void protected function configure(): void
{ {
$this $this
@ -29,10 +24,6 @@ class ExecuteDay extends Command
->addArgument('year', InputArgument::OPTIONAL, 'The year', date('y')); ->addArgument('year', InputArgument::OPTIONAL, 'The year', date('y'));
} }
/**
* Initializes the command after the input has been bound and before the input
* is validated.
*/
protected function initialize(InputInterface $input, OutputInterface $output): void protected function initialize(InputInterface $input, OutputInterface $output): void
{ {
$this->day = $input->getArgument('day'); $this->day = $input->getArgument('day');
@ -45,14 +36,10 @@ class ExecuteDay extends Command
$output->writeln(str_repeat('-', strlen($this->title))); $output->writeln(str_repeat('-', strlen($this->title)));
} }
/**
* Executes the current command.
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$className = sprintf('%s\\Y%d\\Day%d', __NAMESPACE__, $this->year, $this->day); $className = sprintf('%s\\Y%d\\Day%d', __NAMESPACE__, $this->year, $this->day);
/** @var Solution $class */ /** @var Solution $class */
$class = new $className(); $class = new $className();
$class->loadData(); $class->loadData();

View File

@ -2,25 +2,23 @@
namespace trizz\AdventOfCode; namespace trizz\AdventOfCode;
use PhpPkg\CliMarkdown\CliMarkdown;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use trizz\AdventOfCode\Utils\SymfonyConsoleMarkdown;
class Puzzle extends Command final class Puzzle extends Command
{ {
protected function configure(): void protected function configure(): void
{ {
$this $this
->setName('puzzle') ->setName('puzzle')
->setDescription('Show the puzzle description.')
->addArgument('day', InputArgument::REQUIRED, 'The day number.') ->addArgument('day', InputArgument::REQUIRED, 'The day number.')
->addArgument('year', InputArgument::OPTIONAL, 'The year', date('y')); ->addArgument('year', InputArgument::OPTIONAL, 'The year', date('y'));
} }
/**
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$contents = file_get_contents( $contents = file_get_contents(
@ -31,7 +29,14 @@ class Puzzle extends Command
(int) $input->getArgument('day') (int) $input->getArgument('day')
) )
); );
$rendered = (new SymfonyConsoleMarkdown())->render($contents);
if (!$contents) {
$output->writeln('Can not read puzzle.');
return Command::FAILURE;
}
$rendered = (new CliMarkdown())->render($contents);
$output->writeln($rendered); $output->writeln($rendered);

View File

@ -16,12 +16,14 @@ abstract class Solution
/** /**
* @var string[] The data to use. * @var string[] The data to use.
*
* @psalm-suppress PropertyNotSetInConstructor * @psalm-suppress PropertyNotSetInConstructor
*/ */
public ?array $data = null; public ?array $data = null;
/** /**
* @var string[] The example data. * @var string[] The example data.
*
* @psalm-suppress PropertyNotSetInConstructor * @psalm-suppress PropertyNotSetInConstructor
*/ */
public ?array $exampleData = null; public ?array $exampleData = null;
@ -50,7 +52,7 @@ abstract class Solution
return 'n/a'; return 'n/a';
} }
public function loadData() public function loadData(): void
{ {
$dataFile = sprintf('%s/../data/Y%d/day%d/data.txt', __DIR__, $this->year(), $this->day()); $dataFile = sprintf('%s/../data/Y%d/day%d/data.txt', __DIR__, $this->year(), $this->day());
$dataExampleFile = sprintf('%s/../data/Y%d/day%d/example.txt', __DIR__, $this->year(), $this->day()); $dataExampleFile = sprintf('%s/../data/Y%d/day%d/example.txt', __DIR__, $this->year(), $this->day());
@ -80,16 +82,19 @@ abstract class Solution
return (int) substr(explode('\\', static::class)[3], 3); return (int) substr(explode('\\', static::class)[3], 3);
} }
public function hasData() public function hasData(): bool
{ {
return !empty($this->data); return !empty($this->data);
} }
public function hasExampleData() public function hasExampleData(): bool
{ {
return !empty($this->exampleData); return !empty($this->exampleData);
} }
/**
* @return array{part1: int|string, part2: int|string}
*/
#[ArrayShape(['part1' => 'int|string', 'part2' => 'int|string'])] #[ArrayShape(['part1' => 'int|string', 'part2' => 'int|string'])]
public function results(bool $useExampleData = true): array public function results(bool $useExampleData = true): array
{ {

View File

@ -2,7 +2,7 @@
namespace trizz\AdventOfCode\Utils; namespace trizz\AdventOfCode\Utils;
class Arr final class Arr
{ {
/** /**
* Flatten a multi-dimensional array into a single level. * Flatten a multi-dimensional array into a single level.
@ -11,12 +11,11 @@ class Arr
* *
* @see https://github.com/laravel/framework/blob/c16367a1af68d8f3a1addc1a819f9864334e2c66/src/Illuminate/Collections/Arr.php#L221-L249 * @see https://github.com/laravel/framework/blob/c16367a1af68d8f3a1addc1a819f9864334e2c66/src/Illuminate/Collections/Arr.php#L221-L249
* *
* @param iterable $array * @param array<mixed> $array
* @param float|int $depth
* *
* @return array * @return array<mixed>
*/ */
public static function flatten(iterable $array, float|int $depth = INF) public static function flatten(iterable $array, float|int $depth = INF): array
{ {
$result = []; $result = [];

View File

@ -2,7 +2,7 @@
namespace trizz\AdventOfCode\Utils; namespace trizz\AdventOfCode\Utils;
class Str final class Str
{ {
/** /**
* Check if the entirety of string two matches string one. * Check if the entirety of string two matches string one.

View File

@ -4,12 +4,14 @@ namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class Day1 extends Solution final class Day1 extends Solution
{ {
public static int|string|null $part1ExampleResult = 7; public static int|string|null $part1ExampleResult = 7;
public static int|string|null $part1Result = 1688; public static int|string|null $part1Result = 1688;
public static int|string|null $part2ExampleResult = 5; public static int|string|null $part2ExampleResult = 5;
public static int|string|null $part2Result = 1728; public static int|string|null $part2Result = 1728;
/** /**

View File

@ -4,13 +4,15 @@ namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class Day2 extends Solution final class Day2 extends Solution
{ {
public static int|string|null $part1ExampleResult = 150; public static int|string|null $part1ExampleResult = 150;
public static int|string|null $part1Result = 1654760;
public static int|string|null $part1Result = 1_654_760;
public static int|string|null $part2ExampleResult = 900; public static int|string|null $part2ExampleResult = 900;
public static int|string|null $part2Result = 1956047400;
public static int|string|null $part2Result = 1_956_047_400;
/** /**
* {@inheritdoc} * {@inheritdoc}

View File

@ -4,10 +4,11 @@ namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class Day3 extends Solution final class Day3 extends Solution
{ {
public static int|string|null $part1ExampleResult = 198; public static int|string|null $part1ExampleResult = 198;
public static int|string|null $part1Result = 3309596;
public static int|string|null $part1Result = 3_309_596;
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -27,9 +28,9 @@ class Day3 extends Solution
$gammaRate = ''; $gammaRate = '';
$epsilonRate = ''; $epsilonRate = '';
foreach ($bits as $values) { foreach ($bits as $bit) {
$zeros = array_filter($values, static fn ($value) => $value === '0'); $zeros = array_filter($bit, static fn ($value) => $value === '0');
$ones = array_filter($values, static fn ($value) => $value === '1'); $ones = array_filter($bit, static fn ($value) => $value === '1');
$gammaRate .= ($ones > $zeros) ? '1' : '0'; $gammaRate .= ($ones > $zeros) ? '1' : '0';
$epsilonRate .= ($ones < $zeros) ? '1' : '0'; $epsilonRate .= ($ones < $zeros) ? '1' : '0';

View File

@ -4,12 +4,14 @@ namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class Day4 extends Solution final class Day4 extends Solution
{ {
public static int|string|null $part1ExampleResult = 4512; public static int|string|null $part1ExampleResult = 4512;
public static int|string|null $part1Result = 60368; public static int|string|null $part1Result = 60368;
public static int|string|null $part2ExampleResult = 1924; public static int|string|null $part2ExampleResult = 1924;
public static int|string|null $part2Result = 17435; public static int|string|null $part2Result = 17435;
/** /**
@ -30,15 +32,13 @@ class Day4 extends Solution
/** /**
* @param int[] $winningCard * @param int[] $winningCard
* @param int $number
* @psalm-param array<int, array<array-key, bool|int>|string> $winningCard
* *
* @return int * @psalm-param array<int, array<array-key, bool|int>|string> $winningCard
*/ */
protected function calculateScore(array $winningCard, int $number): int private function calculateScore(array $winningCard, int $number): int
{ {
$return = []; $return = [];
array_walk_recursive($winningCard, static function (bool $value, int $key) use (&$return) { array_walk_recursive($winningCard, static function (bool $value, int $key) use (&$return): void {
$return[$key] = $value; $return[$key] = $value;
}); });
$unusedNumbers = array_keys(array_filter($return, static fn (bool $value) => !$value)); $unusedNumbers = array_keys(array_filter($return, static fn (bool $value) => !$value));
@ -47,14 +47,13 @@ class Day4 extends Solution
} }
/** /**
* @param string $numberList * @param non-empty-string $separator
* @param string $separator
* *
* @return int[] * @return int[]
* *
* @psalm-return array<int, int> * @psalm-return array<int, int>
*/ */
protected function explodeNumbers(string $numberList, string $separator): array private function explodeNumbers(string $numberList, string $separator): array
{ {
return array_map( return array_map(
static fn ($value) => (int) $value, static fn ($value) => (int) $value,
@ -67,13 +66,10 @@ class Day4 extends Solution
/** /**
* @param string[] $data * @param string[] $data
* @param bool $firstWins
*
* @return int|string
*/ */
protected function playBingo(array $data, bool $firstWins = true): int|string private function playBingo(array $data, bool $firstWins = true): int|string
{ {
$numbers = $this->explodeNumbers(array_shift($data), ','); $numbers = $this->explodeNumbers(array_shift($data) ?? '', ',');
$cards = $this->setupCards($data); $cards = $this->setupCards($data);
$finishedCards = []; $finishedCards = [];
@ -129,7 +125,7 @@ class Day4 extends Solution
* *
* @psalm-return array<int, array<int, array<false|int>|string>> * @psalm-return array<int, array<int, array<false|int>|string>>
*/ */
protected function setupCards(array $data): array private function setupCards(array $data): array
{ {
$cards = array_chunk($data, 5); $cards = array_chunk($data, 5);
foreach ($cards as $card => $rows) { foreach ($cards as $card => $rows) {
@ -148,7 +144,7 @@ class Day4 extends Solution
* *
* @psalm-return list<int> * @psalm-return list<int>
*/ */
protected function checkCards(array $cards, array $finishedCards): array private function checkCards(array $cards, array $finishedCards): array
{ {
$winningCards = []; $winningCards = [];
// Check rows // Check rows
@ -191,7 +187,7 @@ class Day4 extends Solution
return $winningCards; return $winningCards;
} }
protected function arrayHasSingleValue(array $array, bool $value): bool private function arrayHasSingleValue(array $array, bool $value): bool
{ {
return count(array_unique($array)) === 1 && end($array) === $value; return count(array_unique($array)) === 1 && end($array) === $value;
} }

View File

@ -5,20 +5,22 @@ namespace trizz\AdventOfCode\Y21;
use JetBrains\PhpStorm\Immutable; use JetBrains\PhpStorm\Immutable;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class Day6 extends Solution final class Day6 extends Solution
{ {
public static int|string|null $part1ExampleResult = 5934; public static int|string|null $part1ExampleResult = 5934;
public static int|string|null $part1Result = 350917; public static int|string|null $part1Result = 350917;
public static int|string|null $part2ExampleResult = 26984457539; public static int|string|null $part2ExampleResult = 26_984_457_539;
public static int|string|null $part2Result = 1592918715629;
public static int|string|null $part2Result = 1_592_918_715_629;
/** /**
* @var int[] * @var int[]
*
* @psalm-param array{int: int} * @psalm-param array{int: int}
*/ */
#[Immutable] #[Immutable] private array $startState = [
protected array $startState = [
8 => 0, 8 => 0,
7 => 0, 7 => 0,
6 => 0, 6 => 0,
@ -48,11 +50,10 @@ class Day6 extends Solution
/** /**
* @param int[] $state * @param int[] $state
* @psalm-param array{int: int} $state
* *
* @return array * @psalm-param array{int: int} $state
*/ */
protected function processDay(array $state): array private function processDay(array $state): array
{ {
$newState = $state; $newState = $state;
@ -75,11 +76,11 @@ class Day6 extends Solution
return $newState; return $newState;
} }
protected function processPuzzle(int $numberOfDays, string $data): int private function processPuzzle(int $numberOfDays, string $data): int
{ {
$state = $this->startState; $state = $this->startState;
array_map(static function (string $stateValue) use (&$state) { array_map(static function (string $stateValue) use (&$state): void {
++$state[(int) $stateValue]; ++$state[(int) $stateValue];
}, explode(',', $data)); }, explode(',', $data));

View File

@ -4,13 +4,15 @@ namespace trizz\AdventOfCode\Y21;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class Day7 extends Solution final class Day7 extends Solution
{ {
public static int|string|null $part1ExampleResult = 37; public static int|string|null $part1ExampleResult = 37;
public static int|string|null $part1Result = 344297; public static int|string|null $part1Result = 344297;
public static int|string|null $part2ExampleResult = 168; public static int|string|null $part2ExampleResult = 168;
public static int|string|null $part2Result = 97164301;
public static int|string|null $part2Result = 97_164_301;
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -28,15 +30,10 @@ class Day7 extends Solution
return $this->calculateFuel($data[0], forPart2: true); return $this->calculateFuel($data[0], forPart2: true);
} }
/** private function calculateFuel(string $data, bool $forPart2 = false): int
* @param string $data
* @param bool $forPart2
*
* @return int
*/
protected function calculateFuel(string $data, bool $forPart2 = false): int
{ {
$crabs = array_map(static fn (string $crab) => (int) $crab, explode(',', $data)); $crabs = array_map(static fn (string $crab) => (int) $crab, explode(',', $data));
/** @psalm-param array{int: int} $fuelPerPosition */ /** @psalm-param array{int: int} $fuelPerPosition */
$fuelPerPosition = []; $fuelPerPosition = [];

View File

@ -6,7 +6,7 @@ use trizz\AdventOfCode\Solution;
use trizz\AdventOfCode\Utils\Arr; use trizz\AdventOfCode\Utils\Arr;
use trizz\AdventOfCode\Utils\Str; use trizz\AdventOfCode\Utils\Str;
class Day8 extends Solution final class Day8 extends Solution
{ {
public static int|string|null $part1ExampleResult = 26; public static int|string|null $part1ExampleResult = 26;
@ -14,7 +14,7 @@ class Day8 extends Solution
public static int|string|null $part2ExampleResult = 61229; public static int|string|null $part2ExampleResult = 61229;
public static int|string|null $part2Result = 1027422; public static int|string|null $part2Result = 1_027_422;
private array $digitPatterns; private array $digitPatterns;
@ -26,7 +26,7 @@ class Day8 extends Solution
public function part1(array $data): int public function part1(array $data): int
{ {
$values = array_map( $values = array_map(
static fn ($item) => strlen($item), static fn ($item) => strlen((string) $item),
Arr::flatten( Arr::flatten(
array_map( array_map(
static fn ($item) => explode(' ', $item), static fn ($item) => explode(' ', $item),
@ -48,8 +48,8 @@ class Day8 extends Solution
foreach ($data as $line) { foreach ($data as $line) {
$item = explode(' | ', $line); $item = explode(' | ', $line);
$sequences[] = [ $sequences[] = [
'patterns' => array_map([Str::class, 'sort'], explode(' ', $item[0])), 'patterns' => array_map(Str::sort(...), explode(' ', $item[0])),
'shown' => array_map([Str::class, 'sort'], explode(' ', $item[1])), 'shown' => array_map(Str::sort(...), explode(' ', $item[1])),
]; ];
} }

View File

@ -2,56 +2,84 @@
namespace Tests; namespace Tests;
use trizz\AdventOfCode\ExecuteDay;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use trizz\AdventOfCode\Solution; use trizz\AdventOfCode\Solution;
class SolutionsTest extends TestCase /**
* @internal
*/
final class SolutionsTest extends TestCase
{ {
/** /**
* @dataProvider loadSolutions * @dataProvider loadSolutions
*/ */
public function testSolutionPart1Example(Solution $class): void public function testSolutionPart1Example(Solution $solution): void
{ {
$this->runPart($class, part: 1, testExample: true); $this->runPart($solution, part: 1, testExample: true);
} }
/** /**
* @dataProvider loadSolutions * @dataProvider loadSolutions
*
* @depends testSolutionPart1Example * @depends testSolutionPart1Example
*/ */
public function testSolutionPart1(Solution $class): void public function testSolutionPart1(Solution $solution): void
{ {
$this->runPart($class, part: 1, testExample: false); $this->runPart($solution, part: 1, testExample: false);
} }
/** /**
* @dataProvider loadSolutions * @dataProvider loadSolutions
*
* @depends testSolutionPart1 * @depends testSolutionPart1
*/ */
public function testSolutionPart2Example(Solution $class): void public function testSolutionPart2Example(Solution $solution): void
{ {
$this->runPart($class, part: 2, testExample: true); $this->runPart($solution, part: 2, testExample: true);
} }
/** /**
* @dataProvider loadSolutions * @dataProvider loadSolutions
*
* @depends testSolutionPart2Example * @depends testSolutionPart2Example
*/ */
public function testSolutionPart2(Solution $class): void public function testSolutionPart2(Solution $solution): void
{ {
$this->runPart($class, part: 2, testExample: false); $this->runPart($solution, part: 2, testExample: false);
} }
private function runPart(Solution $class, int $part, bool $testExample): void /**
* @return array<string, array<int, Solution>>
*/
public function loadSolutions(): array
{
$classes = [];
for ($year = 15; $year <= date('y'); ++$year) {
if (is_dir(__DIR__.'/../src/Y'.$year)) {
for ($day = 1; $day < 26; ++$day) {
$className = sprintf('trizz\\AdventOfCode\\Y%d\\Day%d', $year, $day);
if (class_exists($className)) {
/** @var Solution $class */
$class = new $className();
$class->loadData();
$classes["Year '".$year.' / Day '.$day] = [$class];
}
}
}
}
return $classes;
}
private function runPart(Solution $solution, int $part, bool $testExample): void
{ {
if ( if (
($testExample && $class->hasExampleData()) ($testExample && $solution->hasExampleData())
|| (!$testExample && $class->hasData()) || (!$testExample && $solution->hasData())
) { ) {
$expectedResult = $class::${'part'.$part.($testExample ? 'Example' : null).'Result'}; $expectedResult = $solution::${'part'.$part.($testExample ? 'Example' : null).'Result'};
if ($expectedResult) { if ($expectedResult) {
$result = $class->{'part'.$part.'Data'}(useExampleData: $testExample); $result = $solution->{'part'.$part.'Data'}(useExampleData: $testExample);
self::assertSame($expectedResult, $result); self::assertSame($expectedResult, $result);
} else { } else {
$this->markTestSkipped('No '.($testExample ? 'example' : 'expected').' data for part '.$part.'.'); $this->markTestSkipped('No '.($testExample ? 'example' : 'expected').' data for part '.$part.'.');
@ -60,23 +88,4 @@ class SolutionsTest extends TestCase
$this->markTestSkipped('No example and expected data for part '.$part.'.'); $this->markTestSkipped('No example and expected data for part '.$part.'.');
} }
} }
public function loadSolutions(): array
{
$classes = [];
for ($year = 15; $year <= date('y'); $year++) {
if (is_dir(__DIR__.'/../src/Y'.$year)) {
for ($day = 1; $day < 26; $day++) {
$className = sprintf("trizz\\AdventOfCode\\Y%d\\Day%d", $year, $day);
if (class_exists($className)) {
$class = new $className();
$class->loadData();
$classes['Year \''.$year.' / Day '.$day] = [$class];
}
}
}
}
return $classes;
}
} }