#!/usr/bin/env python3 """CodeShell.kr - Undo History (Misc, 200p) solver. A VOID undoes an earlier event, but a VOID can itself be undone by a later VOID, so the survival of each event is the fixpoint of alive[e] = 1 XOR (XOR of alive[v] for v pointing at e). Iterating to the fixpoint and then applying the surviving non-VOID events in ascending tick order to the initial screen gives the answer. """ import csv
defmain(): rows = sorted(csv.DictReader(open(LEDGER)), key=lambda r: int(r["tick"])) voids = {int(r["id"]): int(r["a"]) for r in rows if r["op"] == "VOID"}
alive = {int(r["id"]): 1for r in rows} updates = 0 whileTrue: new = {i: 1 ^ (sum(alive[v] for v, t in voids.items() if t == i) & 1) for i in alive} if new == alive: break alive = new updates += 1 print(f"fixpoint after {updates} updates; surviving VOIDs " f"{sum(alive[v] for v in voids)}/{len(voids)}")
s = list(INITIAL) for r in rows: ifnot alive[int(r["id"])] or r["op"] == "VOID": continue a, b = int(r["a"]), (int(r["b"]) if r["b"] elseNone) if r["op"] == "SWAP": s[a], s[b] = s[b], s[a] elif r["op"] == "REVERSE": s[a:b + 1] = s[a:b + 1][::-1] elif r["op"] == "ROTATE": n = a % 15 s = s[-n:] + s[:-n] if n else s print("".join(s))