prep for 2021; implemented 2017d1 as reference
This commit is contained in:
parent
43e258313a
commit
2b8a69c24b
4
aoclib/__init__.py
Normal file
4
aoclib/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from .day import *
|
||||||
|
from .tools import *
|
||||||
|
from .output import *
|
||||||
|
from .performance import *
|
||||||
112
aoclib/day.py
Normal file
112
aoclib/day.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import os
|
||||||
|
from typing import List, Any
|
||||||
|
from .tools import splitLine
|
||||||
|
from .output import printSolution
|
||||||
|
|
||||||
|
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
INPUTS_PATH = os.path.join(BASE_PATH, 'inputs')
|
||||||
|
|
||||||
|
|
||||||
|
class AOCDay:
|
||||||
|
day: int
|
||||||
|
input: List # our input is always a list of str/lines
|
||||||
|
test_solutions_p1: List
|
||||||
|
test_solutions_p2: List
|
||||||
|
|
||||||
|
def __init__(self, day):
|
||||||
|
self.day = day
|
||||||
|
with open(os.path.join(INPUTS_PATH, "input%02d" % day)) as f:
|
||||||
|
self.input = f.read().splitlines()
|
||||||
|
|
||||||
|
def part1(self) -> Any:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def part2(self) -> Any:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_part1(self) -> bool:
|
||||||
|
live_input = self.input.copy()
|
||||||
|
for case, solution in enumerate(self.test_solutions_p1):
|
||||||
|
with open(os.path.join(INPUTS_PATH, "test_input%02d_1_%d" % (self.day, case))) as f:
|
||||||
|
self.input = f.read().splitlines()
|
||||||
|
|
||||||
|
check = self.part1()
|
||||||
|
printSolution(self.day, 1, check, solution, case)
|
||||||
|
if check != solution:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.input = live_input
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_part2(self) -> bool:
|
||||||
|
live_input = self.input.copy()
|
||||||
|
for case, solution in enumerate(self.test_solutions_p2):
|
||||||
|
with open(os.path.join(INPUTS_PATH, "test_input%02d_2_%d" % (self.day, case))) as f:
|
||||||
|
self.input = f.read().splitlines()
|
||||||
|
|
||||||
|
check = self.part2()
|
||||||
|
printSolution(self.day, 2, check, solution, case)
|
||||||
|
if check != solution:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.input = live_input
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getInputListAsType(self, return_type):
|
||||||
|
"""
|
||||||
|
get input as list casted to return_type, each line representing one list entry
|
||||||
|
"""
|
||||||
|
return [return_type(i) for i in self.input]
|
||||||
|
|
||||||
|
def getMultiLineInputAsArray(self, return_type=None, join_char=None):
|
||||||
|
"""
|
||||||
|
get input for day x as 2d array, split by empty lines
|
||||||
|
"""
|
||||||
|
lines = self.input
|
||||||
|
lines.append('')
|
||||||
|
|
||||||
|
return_array = []
|
||||||
|
line_array = []
|
||||||
|
for line in lines:
|
||||||
|
if not line:
|
||||||
|
if join_char:
|
||||||
|
return_array.append(join_char.join(line_array))
|
||||||
|
else:
|
||||||
|
return_array.append(line_array)
|
||||||
|
line_array = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
if return_type:
|
||||||
|
line_array.append(return_type(line))
|
||||||
|
else:
|
||||||
|
line_array.append(line)
|
||||||
|
|
||||||
|
return return_array
|
||||||
|
|
||||||
|
def getInputAs2DArray(self, return_type=None):
|
||||||
|
"""
|
||||||
|
get input for day x as 2d-array (a[line][pos])
|
||||||
|
"""
|
||||||
|
if return_type is None:
|
||||||
|
return self.input # strings already act like a list
|
||||||
|
else:
|
||||||
|
return_array = []
|
||||||
|
for line in self.input:
|
||||||
|
return_array.append([return_type(i) for i in line])
|
||||||
|
|
||||||
|
return return_array
|
||||||
|
|
||||||
|
def getInputAsArraySplit(self, split_char=',', return_type=None):
|
||||||
|
"""
|
||||||
|
get input for day x with the lines split by split_char
|
||||||
|
if input has only one line, returns a 1d array with the values
|
||||||
|
if input has multiple lines, returns a 2d array (a[line][values])
|
||||||
|
"""
|
||||||
|
if len(self.input) == 1:
|
||||||
|
return splitLine(line=self.input[0], split_char=split_char, return_type=return_type)
|
||||||
|
else:
|
||||||
|
return_array = []
|
||||||
|
for line in self.input:
|
||||||
|
return_array.append(splitLine(line=line, split_char=split_char, return_type=return_type))
|
||||||
|
|
||||||
|
return return_array
|
||||||
8
aoclib/output.py
Normal file
8
aoclib/output.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
def printSolution(day, part, solution, test=None, test_case=0):
|
||||||
|
if test is not None:
|
||||||
|
print(
|
||||||
|
"(TEST case%d/day%d/part%d) -- got '%s' -- expected '%s' -> %s"
|
||||||
|
% (test_case, day, part, solution, test, "correct" if test == solution else "WRONG")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print("Solution to day %s, part %s: %s" % (day, part, solution))
|
||||||
8
aoclib/performance.py
Normal file
8
aoclib/performance.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
def print_execution_time(day, part, avg_time):
|
||||||
|
units = ['s', 'ms', 'μs', 'ns']
|
||||||
|
unit = 0
|
||||||
|
while avg_time < 1:
|
||||||
|
avg_time *= 1000
|
||||||
|
unit += 1
|
||||||
|
|
||||||
|
print("Average execution time for day %s part %s: %1.2f%s" % (day, part, avg_time, units[unit]))
|
||||||
8
aoclib/tools.py
Normal file
8
aoclib/tools.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
def splitLine(line, split_char=',', return_type=None):
|
||||||
|
if split_char:
|
||||||
|
line = line.split(split_char)
|
||||||
|
|
||||||
|
if return_type is None:
|
||||||
|
return line
|
||||||
|
else:
|
||||||
|
return [return_type(i) for i in line]
|
||||||
28
day01.py
Normal file
28
day01.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from aoclib import AOCDay
|
||||||
|
|
||||||
|
|
||||||
|
class Day(AOCDay):
|
||||||
|
test_solutions_p1 = [3, 4, 0, 9]
|
||||||
|
test_solutions_p2 = [6, 0, 4, 12, 4]
|
||||||
|
|
||||||
|
def part1(self):
|
||||||
|
res = 0
|
||||||
|
number = self.input[0]
|
||||||
|
if number[0] == number[-1]:
|
||||||
|
res += int(number[0])
|
||||||
|
|
||||||
|
for i in range(len(number) - 1):
|
||||||
|
if number[i] == number[i+1]:
|
||||||
|
res += int(number[i])
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def part2(self):
|
||||||
|
res = 0
|
||||||
|
number = self.input[0]
|
||||||
|
half = len(number) // 2
|
||||||
|
for i in range(half):
|
||||||
|
if number[i] == number[i+half]:
|
||||||
|
res += int(number[i]) * 2
|
||||||
|
|
||||||
|
return res
|
||||||
1
inputs/input01
Normal file
1
inputs/input01
Normal file
@ -0,0 +1 @@
|
|||||||
|
516299281491169512719425276194596424291268712697155863651846937925928456958813624428156218468331423858422613471962165756423837756856519754524985759763747559711257977361228357678293572698839754444752898835313399815748562519958329927911861654784216355489319995566297499836295985943899373615223375271231128914745273184498915241488393761676799914385265459983923743146555465177886491979962465918888396664233693243983969412682561799628789569294374554575677368219724142536789649121758582991345537639888858113763738518511184439854223386868764189133964543721941169786274781775658991329331759679943342217578532643519615296424396487669451453728113114748217177826874953466435436129165295379157226345786756899935747336785161745487933721527239394118721517195849186676814232887413175587327214144876898248571248517121796766248817366614333915154796983612174281237846165129114988453188844745119798643314857871527757831265298846833327863781341559381238458322786192379487455671563757123534253463563421716138641611915686247343417126655317378639314168461345613427262786624689498485599942336813995725145169355942616672812792174556866436158375938988738721253664772584577384558696477546232189312287262439452141564522329987139692281984783513691857538335537553448919819545332125483128878925492334361562192621672993868479566688564752226111784486619789588318171745995253645886833872665447241245329935643883892447524286642296955354249478815116517315832179925494818748478164317669471654464867111924676961162162841232473474394739793968624974397916495667233337397241933765513777241916359166994384923869741468174653353541147616645393917694581811193977311981752554551499629219873391493426883886536219455848354426461562995284162323961773644581815633779762634745339565196798724847722781666948626231631632144371873154872575615636322965353254642186897127423352618879431499138418872356116624818733232445649188793318829748789349813295218673497291134164395739665667255443366383299669973689528188264386373591424149784473698487315316676637165317972648916116755224598519934598889627918883283534261513179931798591959489372165295
|
||||||
1
inputs/test_input01_1_0
Normal file
1
inputs/test_input01_1_0
Normal file
@ -0,0 +1 @@
|
|||||||
|
1122
|
||||||
1
inputs/test_input01_1_1
Normal file
1
inputs/test_input01_1_1
Normal file
@ -0,0 +1 @@
|
|||||||
|
1111
|
||||||
1
inputs/test_input01_1_2
Normal file
1
inputs/test_input01_1_2
Normal file
@ -0,0 +1 @@
|
|||||||
|
1234
|
||||||
1
inputs/test_input01_1_3
Normal file
1
inputs/test_input01_1_3
Normal file
@ -0,0 +1 @@
|
|||||||
|
91212129
|
||||||
1
inputs/test_input01_2_0
Normal file
1
inputs/test_input01_2_0
Normal file
@ -0,0 +1 @@
|
|||||||
|
1212
|
||||||
1
inputs/test_input01_2_1
Normal file
1
inputs/test_input01_2_1
Normal file
@ -0,0 +1 @@
|
|||||||
|
1221
|
||||||
1
inputs/test_input01_2_2
Normal file
1
inputs/test_input01_2_2
Normal file
@ -0,0 +1 @@
|
|||||||
|
123425
|
||||||
1
inputs/test_input01_2_3
Normal file
1
inputs/test_input01_2_3
Normal file
@ -0,0 +1 @@
|
|||||||
|
123123
|
||||||
1
inputs/test_input01_2_4
Normal file
1
inputs/test_input01_2_4
Normal file
@ -0,0 +1 @@
|
|||||||
|
12131415
|
||||||
83
main.py
83
main.py
@ -1,16 +1,79 @@
|
|||||||
# This is a sample Python script.
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Press Umschalt+F10 to execute it or replace it with your code.
|
import aoclib
|
||||||
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
|
import argparse
|
||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import timeit
|
||||||
|
|
||||||
|
TIMEIT_NUMBER = 50
|
||||||
|
|
||||||
def print_hi(name):
|
argument_parser = argparse.ArgumentParser()
|
||||||
# Use a breakpoint in the code line below to debug your script.
|
argument_parser.add_argument("-d", "--day", help="specify day to process; leave empty for ALL days", type=int)
|
||||||
print(f'Hi, {name}') # Press Strg+F8 to toggle the breakpoint.
|
argument_parser.add_argument("-t", "--test", help="run test cases", action="store_true", default=False)
|
||||||
|
argument_parser.add_argument("-p", "--part", help="run only part x", choices=[1, 2], type=int)
|
||||||
|
argument_parser.add_argument("--timeit", help="measure execution time", action="store_true", default=False)
|
||||||
|
argument_parser.add_argument(
|
||||||
|
"--timeit-number",
|
||||||
|
help="build average time over this many executions",
|
||||||
|
type=int,
|
||||||
|
default=TIMEIT_NUMBER
|
||||||
|
)
|
||||||
|
flags = argument_parser.parse_args()
|
||||||
|
|
||||||
|
import_day = ""
|
||||||
|
if flags.day:
|
||||||
|
import_day = "%02d" % flags.day
|
||||||
|
|
||||||
# Press the green button in the gutter to run the script.
|
imported = []
|
||||||
if __name__ == '__main__':
|
for _, _, files in os.walk(aoclib.BASE_PATH):
|
||||||
print_hi('PyCharm')
|
for f in files:
|
||||||
|
if f.startswith('day' + import_day) and f.endswith('.py'):
|
||||||
|
lib_name = f[:-3]
|
||||||
|
globals()[lib_name] = importlib.import_module(lib_name)
|
||||||
|
imported.append(lib_name)
|
||||||
|
|
||||||
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
|
break
|
||||||
|
|
||||||
|
for lib in sorted(imported):
|
||||||
|
day = int(lib[-2:])
|
||||||
|
day_class = getattr(globals()[lib], "Day")(day)
|
||||||
|
if not flags.test:
|
||||||
|
if not flags.part or flags.part == 1:
|
||||||
|
if not day_class.test_part1():
|
||||||
|
print("TEST FAILED! Aborting.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not flags.part or flags.part == 2:
|
||||||
|
if not day_class.test_part2():
|
||||||
|
print("TEST FAILED! Aborting.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not flags.part or flags.part == 1:
|
||||||
|
if not flags.timeit:
|
||||||
|
if flags.test:
|
||||||
|
day_class.test_part1()
|
||||||
|
else:
|
||||||
|
aoclib.printSolution(day, 1, day_class.part1())
|
||||||
|
else:
|
||||||
|
exec_time = timeit.timeit(
|
||||||
|
'day_class.part1()',
|
||||||
|
globals=globals(),
|
||||||
|
number=flags.timeit_number
|
||||||
|
) / flags.timeit_number
|
||||||
|
aoclib.print_execution_time(day, 1, exec_time)
|
||||||
|
|
||||||
|
if not flags.part or flags.part == 2:
|
||||||
|
if not flags.timeit:
|
||||||
|
if flags.test:
|
||||||
|
day_class.test_part2()
|
||||||
|
else:
|
||||||
|
aoclib.printSolution(day, 2, day_class.part2())
|
||||||
|
else:
|
||||||
|
exec_time = timeit.timeit(
|
||||||
|
'day_class.part2()',
|
||||||
|
globals=globals(),
|
||||||
|
number=flags.timeit_number
|
||||||
|
) / flags.timeit_number
|
||||||
|
aoclib.print_execution_time(day, 2, exec_time)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user