readme
This commit is contained in:
165
day06/part1.py
Normal file
165
day06/part1.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import deque
|
||||
import os.path
|
||||
import pathlib as pl
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import typing as t
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
import pytest
|
||||
|
||||
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
|
||||
|
||||
|
||||
def compute(s: str):
|
||||
four_window = deque(maxlen=4)
|
||||
for idx, char in enumerate(s):
|
||||
if char in four_window:
|
||||
four_window.clear()
|
||||
elif len(four_window) == 3:
|
||||
return idx
|
||||
four_window.append(char)
|
||||
raise Exception('no answer')
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
('input_s', 'expected'),
|
||||
(("mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7))
|
||||
)
|
||||
|
||||
#### HELPERS
|
||||
|
||||
def test(input_s: str, expected: int) -> None:
|
||||
assert compute(input_s) == expected
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print(compute(pl.Path("input.txt").read_text()))
|
||||
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def _get_cookie_headers() -> dict[str, str]:
|
||||
with open(os.path.join(HERE, '../.env')) as f:
|
||||
contents = f.read().strip()
|
||||
return {'Cookie': contents}
|
||||
|
||||
|
||||
def get_input(year: int, day: int) -> str:
|
||||
url = f'https://adventofcode.com/{year}/day/{day}/input'
|
||||
req = urllib.request.Request(url, headers=_get_cookie_headers())
|
||||
return urllib.request.urlopen(req).read().decode()
|
||||
|
||||
|
||||
def get_year_day() -> tuple[int, int]:
|
||||
cwd = os.getcwd() # type: ignore
|
||||
day_s = os.path.basename(cwd)
|
||||
year_s = os.path.basename(os.path.dirname(cwd))
|
||||
|
||||
if not day_s.startswith('day') or not year_s.startswith('20'):
|
||||
raise AssertionError(f'unexpected working dir: {cwd}')
|
||||
|
||||
return int(year_s), int(day_s[len('day'):])
|
||||
|
||||
|
||||
def download_input() -> int:
|
||||
year, day = get_year_day()
|
||||
|
||||
for _ in range(5):
|
||||
try:
|
||||
s = get_input(year, day)
|
||||
except urllib.error.URLError as e:
|
||||
print(f'zzz: not ready yet: {e}')
|
||||
time.sleep(1)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
raise SystemExit('timed out after attempting many times')
|
||||
|
||||
with open('input.txt', 'w') as f:
|
||||
f.write(s)
|
||||
inputs = s
|
||||
if '\n' in inputs.strip():
|
||||
print('splitting')
|
||||
inputs = inputs.split('\n')
|
||||
print(inputs[0])
|
||||
if inputs[0].isnumeric():
|
||||
print('ints')
|
||||
inputs = list(map(int, inputs))
|
||||
inputs = str(inputs).replace("'", '"')
|
||||
|
||||
lines = s.splitlines()
|
||||
if len(lines) > 10:
|
||||
for line in lines[:10]:
|
||||
print(line)
|
||||
print('...')
|
||||
else:
|
||||
print(lines[0][:80])
|
||||
print('...')
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
TOO_QUICK = re.compile('You gave an answer too recently.*to wait.')
|
||||
WRONG = re.compile(r"That's not the right answer.*?\.")
|
||||
RIGHT = "That's the right answer!"
|
||||
ALREADY_DONE = re.compile(r"You don't seem to be solving.*\?")
|
||||
|
||||
|
||||
def _post_answer(year: int, day: int, part: int, answer: int) -> str:
|
||||
params = urllib.parse.urlencode({'level': part, 'answer': answer})
|
||||
req = urllib.request.Request(
|
||||
f'https://adventofcode.com/{year}/day/{day}/answer',
|
||||
method='POST',
|
||||
data=params.encode(),
|
||||
headers=_get_cookie_headers(),
|
||||
)
|
||||
resp = urllib.request.urlopen(req)
|
||||
|
||||
return resp.read().decode()
|
||||
|
||||
|
||||
def submit_solution() -> int:
|
||||
year, day = get_year_day()
|
||||
part = get_part()
|
||||
answer = compute(pl.Path("input.txt").read_text())
|
||||
|
||||
print(f'answer: {answer}')
|
||||
|
||||
contents = _post_answer(year=year, day=day, part=part, answer=answer)
|
||||
|
||||
for error_regex in (WRONG, TOO_QUICK, ALREADY_DONE):
|
||||
error_match = error_regex.search(contents)
|
||||
if error_match:
|
||||
print(f'\033[41m{error_match[0]}\033[m')
|
||||
return 1
|
||||
|
||||
if RIGHT in contents:
|
||||
print(RIGHT)
|
||||
return 0
|
||||
else:
|
||||
# unexpected output?
|
||||
print(contents)
|
||||
return 1
|
||||
|
||||
|
||||
def get_part() -> t.Literal[1, 2]:
|
||||
if __file__.endswith("2.py"):
|
||||
return 2
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[1] == "get_input":
|
||||
print('getting input data...')
|
||||
download_input()
|
||||
elif sys.argv[1] == "submit":
|
||||
submit_solution()
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user