mirror of
https://github.com/plasmaofthedawn/adventofcode.git
synced 2025-08-24 01:52:04 -05:00
initial commit
This commit is contained in:
175
run.py
Normal file
175
run.py
Normal file
@@ -0,0 +1,175 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Optional
|
||||
import shlex
|
||||
import re
|
||||
import os
|
||||
import argparse
|
||||
|
||||
class Language:
|
||||
def __init__(self, name: str, extension: str, run, build_extension: Optional[str] = None):
|
||||
|
||||
self.name = name
|
||||
self.extension = extension
|
||||
self.run = run
|
||||
self.build_extension = build_extension
|
||||
|
||||
class Problem:
|
||||
def __init__(self, language: Language, year: int, day: int, part: int, resource_location = None):
|
||||
self.language = language
|
||||
self.year = year
|
||||
self.day = day
|
||||
self.part = part
|
||||
|
||||
self.source_location = str(Path("src") / self.language.name / str(self.year) / f"day{self.day}" / f"part{self.part}.{self.language.extension}")
|
||||
|
||||
if resource_location:
|
||||
self.resource_location = resource_location
|
||||
else:
|
||||
self.resource_location = str(Path("resources") / str(self.year) / f"day{self.day}.txt")
|
||||
|
||||
self.build_location = str(Path("build") / f"{self.language.name}{self.year}day{self.day}part{self.part}") + (f".{self.language.build_extension}" if self.language.build_extension else "")
|
||||
|
||||
self.resource_build_location = str(Path("build") / f"{self.language.name}{self.year}day{self.day}part{self.part}input")
|
||||
|
||||
|
||||
def run(self, flags=None):
|
||||
if flags is None:
|
||||
flags = []
|
||||
|
||||
try:
|
||||
self.language.run(self, flags=flags)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
def print_command(command: str | list):
|
||||
print(command if isinstance(command, str) else shlex.join([str(x) for x in command]))
|
||||
|
||||
def run_command(command: str | list[str], **kwargs):
|
||||
print_command(command)
|
||||
p = subprocess.run(command, **kwargs)
|
||||
if p.returncode != 0:
|
||||
print("process returned with error code", p.returncode)
|
||||
raise RuntimeError()
|
||||
|
||||
def run_compile_command(command: str | list[str], **kwargs):
|
||||
run_command(command, stdout=subprocess.DEVNULL, stderr=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def run_run_command(command: str | list[str], **kwargs):
|
||||
run_command(command, stdout=sys.stdout, stderr=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def generate_commands_pladcl(problem: Problem, flags: Optional[list[str]]=None):
|
||||
|
||||
preprocess_location = "utilities/dc/preprocess.py"
|
||||
|
||||
run_compile_command(["pladclc", problem.source_location, "-o", problem.build_location] + (flags if flags else []))
|
||||
run_compile_command(["python3", preprocess_location, problem.resource_location, "-o", problem.resource_build_location])
|
||||
run_run_command(" ".join(["cat", problem.resource_build_location, "|", "dc", problem.build_location]), shell=True)
|
||||
|
||||
|
||||
def generate_commands_pascal(problem: Problem, flags: Optional[list[str]]=None):
|
||||
|
||||
run_compile_command(["fpc", problem.source_location, "-o" + problem.build_location] + (flags if flags else []))
|
||||
run_run_command([problem.build_location])
|
||||
|
||||
def generate_commands_z80(problem: Problem, flags:Optional[list[str]]=None):
|
||||
simulator_location = "utilities/z80/z80sim"
|
||||
preamble_location = "utilities/z80/preamble"
|
||||
|
||||
run_compile_command(["zasm", problem.source_location, "-o", problem.build_location] + (flags if flags else []))
|
||||
run_compile_command(f"cat {preamble_location} {problem.build_location} > {problem.build_location + "0"}", shell=True)
|
||||
|
||||
run_run_command(f"echo q | {simulator_location} -x{problem.build_location}0", shell=True)
|
||||
|
||||
|
||||
languages = {
|
||||
"pladcl": Language("pladcl", "pdl", generate_commands_pladcl, build_extension="dc"),
|
||||
"pascal": Language("pascal", "pas", generate_commands_pascal),
|
||||
"python": Language("python", "py", lambda problem, flags: run_run_command(["python3", problem.source_location] + (flags if flags else []))),
|
||||
"z80": Language("z80", "z80", generate_commands_z80, build_extension="bin")
|
||||
}
|
||||
|
||||
|
||||
def parse_problem(problem: str):
|
||||
|
||||
pattern = r"^([a-zA-Z0-9]+)(\d{4})d(?:ay)?(\d+)p(?:art)?(\d+)$"
|
||||
|
||||
if not (match := re.match(pattern, problem)):
|
||||
raise ValueError(f"unable to understand problem \"{problem}\"")
|
||||
|
||||
language, year, day, part = match.groups()
|
||||
|
||||
if not language in languages:
|
||||
raise ValueError(f"unknown language \"{language}\"")
|
||||
|
||||
language = languages[language]
|
||||
year = int(year)
|
||||
day = int(day)
|
||||
part = int(part)
|
||||
|
||||
p = Problem(language, year, day, part)
|
||||
|
||||
return p
|
||||
|
||||
USAGE = """
|
||||
|
||||
for example, to run pladcl year 2024 day 3 part 1 with debug flags
|
||||
python3 run.py pladcl2024day3part1 -d
|
||||
|
||||
extra flags are passed as is to the compiler"""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="run.py",
|
||||
epilog=USAGE,
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
exit_on_error=False,
|
||||
)
|
||||
|
||||
parser.add_argument("problem", type=str,
|
||||
help="program to run [formatted as <language><year>day<day>part<part>]")
|
||||
parser.add_argument("--resource-location", type=str,
|
||||
help="override the default resource file (which is resources/<year>/day<day>.txt)")
|
||||
|
||||
|
||||
def fail():
|
||||
parser.print_usage()
|
||||
print()
|
||||
|
||||
print("\n".join(parser.format_help().splitlines()[2:]))
|
||||
quit(2)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
try:
|
||||
args, extra_flags = parser.parse_known_args(sys.argv[1:])
|
||||
|
||||
problem = parse_problem(args.problem)
|
||||
|
||||
if args.resource_location:
|
||||
problem.resource_location = args.resource_location
|
||||
|
||||
if not os.path.exists(loc := problem.source_location):
|
||||
raise ValueError(f"couldn't find the source file\nexpected it to be {loc}")
|
||||
|
||||
if not os.path.exists(loc := problem.resource_location):
|
||||
raise ValueError(f"couldn't find the resource file\nexpected it to be {loc}")
|
||||
|
||||
|
||||
problem.run(extra_flags)
|
||||
|
||||
except (argparse.ArgumentError, ValueError) as e:
|
||||
print(e)
|
||||
print()
|
||||
fail()
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user