11import importlib
22import shutil
3+ import typing
34from datetime import datetime
45from pathlib import Path
56from typing import Annotated , Literal
@@ -26,6 +27,9 @@ def get_current_aoc_year():
2627 return now .year if now .month == 12 else now .year - 1
2728
2829
30+ current_aoc_year = get_current_aoc_year ()
31+
32+
2933def echo (text , fg = typer .colors .GREEN ):
3034 typer .echo (
3135 typer .style (
@@ -35,16 +39,29 @@ def echo(text, fg=typer.colors.GREEN):
3539 )
3640
3741
38- def import_challenge_module (day : int ):
39- module_name = f"aoc.day_{ day :02} "
42+ year_option = Annotated [
43+ int ,
44+ typer .Option (
45+ "-y" ,
46+ "--year" ,
47+ help = "Year for which to get the puzzle data" ,
48+ ),
49+ ]
50+
51+
52+ def get_challenge_module_name (year : int , day : int ) -> str :
53+ return f"aoc_solutions.{ year } .day_{ day :02} "
54+
55+
56+ def import_challenge_module (year , day : int ):
4057 try :
41- module = importlib .import_module (module_name )
58+ module = importlib .import_module (get_challenge_module_name ( year , day ) )
4259 except ModuleNotFoundError as e :
4360 echo (
4461 f'Could not import "{ e .name } "' ,
4562 fg = typer .colors .RED ,
4663 )
47- if e .name == module_name :
64+ if e .name == get_challenge_module_name :
4865 echo (
4966 f"You have not solved day { day } yet. Start it using 'new-day' command" ,
5067 fg = typer .colors .RED ,
@@ -55,12 +72,20 @@ def import_challenge_module(day: int):
5572 return module
5673
5774
58- def run_challenge (day : int , test_data : bool , input_path : Path | None = None ):
59- module = import_challenge_module (day )
75+ def run_challenge (
76+ year : int ,
77+ day : int ,
78+ test_data : bool ,
79+ data_dir : Path | None ,
80+ input_path : Path | None = None ,
81+ ):
82+ module = import_challenge_module (year , day )
6083 input_provider = (
61- SingleFileInputProvider (day = day , input_path = input_path )
84+ SingleFileInputProvider (year = year , day = day , input_path = input_path )
6285 if input_path
63- else SmartFileInputProvider (day = day , use_test_data = test_data )
86+ else SmartFileInputProvider (
87+ year = year , day = day , data_dir = data_dir , use_test_data = test_data
88+ )
6489 )
6590 if test_data :
6691 module .Challenge (input_provider = input_provider ).run ()
@@ -100,20 +125,31 @@ def write_input_data(puzzle, real_input_data):
100125@app .command ()
101126def run (
102127 day : Annotated [int , typer .Argument (..., help = "Day of the challenge to run." )],
128+ year : year_option = current_aoc_year ,
129+ data_directory : Annotated [
130+ Path ,
131+ typer .Option (
132+ help = "Path to a directory with data. Will be used if you won't provide"
133+ " --file/-f option"
134+ ),
135+ ] = Path ("data" ),
103136 file : Annotated [
104- Path | None , typer .Option (..., "--file" , "-f" , help = "File to run." )
137+ typing . Optional [ Path ] , typer .Option (..., "--file" , "-f" , help = "File to run." ) # noqa
105138 ] = None ,
106139 test_data : bool = typer .Option (
107140 False , "--test-data" , "-t" , help = "Run challenge also for test data."
108141 ),
109142):
110143 """Run the challenge."""
111- run_challenge (day , test_data , file )
144+ run_challenge (year , day , test_data , data_directory , file )
112145
113146
114147@app .command ()
115148def verify (
116- day : int | None = typer .Argument (None , help = "Day of the challenge to verify." ),
149+ day : typing .Optional [int ] = typer .Argument ( # noqa: UP007
150+ None , help = "Day of the challenge to verify."
151+ ),
152+ year : year_option = current_aoc_year ,
117153 part_one_only : bool = typer .Option (
118154 False , "--part-one" , "-1" , help = "Verify only part one of the solution."
119155 ),
@@ -135,7 +171,8 @@ def verify(
135171 if sum ([part_one_only , part_two_only ]) == 1 :
136172 pytest_args .extend (["-k" , "part_1" if part_one_only else "part_2" ])
137173 if day is not None :
138- module = import_challenge_module (day )
174+ module = import_challenge_module (year , day )
175+ print (module .__file__ )
139176 if not module .__file__ :
140177 typer .echo (
141178 typer .style (
@@ -192,7 +229,7 @@ def submit(
192229 ),
193230):
194231 validated_part = _full_validate (part )
195- module = import_challenge_module (day )
232+ module = import_challenge_module (year , day )
196233 if validated_part == "a" :
197234 solution = module .Challenge (use_test_data = False ).part_1 ()
198235 else :
@@ -203,14 +240,7 @@ def submit(
203240@app .command ()
204241def new_day (
205242 day : Annotated [int , typer .Argument (help = "Day for which to create a directory." )],
206- year : Annotated [
207- int ,
208- typer .Option (
209- "-y" ,
210- "--year" ,
211- help = "Year for which to get the puzzle data" ,
212- ),
213- ] = get_current_aoc_year (),
243+ year : year_option = current_aoc_year ,
214244 directory : Annotated [
215245 Path ,
216246 typer .Option (
@@ -219,7 +249,7 @@ def new_day(
219249 "--directory" ,
220250 help = "Path to a directory with challenges" ,
221251 ),
222- ] = Path ("src/aoc " ),
252+ ] = Path (". " ),
223253 data_directory : Annotated [
224254 Path ,
225255 typer .Option (help = "Path to a directory with data." ),
@@ -245,7 +275,7 @@ def new_day(
245275 if day < 1 or day > 25 :
246276 typer .echo (typer .style ("Day must be between 1 and 25." , fg = typer .colors .RED ))
247277 raise typer .Exit (1 )
248- destination = directory .joinpath (f"day_{ day :02} " )
278+ destination = directory .joinpath (f"aoc_solutions/ { year } / day_{ day :02} " )
249279 if destination .exists () and not force :
250280 typer .echo (
251281 typer .style (
@@ -258,9 +288,9 @@ def new_day(
258288 typer .echo (
259289 typer .style (f"Created solution directory for day { day } ." , fg = typer .colors .GREEN )
260290 )
261- data_directory .mkdir (exist_ok = True )
291+ data_directory .joinpath ( str ( year )). mkdir (parents = True , exist_ok = True )
262292 if (
263- real_input_data := data_directory .joinpath (f"{ day :02} _input.txt" )
293+ real_input_data := data_directory .joinpath (f"{ year } / { day :02} _input.txt" )
264294 ).exists () and real_input_data .stat ().st_size :
265295 typer .echo (
266296 typer .style (
@@ -275,7 +305,9 @@ def new_day(
275305 typer .style (f"Created input data for day { day } ." , fg = typer .colors .GREEN )
276306 )
277307 if (
278- test_input_data := data_directory .joinpath (Path (f"{ day :02} _test_input.txt" ))
308+ test_input_data := data_directory .joinpath (
309+ Path (f"{ year } /{ day :02} _test_input.txt" )
310+ )
279311 ).exists () and test_input_data .stat ().st_size :
280312 typer .echo (
281313 typer .style (
0 commit comments