diff --git a/README.md b/README.md index 8ce430d..f343ccd 100644 --- a/README.md +++ b/README.md @@ -1,62 +1,96 @@ -## Advent of Code 2022 PHP -The solutions to [advent of code 2022](https://adventofcode.com/2022), solved using PHP 8.2. By [James Thatcher](http://github.com/jthatch) +# Advent of Code 2022 - PHP -### Solutions 🥳🎉 -> 🎄 [Day 1](/src/Days/Day1.php) 🎅 [Day 2](/src/Days/Day2.php) ☃️ [Day 3](/src/Days/Day3.php) -> 🦌 [Day 4](/src/Days/Day4.php) 🍪 [Day 5](/src/Days/Day5.php) 🥛 [Day 6](/src/Days/Day6.php) -> 🧦 [Day 7](/src/Days/Day7.php) 🎁 [Day 8](/src/Days/Day8.php) ⛄ [Day 9](/src/Days/Day9.php) -> 🛐 [Day 10](/src/Days/Day10.php) ⛄ [Day 11](/src/Days/Day11.php) 🧝 [Day 12](/src/Days/Day12.php) -> 🎄 [Day 13](/src/Days/Day13.php) 🎅 [Day 14](/src/Days/Day14.php) ☃️ [Day 15](/src/Days/Day15.php) - -### About -My attempts at tacking the awesome challenges at [Advent of Code 2022](https://adventofcode.com/2022/day/1) using PHP 8.2. +This repository contains PHP solutions for the [Advent of Code 2022](https://adventofcode.com/2022) challenges. +## Requirements -![day runner in action](/aoc-2022-jt.png "AOC 2022 PHP by James Thatcher") +- Docker +- Bash shell -## Day 14 Interactive Mode -[Day 14](/src/Days/Day14.php) has an interactive mode that allows you to see the sand fall in real time. +## Setup -Demo: [aoc-2022-jt-day-14.webm (648kb)](/aoc-2022-jt-day-14.webm) +1. Clone this repository +2. Make sure the script is executable: `chmod +x aoc.sh` +3. Run `./aoc.sh build` to build the Docker image +4. Run `./aoc.sh composer` to install dependencies -![day 14 interactive mode](/aoc-2022-jt-day-14.png) +## Usage -### Commands -_Note: checkout the code then run `make run`. The docker and composer libraries will auto install._ +The `aoc.sh` script provides a wrapper around Docker to run the PHP code. It allows you to pass command-line arguments directly to the PHP script. -**Solve all days puzzles** -`make run` +### Basic Commands -**Solve an individual days puzzles** -`make run day={N}` e.g. `make run day=13` +```bash +# Run all days +./aoc.sh run -**Solve multiple days puzzles** -`make run day={N},{N1}-{N2}...` e.g. `make run day=1-5,7,10,10,10` _Runs days 1-5, 7 and 10 3 times_ +# Run a specific day +./aoc.sh run --day=1 -**Solve a single part of a days puzzles** -`make run day={N} part={N}` e.g. `make run day=16 part=2` +# Run a specific day with examples +./aoc.sh run --day=15 --examples -**Create the next days PHP file and download puzzle from server** -_Auto detects what current Day you are on and will create the next (only if the files don't exist)_ -```shell -make next -# Created new file: src/Days/Day8.php -# Fetching latest input using day=8 AOC_COOKIE=53616c7465645f5f539435aCL1P -# ./input/day8.txt downloaded +# Run multiple days +./aoc.sh run --day=1-5,9 + +# Run a specific part of a day +./aoc.sh run --day=6,7 --part=2 + +# Show help for the run.php script +./aoc.sh run --help ``` -**Use XDebug** -`make xdebug` +### Other Commands + +```bash +# Build the Docker image +./aoc.sh build + +# Launch a shell into the Docker container +./aoc.sh shell + +# Run composer commands +./aoc.sh composer update +./aoc.sh composer require package/name + +# Run with xdebug enabled +./aoc.sh xdebug --day=1 + +# Run with xdebug profiler +./aoc.sh xdebug-profile + +# Run PHP CS Fixer +./aoc.sh pint + +# Run PHPStan +./aoc.sh phpstan + +# Retrieve the latest day's input from server +./aoc.sh get-input + +# Create next day's file +./aoc.sh next + +# Show help +./aoc.sh help +``` + +## Getting Input Files + +To retrieve input files from the Advent of Code website, you need to set the `AOC_COOKIE` environment variable with your session cookie: + +```bash +export AOC_COOKIE=your_session_cookie_here +./aoc.sh get-input +``` + +## Advantages Over the Previous Makefile Approach + +1. **Direct Argument Passing**: All arguments after the `run` command are passed directly to the PHP script, allowing for commands like `./aoc.sh run --help`. +2. **Simpler Syntax**: The command structure is more intuitive and follows standard CLI patterns. +3. **Better Help Documentation**: Comprehensive help is available with `./aoc.sh help`. +4. **Easier Maintenance**: The script is more modular and easier to extend with new functionality. -**Xdebug can also be triggered on a single days and/or part** -`make xdebug day={N}` e.g. `make xdebug day=13` or `make xdebug day=13 part=2` +## License -IDE settings: -- `10000` - xdebug port -- `aoc-2021` - PHP_IDE_CONFIG (what you put in PHPStorm -> settings -> debug -> server -> name) -- `/app` - absolute path on the server -- see [xdebug.ini](/xdebug.ini) if you're stuck \ No newline at end of file +[MIT License](LICENSE) \ No newline at end of file diff --git a/aoc b/aoc new file mode 120000 index 0000000..f299b62 --- /dev/null +++ b/aoc @@ -0,0 +1 @@ +aoc.sh \ No newline at end of file diff --git a/aoc.sh b/aoc.sh new file mode 100755 index 0000000..ffd3788 --- /dev/null +++ b/aoc.sh @@ -0,0 +1,187 @@ +#!/bin/bash + +# Advent of Code 2022 - Docker wrapper script +# This script replaces the Makefile approach to allow for direct passing of arguments + +# Configuration +IMAGE_NAME="aoc-2022" +UID=$(id -u) +GID=$(id -g) +PHP_TWEAKS="-dmemory_limit=1G -dopcache.enable_cli=1 -dopcache.jit_buffer_size=100M -dopcache.jit=1255" + +# Function to display help +show_help() { + echo -e "\033[32m---------------------------------------------------------------------------" + echo -e " Advent of Code 2022 - James Thatcher" + echo -e "---------------------------------------------------------------------------\033[0m" + echo "" + echo "Usage: ./aoc.sh [command] [options]" + echo "" + echo "Commands:" + echo " run [options] Run the PHP script with options passed directly to run.php" + echo " build Build the Docker image" + echo " shell Launch a shell into the Docker container" + echo " composer [cmd] Run composer commands (default: update)" + echo " xdebug [options] Run with xdebug enabled" + echo " xdebug-profile Run with xdebug profiler" + echo " pint Run PHP CS Fixer" + echo " phpstan Run PHPStan" + echo " get-input Retrieve the latest day's input from server" + echo " next Create next day's file" + echo " help Show this help message" + echo "" + echo "Examples:" + echo " ./aoc.sh run --day=15 --examples" + echo " ./aoc.sh run --day=1-5,9" + echo " ./aoc.sh run --day=10" + echo " ./aoc.sh run --day=6,7 --part=2" + echo " ./aoc.sh run --help" + echo "" +} + +# Function to check if Docker image exists +check_docker_image() { + if ! docker image inspect "$IMAGE_NAME" &>/dev/null; then + echo -e "\nFirst run detected! No $IMAGE_NAME docker image found, running docker build...\n" + build_docker_image + return 1 + fi + return 0 +} + +# Function to check if vendor directory exists +check_vendor() { + if [ ! -d "vendor" ]; then + echo -e "\nFirst run detected! No vendor/ folder found, running composer update...\n" + run_composer "update" + return 1 + fi + return 0 +} + +# Function to build Docker image +build_docker_image() { + DOCKER_BUILDKIT=1 docker build --build-arg UID="$UID" --build-arg GID="$GID" \ + --tag="$IMAGE_NAME" \ + -f Dockerfile . +} + +# Function to run Docker container +run_docker() { + docker run -it --rm --init \ + --name "$IMAGE_NAME" \ + -u "$UID:$GID" \ + -v "$(pwd):/app" \ + -e PHP_IDE_CONFIG="serverName=$IMAGE_NAME" \ + -w /app \ + "$@" +} + +# Function to run PHP script +run_php() { + check_docker_image || return + check_vendor || return + run_docker "$IMAGE_NAME" php $PHP_TWEAKS run.php "$@" +} + +# Function to run composer +run_composer() { + check_docker_image || return + run_docker "$IMAGE_NAME" composer --no-cache "$@" +} + +# Function to run with xdebug +run_xdebug() { + check_docker_image || return + check_vendor || return + run_docker -e XDEBUG_MODE=debug "$IMAGE_NAME" php -dmemory_limit=1G run.php "$@" +} + +# Function to run xdebug profiler +run_xdebug_profile() { + check_docker_image || return + check_vendor || return + run_docker -e XDEBUG_MODE=profile "$IMAGE_NAME" php -dxdebug.output_dir=/app -dmemory_limit=1G run.php "$@" +} + +# Function to get input +get_input() { + local latestDay + if [[ "$(uname -s | tr A-Z a-z)" == "linux" ]]; then + latestDay=$(find src/Days -maxdepth 1 -type f \( -name "Day[0-9][0-9].php" -o -name "Day[0-9].php" \) -printf '%f\n' | sort -Vr | head -1 | grep -o '[0-9]\+' || echo "1") + else + latestDay=$(find src/Days -maxdepth 1 -type f \( -name "Day[0-9][0-9].php" -o -name "Day[0-9].php" \) -print0 | xargs -0 stat -f '%N ' | sort -Vr | head -1 | grep -o '[0-9]\+' || echo "1") + fi + + if [ -z "$AOC_COOKIE" ]; then + echo -e "Missing AOC_COOKIE env\n\nPlease login to https://adventofcode.com/ and retrieve your session cookie." + echo -e "Then set the environmental variable AOC_COOKIE. e.g. export AOC_COOKIE=53616c7465645f5f2b44c4d4742765e14...\n" + return 1 + fi + + echo -e "Fetching latest input using day=$latestDay AOC_COOKIE=$AOC_COOKIE" + curl -s --location --request GET "https://adventofcode.com/2022/day/$latestDay/input" --header "Cookie: session=$AOC_COOKIE" -o "./input/day$latestDay.txt" && echo "./input/day$latestDay.txt downloaded" || echo "error downloading" +} + +# Function to create next day file +create_next_day() { + echo "Creating next day's file..." + next_day=$(ls src/Days | grep -oE 'Day[0-9]+' | sort -V | tail -n 1 | sed 's/Day//') + next_day=$((next_day + 1)) + sed "s/DayX/Day$next_day/g" stub/DayX.php.stub > "src/Days/Day$next_day.php" + echo "Created src/Days/Day$next_day.php" + get_input +} + +# Main command processing +case "$1" in + run) + shift + run_php "$@" + ;; + build) + build_docker_image + ;; + shell) + check_docker_image || exit + run_docker "$IMAGE_NAME" /bin/bash + ;; + composer) + shift + if [ $# -eq 0 ]; then + run_composer "update" + else + run_composer "$@" + fi + ;; + xdebug) + shift + run_xdebug "$@" + ;; + xdebug-profile) + run_xdebug_profile + ;; + pint) + check_docker_image || exit + run_docker "$IMAGE_NAME" composer --no-cache run pint + ;; + phpstan) + check_docker_image || exit + run_docker "$IMAGE_NAME" composer run phpstan + ;; + get-input) + get_input + ;; + next) + create_next_day + ;; + help|--help|-h) + show_help + ;; + *) + show_help + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/src/Runner/ParseCliArgs.php b/src/Runner/ParseCliArgs.php index 6780464..48e1763 100644 --- a/src/Runner/ParseCliArgs.php +++ b/src/Runner/ParseCliArgs.php @@ -26,6 +26,7 @@ public function getOptions(): Options days: $this->options['day']->value ?? null, parts: $this->options['part']->value ?? null, withExamples: (bool) ($this->options['examples']->value ?? false), + wantsHelp: (bool) ($this->options['help']->value ?? false), ); }