scripts: rewrite live script

This commit is contained in:
Felix Bargfeldt 2024-12-10 21:28:56 +01:00
parent 93c80d9f0c
commit 5ee5268431
Signed by: Defelo
GPG key ID: 2A05272471204DD3
5 changed files with 151 additions and 75 deletions

View file

@ -30,45 +30,6 @@ from heapq import heapify, heappop, heappush
from pathlib import Path
import numpy as np
import pyperclip
import z3
YEAR: int | None = None
DAY: int | None = None
def read_input(year: int, day: int, example: int | None = None) -> str:
global YEAR, DAY
if example is None:
YEAR = year
DAY = day
if example is None:
f = Path(__file__).parent / f"../../.cache/{year}/{day}"
else:
f = Path(__file__).parent / f"../../examples/{year}/{day}/{example}"
return f.read_text()
def ans(answer):
print(answer)
pyperclip.copy(str(answer))
if YEAR is None or DAY is None:
print("\n(cannot submit solution of example)")
return
submit_part = input("\nSubmit solution? level=")
if submit_part not in ["1", "2"]:
return
import bs4
import requests
session = (Path(__file__).parent / f"../../.cache/session").read_text()
resp = requests.post(
f"https://adventofcode.com/{YEAR}/day/{DAY}/answer",
cookies={"session": session},
data={"level": submit_part, "answer": answer},
).text
bs = bs4.BeautifulSoup(resp, "html.parser")
print(bs.main.article.p.text)

View file

@ -32,9 +32,6 @@
with p; [
z3
numpy
pyperclip
requests
beautifulsoup4
networkx
sympy
]);
@ -88,23 +85,18 @@
beautifulsoup4
];
};
live = pkgs.stdenvNoCC.mkDerivation {
live = pkgs.python3.pkgs.buildPythonApplication {
name = "aoc-live";
pyproject = false;
dontUnpack = true;
nativeBuildInputs = with pkgs; [makeWrapper];
installPhase = ''
mkdir -p $out/bin
cp ${./scripts/live.sh} $out/bin/aoc-live
chmod +x $out/bin/*
wrapProgram $out/bin/* --set PATH ${with pkgs;
lib.makeBinPath [
python
bash
coreutils
inotify-tools
wl-clipboard
]}
'';
installPhase = "mkdir -p $out/bin; cp ${./scripts/live.py} $out/bin/aoc-live; chmod +x $out/bin/*";
makeWrapperArgs = ["--set AOC_PYTHON ${python}/bin/python"];
propagatedBuildInputs = with pkgs.python3.pkgs; [
requests
beautifulsoup4
pyperclip
watchdog
];
};
};
})

View file

@ -1,6 +1,6 @@
from lib import *
input = read_input(2024, 1)
input = open(0).read().strip()
blocks = input.split("\n\n")
lines = input.splitlines()
@ -11,4 +11,4 @@ for line in lines:
match = re.match(r"^$", line)
ans(out)
print(out)

139
scripts/live.py Normal file
View file

@ -0,0 +1,139 @@
#!/usr/bin/env python
import os
import subprocess
import sys
import time
from multiprocessing import Process
from pathlib import Path
from threading import Thread
from typing import Any, cast
import bs4
import pyperclip
import requests
from watchdog.events import FileSystemEvent, FileSystemEventHandler
from watchdog.observers import Observer
root_dir = Path(os.getcwd())
while not (root_dir / "flake.nix").is_file():
root_dir = root_dir.parent
os.chdir(root_dir / "live")
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} YEAR DAY")
exit(1)
year, day = map(int, sys.argv[1:3])
def run_solution(input: Path) -> str | None:
if not input.exists():
print(f"\033[1m\033[31mInput file {input} does not exist\033[0m")
return None
py = os.environ.get("AOC_PYTHON", "python")
inp = input.read_bytes()
print(f"cmd: {py} live.py | input: {input.resolve().relative_to(root_dir)}")
start = time.time()
out = subprocess.run([py, "live.py"], input=inp, capture_output=True)
delta = time.time() - start
print(f"\033[3{'12'[out.returncode == 0]}mexit code: {out.returncode} | delta: {delta:.2f}s\033[0m")
print("--- stderr ---")
sys.stdout.buffer.write(out.stderr)
print("--- stdout ---")
sys.stdout.buffer.write(out.stdout)
if out.returncode != 0:
return None
try:
return out.stdout.decode().strip().splitlines()[-1].strip()
except:
return None
def trigger():
print(end="\033[H\033[2J\033[0m")
ex_dir = Path(f"../examples/{year}/{day}")
for ex in sorted(
(x for x in (ex_dir.iterdir() if ex_dir.is_dir() else []) if x.name.isnumeric()), key=lambda f: int(f.name)
):
n = int(ex.name)
print(f"\033[1m\033[34m----- Example {n} -----\033[0m")
run_solution(ex)
print()
print("\033[1m\033[34m----- Puzzle Input -----\033[0m")
ans = run_solution(Path(f"../.cache/{year}/{day}"))
if ans is not None:
print(f"\n\033[1m\033[32mAnswer: {ans}\033[0m")
pyperclip.copy(ans)
if (part := input(f"Submit? level=")) in ["1", "2"]:
print(f"(submitting answer for part {part})")
session = (root_dir / ".cache/session").read_text().strip()
resp = requests.post(
f"https://adventofcode.com/{year}/day/{day}/answer",
cookies={"session": session},
data={"level": part, "answer": ans},
).text
bs = bs4.BeautifulSoup(resp, "html.parser")
resp = cast(Any, bs).main.article.p.text
ok = resp.startswith("That's the right answer!")
print(f"\033[1m\033[3{'12'[ok]}m{resp}\033[0m")
else:
print("\033[1m\033[31m(failed to find answer in program output)\033[0m")
print("(waiting for changes to live.py)")
proc: Process | None = None
def spawn_trigger_process():
global proc
if proc is not None and proc.is_alive():
print("(process killed)")
proc.kill()
def trigger_wrapper():
sys.stdin = open(0)
while True:
trigger()
input()
proc = Process(target=trigger_wrapper)
proc.start()
class Handler(FileSystemEventHandler):
def __init__(self):
super().__init__()
self.cnt = 0
def on_modified(self, event: FileSystemEvent) -> None:
if event.src_path != "./live.py":
return
self.cnt += 1
cnt = self.cnt
def inner():
time.sleep(0.1)
if self.cnt == cnt:
spawn_trigger_process()
t = Thread(target=inner)
t.start()
spawn_trigger_process()
handler = Handler()
observer = Observer()
observer.schedule(handler, ".", recursive=True)
observer.start()
while True:
time.sleep(1)

View file

@ -1,16 +0,0 @@
#!/usr/bin/env bash
set -m
while ! [[ -e flake.nix ]]; do cd ..; done
cd live
while true; do
printf '\033[H\033[J\033[3J\033[37m'
python live.py &
py=$!
(inotifywait -qqe modify live.py; kill $py) &
wa=$!
fg %-
wait $wa
done