mirror of
https://github.com/thib8956/advent-of-code.git
synced 2026-05-25 19:53:26 +00:00
refactor: move init command to helper.py
This commit is contained in:
@@ -11,10 +11,12 @@ all: venv install
|
|||||||
|
|
||||||
# Create virtual environment if it doesn't exist
|
# Create virtual environment if it doesn't exist
|
||||||
venv:
|
venv:
|
||||||
@echo "Creating virtual environment..."
|
|
||||||
@if [ ! -d $(VENV_DIR) ]; then \
|
@if [ ! -d $(VENV_DIR) ]; then \
|
||||||
|
echo "Creating virtual environment..."; \
|
||||||
python3 -m venv $(VENV_DIR); \
|
python3 -m venv $(VENV_DIR); \
|
||||||
fi
|
fi
|
||||||
|
@echo "Source virtualenv with:"
|
||||||
|
@echo "source $(VENV_DIR)/bin/activate"
|
||||||
|
|
||||||
install: venv
|
install: venv
|
||||||
@$(PYTHON) -m pip install --upgrade pip
|
@$(PYTHON) -m pip install --upgrade pip
|
||||||
@@ -23,4 +25,3 @@ install: venv
|
|||||||
clean:
|
clean:
|
||||||
@echo "Removing virtual environment..."
|
@echo "Removing virtual environment..."
|
||||||
@rm -rf $(VENV_DIR)
|
@rm -rf $(VENV_DIR)
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,23 @@ $ pip install -e .
|
|||||||
### Run a single day
|
### Run a single day
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aoc <year> <day>
|
$ aoc run <year> <day>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run a whole year
|
### Run a whole year
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aoc <year>
|
$ aoc run <year>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Run all years
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ aoc run all
|
||||||
|
```
|
||||||
|
|
||||||
|
## Init a new day
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ aoc init <year> <day>
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# TODO replace PYTHONPATH hack with a proper solution, like making intcode an
|
|
||||||
# installed module https://stackoverflow.com/a/50194143
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from itertools import zip_longest
|
|
||||||
from pathlib import Path
|
|
||||||
from collections import defaultdict, Counter
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
|
from adventofcode.intcode import Interpreter, interpret_intcode
|
||||||
|
|
||||||
from adventofcode.intcode import interpret_intcode, Interpreter
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class State:
|
class State:
|
||||||
@@ -28,7 +25,7 @@ def grouper(n, iterable):
|
|||||||
|
|
||||||
def part1(program):
|
def part1(program):
|
||||||
interpreter = interpret_intcode(program)
|
interpreter = interpret_intcode(program)
|
||||||
game = { (x, y): tile for x, y, tile in grouper(3, interpreter.stdout) }
|
game = {(x, y): tile for x, y, tile in grouper(3, interpreter.stdout)}
|
||||||
print("Part 1: ", len([x for x in game.values() if x == 2]))
|
print("Part 1: ", len([x for x in game.values() if x == 2]))
|
||||||
|
|
||||||
|
|
||||||
@@ -39,11 +36,10 @@ def parse_map(output):
|
|||||||
if (x, y) == (-1, 0):
|
if (x, y) == (-1, 0):
|
||||||
score = tile
|
score = tile
|
||||||
else:
|
else:
|
||||||
grid[x,y] = tile
|
grid[x, y] = tile
|
||||||
paddle = next((k for k, v in grid.items() if v == 3), None)
|
paddle = next((k for k, v in grid.items() if v == 3), None)
|
||||||
ball = next((k for k, v in grid.items() if v == 4), None)
|
ball = next((k for k, v in grid.items() if v == 4), None)
|
||||||
bounds = (max(x for x, y in grid.keys()),
|
bounds = (max(x for x, y in grid.keys()), max(y for x, y in grid.keys()))
|
||||||
max(y for x, y in grid.keys()))
|
|
||||||
return grid, bounds, score, paddle, ball
|
return grid, bounds, score, paddle, ball
|
||||||
|
|
||||||
|
|
||||||
@@ -64,7 +60,7 @@ def update_state(state: State, stdout):
|
|||||||
else:
|
else:
|
||||||
# merge grid
|
# merge grid
|
||||||
for (x, y), v in grid.items():
|
for (x, y), v in grid.items():
|
||||||
state.grid[x,y] = v
|
state.grid[x, y] = v
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
@@ -77,7 +73,7 @@ def part2(program):
|
|||||||
state = update_state(state, interpreter.stdout)
|
state = update_state(state, interpreter.stdout)
|
||||||
if state.stopped:
|
if state.stopped:
|
||||||
break
|
break
|
||||||
#print_map(state)
|
# print_map(state)
|
||||||
interpreter.stdout.clear()
|
interpreter.stdout.clear()
|
||||||
paddle_x, ball_x = state.paddle_pos[0], state.ball_pos[0]
|
paddle_x, ball_x = state.paddle_pos[0], state.ball_pos[0]
|
||||||
if paddle_x < ball_x: # move right
|
if paddle_x < ball_x: # move right
|
||||||
@@ -91,16 +87,16 @@ def part2(program):
|
|||||||
|
|
||||||
def print_map(state):
|
def print_map(state):
|
||||||
clear = "\033[2J"
|
clear = "\033[2J"
|
||||||
tiles = { 0: " ", 1: "#", 2: "~", 3: "_", 4: "O" }
|
tiles = {0: " ", 1: "#", 2: "~", 3: "_", 4: "O"}
|
||||||
max_x, max_y = state.bounds
|
max_x, max_y = state.bounds
|
||||||
print(clear)
|
print(clear)
|
||||||
for y in range(max_y + 1):
|
for y in range(max_y + 1):
|
||||||
l = []
|
l = []
|
||||||
for x in range(max_x + 1):
|
for x in range(max_x + 1):
|
||||||
tile = state.grid[x,y]
|
tile = state.grid[x, y]
|
||||||
l.append(tiles[tile])
|
l.append(tiles[tile])
|
||||||
print("".join(l))
|
print("".join(l))
|
||||||
time.sleep(1/60)
|
time.sleep(1 / 60)
|
||||||
|
|
||||||
|
|
||||||
def main(inp):
|
def main(inp):
|
||||||
@@ -108,9 +104,10 @@ def main(inp):
|
|||||||
part1(program)
|
part1(program)
|
||||||
part2(program)
|
part2(program)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
infile = sys.argv[1] if len(sys.argv) > 1 else "example.txt"
|
infile = sys.argv[1] if len(sys.argv) > 1 else "example.txt"
|
||||||
with open(infile) as raw_input:
|
with open(infile) as raw_input:
|
||||||
main(raw_input)
|
main(raw_input)
|
||||||
|
|
||||||
|
|||||||
+2
-53
@@ -1,29 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from adventofcode.helper import (
|
from adventofcode.helper import init, run, run_all
|
||||||
MAX_YEAR,
|
|
||||||
MIN_YEAR,
|
|
||||||
get_auth,
|
|
||||||
get_input_file,
|
|
||||||
get_max_day,
|
|
||||||
run,
|
|
||||||
run_all,
|
|
||||||
)
|
|
||||||
|
|
||||||
TEMPLATE = """#!/usr/bin/env python3
|
|
||||||
import fileinput
|
|
||||||
|
|
||||||
|
|
||||||
def main(inp):
|
|
||||||
for l in inp:
|
|
||||||
print(l)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
lines = [x.rstrip() for x in fileinput.input()]
|
|
||||||
main(lines)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def year_or_all(value):
|
def year_or_all(value):
|
||||||
@@ -69,35 +46,7 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
def handle_init(year, day):
|
def handle_init(year, day):
|
||||||
if not MIN_YEAR <= year <= MAX_YEAR:
|
init(year, day)
|
||||||
print(f"Invalid year: {year}. Must be between {MIN_YEAR} and {MAX_YEAR}.")
|
|
||||||
return
|
|
||||||
|
|
||||||
max_day = get_max_day(year)
|
|
||||||
if not 1 <= day <= max_day:
|
|
||||||
print(f"Invalid day: {day}. Must be between 1 and {max_day}.")
|
|
||||||
return
|
|
||||||
|
|
||||||
root = Path(__file__).parent
|
|
||||||
day_dir = root / str(year) / f"day{day}"
|
|
||||||
day_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
script_path = day_dir / f"day{day}.py"
|
|
||||||
if not script_path.exists():
|
|
||||||
script_path.write_text(TEMPLATE)
|
|
||||||
print(f"Created {script_path}")
|
|
||||||
else:
|
|
||||||
print(f"{script_path} already exists")
|
|
||||||
|
|
||||||
input_path = day_dir / "input.txt"
|
|
||||||
if not input_path.exists():
|
|
||||||
try:
|
|
||||||
get_auth()
|
|
||||||
res = get_input_file(year, day)
|
|
||||||
input_path.write_bytes(res.read())
|
|
||||||
print(f"Downloaded {input_path}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Could not download input: {e}", file=__import__("sys").stderr)
|
|
||||||
|
|
||||||
|
|
||||||
def handle_run(year, day):
|
def handle_run(year, day):
|
||||||
|
|||||||
+64
-8
@@ -9,6 +9,22 @@ from pathlib import Path
|
|||||||
MIN_YEAR = 2015
|
MIN_YEAR = 2015
|
||||||
MAX_YEAR = 2025
|
MAX_YEAR = 2025
|
||||||
ROOTPATH = Path(os.path.dirname(os.path.realpath(__file__)))
|
ROOTPATH = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
TEMPLATE = """#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
|
||||||
|
|
||||||
|
def main(inp):
|
||||||
|
for l in inp:
|
||||||
|
print(l)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
lines = [x.rstrip() for x in fileinput.input()]
|
||||||
|
main(lines)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
_auth = None
|
||||||
|
|
||||||
|
|
||||||
def get_max_day(year):
|
def get_max_day(year):
|
||||||
@@ -16,7 +32,16 @@ def get_max_day(year):
|
|||||||
return 25 if year < 2025 else 12
|
return 25 if year < 2025 else 12
|
||||||
|
|
||||||
|
|
||||||
_auth = None
|
def validate_day(day, year):
|
||||||
|
if not 1 <= day <= get_max_day(year):
|
||||||
|
return f"Invalid day: {day} for year {year}. Must be between 1 and {get_max_day(year)}"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def validate_year(year):
|
||||||
|
if not MIN_YEAR <= year <= MAX_YEAR:
|
||||||
|
return f"Invalid year: {year}. Must be between {MIN_YEAR} and {MAX_YEAR}"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _load_env_file(env_path: Path) -> dict:
|
def _load_env_file(env_path: Path) -> dict:
|
||||||
@@ -69,25 +94,56 @@ def resolve_paths(year, day):
|
|||||||
return script_path, input_path
|
return script_path, input_path
|
||||||
|
|
||||||
|
|
||||||
|
def init(year, day):
|
||||||
|
if (err := validate_year(year)) is not None:
|
||||||
|
print(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (err := validate_day(day, year)) is not None:
|
||||||
|
print(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
path = ROOTPATH / Path(f"{year}/day{day}")
|
||||||
|
path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
script_path, input_path = resolve_paths(year, day)
|
||||||
|
if script_path.exists():
|
||||||
|
print(f"Script {script_path} already exists.")
|
||||||
|
else:
|
||||||
|
script_path.write_text(TEMPLATE)
|
||||||
|
print(f"Created {script_path}")
|
||||||
|
|
||||||
|
if input_path.exists():
|
||||||
|
print(f"Input {input_path} already exists.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
get_auth()
|
||||||
|
res = get_input_file(year, day)
|
||||||
|
input_path.write_bytes(res.read())
|
||||||
|
print(f"Downloaded {input_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Could not download input: {e}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
def run_all():
|
def run_all():
|
||||||
for year in range(2015, MAX_YEAR + 1):
|
for year in range(MIN_YEAR, MAX_YEAR + 1):
|
||||||
print(f"Running year {year}")
|
print(f"Running year {year}")
|
||||||
run(year, None)
|
run(year, None)
|
||||||
|
|
||||||
|
|
||||||
def run(year, day):
|
def run(year, day):
|
||||||
if not MIN_YEAR <= year <= MAX_YEAR:
|
if (err := validate_year(year)) is not None:
|
||||||
print(f"Invalid year {year}", file=sys.stderr)
|
print(err, file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if day is not None:
|
if day is not None:
|
||||||
if not 1 <= day <= get_max_day(year):
|
if (err := validate_day(day, year)) is not None:
|
||||||
print(f"Invalid day {day}", file=sys.stderr)
|
print(err, file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
script_path, input_path = resolve_paths(year, day)
|
script_path, input_path = resolve_paths(year, day)
|
||||||
if not script_path.exists():
|
if not script_path.exists():
|
||||||
print(f"Invalid day {day}", file=sys.stderr)
|
print(f"Script file {script_path} does not exist", file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
if not input_path.exists():
|
if not input_path.exists():
|
||||||
print(f"Downloading input file {input_path}")
|
print(f"Downloading input file {input_path}")
|
||||||
@@ -98,7 +154,7 @@ def run(year, day):
|
|||||||
|
|
||||||
run_day(script_path, input_path)
|
run_day(script_path, input_path)
|
||||||
else:
|
else:
|
||||||
for day in range(1, 26):
|
for day in range(1, get_max_day(year) + 1):
|
||||||
script_path, input_path = resolve_paths(year, day)
|
script_path, input_path = resolve_paths(year, day)
|
||||||
if script_path.exists():
|
if script_path.exists():
|
||||||
if not input_path.exists():
|
if not input_path.exists():
|
||||||
|
|||||||
Reference in New Issue
Block a user