diff --git a/aoc b/aoc index 7be3c49..dbfb0d6 100755 --- a/aoc +++ b/aoc @@ -4,6 +4,7 @@ require __DIR__.'/vendor/autoload.php'; use NunoMaduro\Collision\Provider as CollisionProvider; use Symfony\Component\Console\Application; +use trizz\AdventOfCode\Commands\AddDay; use trizz\AdventOfCode\Commands\ExecuteDay; use trizz\AdventOfCode\Commands\Puzzle; use trizz\AdventOfCode\Commands\TestDay; @@ -15,6 +16,7 @@ $application = new Application('Advent of Code by trizz'); $application->add(new Puzzle()); $application->add(new ExecuteDay()); $application->add(new TestDay()); +$application->add(new AddDay()); try { $application->run(); diff --git a/composer.json b/composer.json index 8129715..2db3d64 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,8 @@ "php": "^8.3", "ext-mbstring": "*", "cebe/markdown": "^1.2", + "laravel/prompts": "^0.1.13", + "nette/php-generator": "^4.1", "phppkg/cli-markdown": "^2.0", "symfony/console": "^6" }, diff --git a/composer.lock b/composer.lock index 12d5c72..e8d0ce5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fca53f959d62471b393002b4f61d1351", + "content-hash": "bd86bd7f56cbbfba41f30bc5a5a27b50", "packages": [ { "name": "cebe/markdown", @@ -70,6 +70,413 @@ }, "time": "2018-03-26T11:24:36+00:00" }, + { + "name": "illuminate/collections", + "version": "v10.34.2", + "source": { + "type": "git", + "url": "https://github.com/illuminate/collections.git", + "reference": "8e4c4f97ea066cd6aec962ef8a6abc09dfd5e754" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/collections/zipball/8e4c4f97ea066cd6aec962ef8a6abc09dfd5e754", + "reference": "8e4c4f97ea066cd6aec962ef8a6abc09dfd5e754", + "shasum": "" + }, + "require": { + "illuminate/conditionable": "^10.0", + "illuminate/contracts": "^10.0", + "illuminate/macroable": "^10.0", + "php": "^8.1" + }, + "suggest": { + "symfony/var-dumper": "Required to use the dump method (^6.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "files": [ + "helpers.php" + ], + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Collections package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2023-11-27T14:46:52+00:00" + }, + { + "name": "illuminate/conditionable", + "version": "v10.34.2", + "source": { + "type": "git", + "url": "https://github.com/illuminate/conditionable.git", + "reference": "d0958e4741fc9d6f516a552060fd1b829a85e009" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/conditionable/zipball/d0958e4741fc9d6f516a552060fd1b829a85e009", + "reference": "d0958e4741fc9d6f516a552060fd1b829a85e009", + "shasum": "" + }, + "require": { + "php": "^8.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Conditionable package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2023-02-03T08:06:17+00:00" + }, + { + "name": "illuminate/contracts", + "version": "v10.34.2", + "source": { + "type": "git", + "url": "https://github.com/illuminate/contracts.git", + "reference": "f6bf37a272fda164f6c451407c99f820eb1eb95b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/f6bf37a272fda164f6c451407c99f820eb1eb95b", + "reference": "f6bf37a272fda164f6c451407c99f820eb1eb95b", + "shasum": "" + }, + "require": { + "php": "^8.1", + "psr/container": "^1.1.1|^2.0.1", + "psr/simple-cache": "^1.0|^2.0|^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Contracts package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2023-10-30T00:59:22+00:00" + }, + { + "name": "illuminate/macroable", + "version": "v10.34.2", + "source": { + "type": "git", + "url": "https://github.com/illuminate/macroable.git", + "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27", + "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Macroable package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2023-06-05T12:46:42+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.1.13", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "e1379d8ead15edd6cc4369c22274345982edc95a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/e1379d8ead15edd6cc4369c22274345982edc95a", + "reference": "e1379d8ead15edd6cc4369c22274345982edc95a", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/collections": "^10.0|^11.0", + "php": "^8.1", + "symfony/console": "^6.2|^7.0" + }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-mockery": "^1.1" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.1.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "support": { + "issues": "https://github.com/laravel/prompts/issues", + "source": "https://github.com/laravel/prompts/tree/v0.1.13" + }, + "time": "2023-10-27T13:53:59+00:00" + }, + { + "name": "nette/php-generator", + "version": "v4.1.2", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "abc0e79b2d02d4b8aba5933765b90df3f610c143" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/abc0e79b2d02d4b8aba5933765b90df3f610c143", + "reference": "abc0e79b2d02d4b8aba5933765b90df3f610c143", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.9 || ^4.0", + "php": "8.0 - 8.3" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.4", + "nikic/php-parser": "^4.15", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.8" + }, + "suggest": { + "nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.3 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "support": { + "issues": "https://github.com/nette/php-generator/issues", + "source": "https://github.com/nette/php-generator/tree/v4.1.2" + }, + "time": "2023-10-29T22:57:32+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.3", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/a9d127dd6a203ce6d255b2e2db49759f7506e015", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015", + "shasum": "" + }, + "require": { + "php": ">=8.0 <8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.3" + }, + "time": "2023-10-29T21:02:13+00:00" + }, { "name": "phppkg/cli-markdown", "version": "v2.0.2", @@ -167,6 +574,57 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, { "name": "symfony/console", "version": "v6.4.1", diff --git a/src/Commands/AddDay.php b/src/Commands/AddDay.php new file mode 100644 index 0000000..f658671 --- /dev/null +++ b/src/Commands/AddDay.php @@ -0,0 +1,150 @@ +setName('add:day') + ->setDescription('Add a new day.') + ->addArgument('day', InputArgument::OPTIONAL, 'The day number.') + ->addArgument('year', InputArgument::OPTIONAL, 'The year', date('y')); + } + + #[\Override] + protected function execute(InputInterface $input, OutputInterface $output): int + { + $day = $input->getArgument('day'); + $year = $input->getArgument('year'); + + if ($day === null) { + $day = text( + label: 'For which day?', + placeholder: '3', + default: date('j'), + required: true, + validate: fn ($value) => is_numeric($value) && $value > 0 && $value < 26 ? null : 'Please enter a valid day number.' + ); + } + + $example1Result = text( + label: 'Please enter the result for example 1.', + required: true, + validate: fn ($value) => is_numeric($value) ? null : 'Please enter a valid number.' + ); + + // Create short year. + $year = strlen($year) === 4 ? substr($year, 2) : $year; + + $output->writeln("Adding files for day {$day} of year '{$year}."); + + $this + ->createDirs($year, $day) + ->createClass($day, $year, $example1Result) + ->addExampleDirs($year, $day); + + return Command::SUCCESS; + } + + protected function createDirs(int $year, int $day): self + { + if (!is_dir($dir = "src/Y{$year}") && !mkdir($dir) && !is_dir($dir)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir)); + } + + if (!is_dir($dir = "data/Y{$year}/day{$day}") && !mkdir($dir) && !is_dir($dir)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir)); + } + + return $this; + } + + protected function createClass(string $day, string $year, string $example1Result): self + { + $namespace = new PhpNamespace('trizz\AdventOfCode\Y'.$year); + $class = new ClassType('Day'.$day); + + $class->setFinal() + ->setExtends(Solution::class); + + $this->createClassProperties($class, $example1Result); + $this->createClassMethods($class); + + $namespace->add($class); + $this->printClassToFile($class, $year, $day, $namespace); + + return $this; + } + + private function createClassProperties(ClassType $class, string $example1Result): void + { + $properties = [ + 'part1ExampleResult' => $example1Result, + 'part1Result' => null, + 'part2ExampleResult' => null, + 'part2Result' => null, + ]; + + foreach ($properties as $name => $value) { + $class + ->addProperty($name, $value) + ->setPublic() + ->setStatic() + ->setType('null|int|string'); + } + } + + private function createClassMethods(ClassType $class): void + { + $methods = ['part1', 'part2']; + + foreach ($methods as $methodName) { + $class + ->addMethod($methodName) + ->setReturnType('int') + ->setBody('return -1;') + ->addParameter('data')->setType('array'); + } + } + + private function printClassToFile(ClassType $class, string $year, string $day, PhpNamespace $namespace): void + { + $printer = new Printer(); + $printer->indentation = ' '; + + $filename = __DIR__.'/../Y'.$year.'/Day'.$day.'.php'; + if (file_exists($filename)) { + throw new \RuntimeException("File {$filename} already exists."); + } + + file_put_contents($filename, 'printNamespace($namespace)); + } + + protected function addExampleDirs(mixed $year, mixed $day): self + { + $dataDir = __DIR__.'/../../data/Y'.$year.'/day'.$day; + + if (!is_dir($dataDir) && !mkdir($dataDir) && !is_dir($dataDir)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $dataDir)); + } + + touch($dataDir.'/example.txt'); + touch($dataDir.'/data.txt'); + + return $this; + } +}