Skip to content

Commit

Permalink
Boilerplate (#2)
Browse files Browse the repository at this point in the history
* Add boilerplate

* Fix typing
  • Loading branch information
tyler-hoffman authored Nov 23, 2023
1 parent e098f08 commit 1623281
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 0 deletions.
Empty file added utils/__init__.py
Empty file.
67 changes: 67 additions & 0 deletions utils/create_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import argparse
import os

import aocd

from utils.file_data import FileData
from utils.templates.parser import create_parser_stub
from utils.templates.part import create_part_stub
from utils.templates.test_part import create_part_test_stub


def touch_file(path: str) -> None:
open(path, "x")


def write_file(path: str, content: str) -> None:
with open(path, "w") as f:
f.write(content.strip() + "\n")


def create_directories_if_needed(file_data: FileData) -> None:
if not os.path.isdir(file_data.directory):
os.makedirs(file_data.directory)
touch_file(file_data.src_init_file)
write_file(file_data.input_file, aocd.get_data(year=2023, day=file_data.day))
write_file(file_data.parser_file, create_parser_stub())
write_file(file_data.prompt_file, "")

if not os.path.isdir(file_data.test_directory):
os.makedirs(file_data.test_directory)
touch_file(file_data.test_init_file)


def create_part_files(file_data: FileData) -> None:
write_file(
file_data.part_file,
create_part_stub(day_string=file_data.day_string, part=file_data.part),
)

write_file(
file_data.test_part_file,
create_part_test_stub(day_string=file_data.day_string, part=file_data.part),
)


def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Helper to bootstrap files for problems"
)
parser.add_argument("-d", "--day", type=int, help="Day to create files for")
parser.add_argument(
"-p",
"--part",
choices=["a", "b"],
help="Part to create files for",
)

return parser


if __name__ == "__main__":
args = create_parser().parse_args()

file_data = FileData(day=args.day, part=args.part)

create_directories_if_needed(file_data)
create_part_files(file_data)
72 changes: 72 additions & 0 deletions utils/file_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import dataclasses
from typing import Literal, Union

Part = Union[Literal["a"], Literal["b"]]


@dataclasses.dataclass
class FileData(object):
"""Dataclass to handle any directory/file names
to be used when bootstrapping files
"""

src = "aoc_2023"
tests = "tests"

day: int
part: Part

@property
def day_string(self) -> str:
return f"{self.day:02d}"

@property
def part_module(self) -> str:
return f"{self.src}.day_{self.day_string}.{self.part}"

@property
def directory(self) -> str:
return f"{self.src}/day_{self.day_string}"

@property
def test_directory(self) -> str:
return f"{self.tests}/test_day_{self.day_string}"

@property
def input_file(self) -> str:
return f"{self.directory}/input.txt"

@property
def part_file(self) -> str:
return f"{self.directory}/{self.part}.py"

@property
def parser_file(self) -> str:
return f"{self.directory}/parser.py"

@property
def prompt_file(self) -> str:
return f"{self.directory}/from_prompt.py"

@property
def solver_file(self) -> str:
return f"{self.directory}/solver.py"

@property
def test_part_file(self) -> str:
return f"{self.test_directory}/test_{self.part}.py"

@property
def test_data_file(self) -> str:
return f"{self.test_directory}/sample_data.py"

@property
def src_init_file(self) -> str:
return self._init_file(self.directory)

@property
def test_init_file(self) -> str:
return self._init_file(self.test_directory)

def _init_file(self, directory: str) -> str:
return f"{directory}/__init__.py"
37 changes: 37 additions & 0 deletions utils/submit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import argparse
import subprocess

import aocd

from utils.file_data import FileData, Part


def submit(day: int, part: Part) -> None:
data_file = FileData(day=day, part=part)
completed_process = subprocess.run(
["python", "-m", data_file.part_module], capture_output=True
)
answer = completed_process.stdout.decode("utf-8").strip()

print(f"Submitting answer: {answer}")
assert not isinstance(aocd.submit, str)
aocd.submit(day=day, part=part, year=2023, answer=answer)


def create_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Helper to submit problems")
parser.add_argument("-d", "--day", type=int, help="Day to create files for")
parser.add_argument(
"-p",
"--part",
choices=["a", "b"],
help="Part to create files for",
)

return parser


if __name__ == "__main__":
args = create_parser().parse_args()

submit(day=args.day, part=args.part)
Empty file added utils/templates/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions utils/templates/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def create_parser_stub() -> str:
return _PARSER_TEMPLATE


_PARSER_TEMPLATE = """
class Parser:
@staticmethod
def parse(input: str) -> str:
return input.strip()
"""
39 changes: 39 additions & 0 deletions utils/templates/part.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
def create_part_stub(day_string: str, part: str) -> str:
src = "aoc_2023"
return _PART_TEMPLATE.format(
day_string=day_string,
part_upper=part.upper(),
src=src,
)


_PART_TEMPLATE = """
from dataclasses import dataclass
from {src}.day_{day_string}.parser import Parser
@dataclass
class Day{day_string}Part{part_upper}Solver:
input: str
@property
def solution(self) -> int:
return -1
def solve(input: str) -> int:
data = Parser.parse(input)
solver = Day{day_string}Part{part_upper}Solver(data)
return solver.solution
def get_solution() -> int:
with open("aoc_2023/day_{day_string}/input.txt", "r") as f:
input = f.read()
return solve(input)
if __name__ == "__main__":
print(get_solution())
"""
30 changes: 30 additions & 0 deletions utils/templates/test_part.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
def create_part_test_stub(day_string: str, part: str) -> str:
src = "aoc_2023"
return _TEST_PART_TEMPLATE.format(
day_string=day_string,
part=part,
part_upper=part.upper(),
src=src,
)


_TEST_PART_TEMPLATE = """
import pytest
from {src}.day_{day_string}.{part} import get_solution, solve
@pytest.mark.parametrize(
"input, expected",
[
("INPUT", -1),
],
)
def test_solve(input: str, expected: int):
assert solve(input) == expected
@pytest.mark.skip
def test_my_solution():
assert get_solution() == "NOT THIS"
"""

0 comments on commit 1623281

Please sign in to comment.