# Standalone v1 reproduction: identical experiment; prints JSON without writing repository files.
"""Research only; python3 scripts/research/dice_balance.py. No application imports."""
import json, math, random, statistics
from pathlib import Path
W = [1,2,3,4,5,6,5,4,3,2,1]
P = [w/36 for w in W]
TRIALS = 10000
MODES = ['iid', 'deck36_draw36', 'deck36_draw31', 'deck36_draw24', 'deck72_draw36', 'dueness_noise2']

def percentile(a, q):
    return sorted(a)[math.ceil(len(a)*q)-1]

out = {'trials_per_mode': TRIALS, 'seed': 20260908, 'notes': 'Fixed 100-roll sequences, fresh state each trial. Droughts include censored start/end runs. Not full games or production RNG.', 'modes': {}}
for mode_index, mode in enumerate(MODES):
    rng = random.Random(20260908+mode_index)
    tv = {n: [] for n in [36,60,100]}
    droughts, repeats, guesses = [], [], []
    totals = [0]*11
    for trial in range(TRIALS):
        counts = [0]*11
        remaining, due = W.copy(), W.copy()
        last, repeat, drought, worst, guess = -1, 0, 0, 0, 0
        for t in range(100):
            if mode.startswith('deck'):
                size, draws = [int(x) for x in mode.replace('deck','').split('_draw')]
                if t % draws == 0:
                    remaining = [w*(size//36) for w in W]
                weights = remaining
            elif mode.startswith('dueness'):
                weights = [max(d+2*w,0) for d,w in zip(due,W)]
            else:
                weights = W
            guess += max(weights)/sum(weights)
            k = rng.choices(range(11), weights=weights)[0]
            if mode.startswith('deck'):
                remaining[k] -= 1
            elif mode.startswith('dueness'):
                due = [d+w for d,w in zip(due,W)]
                due[k] -= 36
            counts[k] += 1
            totals[k] += 1
            if t < 60:
                repeat += int(k == last)
                drought = 0 if k == 4 else drought+1
                worst = max(worst,drought)
            last = k
            if t+1 in tv:
                tv[t+1].append(sum(abs(c/(t+1)-p) for c,p in zip(counts,P))/2)
        droughts.append(worst)
        repeats.append(repeat/59)
        guesses.append(guess/100)
    out['modes'][mode] = {'mean_tv': {n: round(statistics.mean(v),4) for n,v in tv.items()}, 'p95_tv60': round(percentile(tv[60],.95),4), 'p95_longest_no6_run_in60': percentile(droughts,.95), 'repeat_rate60': round(statistics.mean(repeats),4), 'mean_optimal_next_sum_guess100': round(statistics.mean(guesses),4), 'aggregate_sum_frequencies': [round(n/(TRIALS*100),5) for n in totals]}
print(json.dumps(out,indent=2))
