#!/usr/bin/env python3
"""Reproducible toy model for a static prop challenge (stdlib only)."""
import random
import math

P = .55
START, FAIL, PASS = 50_000, 48_000, 53_000
ATTEMPTS, SEED, HORIZON = 20_000, 20_260_917, 10_000

def model(r, p=P):
    if r <= 0 or (START - FAIL) % r or (PASS - FAIL) % r:
        raise ValueError("r must divide both challenge distances")
    if not 0 < p < 1:
        raise ValueError("p must be between zero and one")
    i, n = (START - FAIL) // r, (PASS - FAIL) // r
    if p == .5:
        chance = i / n
        expected = i * (n - i)
    else:
        q, a = 1 - p, (1 - p) / p
        chance = (1 - a ** i) / (1 - a ** n)
        expected = (n * chance - i) / (p - q)
    return chance, expected

def simulate(r, count=ATTEMPTS, seed=SEED, horizon=HORIZON):
    model(r)  # Check that the step lands exactly on both boundaries.
    if count <= 0 or horizon <= 0:
        raise ValueError("count and horizon must be positive")
    rng = random.Random(seed)
    lower, upper = 0, (PASS - FAIL) // r
    wins = times = censored = 0
    for _ in range(count):
        x = (START - FAIL) // r
        for t in range(1, horizon + 1):
            x += 1 if rng.random() < P else -1
            if x in (lower, upper):
                wins += x == upper
                times += t
                break
        else:
            censored += 1
    finished = count - censored
    return wins / count, (times / finished if finished else math.nan), censored

def self_check():
    assert model(1000, .5)[0] == .4
    assert model(1000, .5)[1] == 6
    for r in (100, 250, 500, 1000):
        assert (START - FAIL) % r == (PASS - FAIL) % r == 0
    assert START - FAIL == 2_000 and PASS - START == 3_000
    for r in (100, 250, 500, 1000):
        analytical, _ = model(r)
        observed, _, censored = simulate(r)
        assert not censored and abs(observed - analytical) < 5 * math.sqrt(.25 / ATTEMPTS)
    _, duration, censored = simulate(100, count=10, horizon=1)
    assert censored == 10 and math.isnan(duration)

if __name__ == "__main__":
    self_check()
    print("r\tanalytic pass\tanalytic trades\tsim pass\tsim trades\tcensored")
    for r in (100, 250, 500, 1000):
        chance, expected = model(r)
        sim_chance, sim_expected, censored = simulate(r)
        print(f"${r}\t{chance:.6%}\t{expected:.6f}\t{sim_chance:.6%}\t{sim_expected:.4f}\t{censored}")
