Horse/Implementations
Jump to navigation
Jump to search
Python
(ChatGPT wrote this, but it's tested)
import re import sys import random class Statement: pass class IncrStmt(Statement): def __init__(self, target, amount): self.target = target self.amount = amount class DecrStmt(Statement): def __init__(self, target, amount): self.target = target self.amount = amount class PrintStmt(Statement): def __init__(self, target=None, message=None): self.target = target self.message = message class HaltStmt(Statement): pass class CollapseStmt(Statement): pass class RandomStmt(Statement): def __init__(self, target): self.target = target class CondStmt(Statement): def __init__(self, target, op, value): self.target = target self.op = op self.value = value class Case: def __init__(self, skip_count, statements): self.skip_count = skip_count self.statements = statements class Horse: def __init__(self, name, cases): self.name = name self.cases = cases # list of Case self.active = True self.value = 0 class Interpreter: def __init__(self, lines): self.horses = {} self.halt = False self.parse(lines) def parse(self, lines): block_re = re.compile(r"<(?:(\d+):)?([^>]*)>") stmt_re = re.compile(r"\[([^\]]+)\]") for line in lines: line = line.strip() if not line or line.startswith('#'): continue parts = line.split(None, 2) name = ' '.join(parts[:2]) if len(parts) >= 2 and '<' not in parts[1] else parts[0] rest = line[len(name):].strip() blocks = block_re.findall(rest) cases = [] for skip_str, body in blocks: skip = int(skip_str) if skip_str else 1 stmts = [self.parse_statement(s.strip(), name) for s in stmt_re.findall(body)] cases.append(Case(skip, stmts)) self.horses[name] = Horse(name, cases) def parse_statement(self, text, current): t = text.strip() # Handle PRINT statements: quoted strings are messages, unquoted are variable targets if t.upper().startswith('PRINT'): parts = t.split(None, 1) # No argument: print current horse's value if len(parts) == 1: return PrintStmt(target=current) arg = parts[1].strip() # Quoted string literal -> message if (arg.startswith('"') and arg.endswith('"')) or (arg.startswith("'") and arg.endswith("'")): message = arg[1:-1] return PrintStmt(message=message) # Otherwise, treat as variable name return PrintStmt(target=arg) if t.upper() == 'HALT': return HaltStmt() if t.upper() == 'COLLAPSE': return CollapseStmt() if t.upper() == 'RANDOM': return RandomStmt(current) if t.upper().startswith('RANDOM '): target = t.split(None, 1)[1].strip() return RandomStmt(target) m = re.match(r"([\w ]+)(!?=)([\-\w ]+)", t) if m: return CondStmt(m.group(1).strip(), m.group(2), m.group(3).strip()) m = re.match(r"([\w ]+) (\d+)([ID])", t) if m: tgt, amt, op = m.group(1).strip(), int(m.group(2)), m.group(3) return IncrStmt(tgt, amt) if op == 'I' else DecrStmt(tgt, amt) m = re.match(r"(\d+)([ID])", t) if m: amt, op = int(m.group(1)), m.group(2) return IncrStmt(current, amt) if op == 'I' else DecrStmt(current, amt) raise ValueError(f"Unknown statement: {t}") def ensure(self, name): if name not in self.horses: self.horses[name] = Horse(name, [Case(1, [])]) def run(self): step = 1 while not self.halt: signals = {} for h_name, h in self.horses.items(): if not h.active: continue for case in h.cases: if step % case.skip_count != 0: continue i = 0 while i < len(case.statements): cond_results = [] while i < len(case.statements) and isinstance(case.statements[i], CondStmt): stmt = case.statements[i] self.ensure(stmt.target) val = self.horses[stmt.target].value try: cmp_val = int(stmt.value) except ValueError: self.ensure(stmt.value) cmp_val = self.horses[stmt.value].value cond = (val == cmp_val) if stmt.op == '=' else (val != cmp_val) cond_results.append(cond) i += 1 if i < len(case.statements) and (not cond_results or all(cond_results)): stmt = case.statements[i] if isinstance(stmt, IncrStmt) or isinstance(stmt, DecrStmt): if stmt.target not in signals: signals[stmt.target] = [] signals[stmt.target].append((h_name, stmt)) i += 1 for h_name, h in self.horses.items(): if not h.active: continue for case in h.cases: if step % case.skip_count != 0: continue i = 0 while i < len(case.statements): cond_results = [] while i < len(case.statements) and isinstance(case.statements[i], CondStmt): stmt = case.statements[i] self.ensure(stmt.target) val = self.horses[stmt.target].value try: cmp_val = int(stmt.value) except ValueError: self.ensure(stmt.value) cmp_val = self.horses[stmt.value].value cond = (val == cmp_val) if stmt.op == '=' else (val != cmp_val) cond_results.append(cond) i += 1 if i < len(case.statements) and (not cond_results or all(cond_results)): stmt = case.statements[i] if isinstance(stmt, IncrStmt) or isinstance(stmt, DecrStmt): collision = False if stmt.target in signals and len(signals[stmt.target]) > 1: collision = True if not collision: if isinstance(stmt, IncrStmt): self.ensure(stmt.target) self.horses[stmt.target].value += stmt.amount else: self.ensure(stmt.target) self.horses[stmt.target].value -= stmt.amount elif isinstance(stmt, PrintStmt): if stmt.message is not None: print(stmt.message) else: self.ensure(stmt.target) print(self.horses[stmt.target].value) elif isinstance(stmt, HaltStmt): self.halt = True break elif isinstance(stmt, CollapseStmt): h.active = False elif isinstance(stmt, RandomStmt): self.ensure(stmt.target) self.horses[stmt.target].value += random.choice([1, -1]) i += 1 if self.halt: break if self.halt: break signals.clear() step += 1 #Debug output #for name, horse in self.horses.items(): # print(f"{name}: {horse.value}", end=' | ') #print() if __name__ == '__main__': lines = sys.stdin.readlines() if len(sys.argv) == 1 else open(sys.argv[1]).readlines() Interpreter(lines).run()