from search_proto import load,seqs
import sys,random,time,math

def evalx(x,D,P,K,locks):
 cnt=0; bad=[]; locksets=[set(A) for A in locks]
 for l,A in enumerate(locks):
  masks=[0]*P
  for k in A:
   for p in range(P): masks[p]|=1<<x[k][p]
  for k in range(K):
   if k in locksets[l]: continue
   if all((masks[p]>>x[k][p])&1 for p in range(P)): cnt+=1; bad.append((l,k))
 return cnt,bad

def solve(D,P,K,locks,limit=120):
 rng=random.Random(9); codes=seqs(D,P); t0=time.time(); best=9999; bx=None
 while time.time()-t0<limit:
  x=[list(rng.choice(codes)) for _ in range(K)]
  cur,bad=evalx(x,D,P,K,locks)
  for step in range(500000):
   if cur<best: best=cur; bx=[r[:] for r in x]; print('best',best,'step',step,'time',time.time()-t0,flush=True);
   if cur==0: return [tuple(r) for r in x]
   if time.time()-t0>limit: break
   T=max(0.05, 5.0*(1-(time.time()-t0)/limit))
   if bad and rng.random()<0.8:
    l,k=rng.choice(bad); k = (rng.choice(list(locks[l])) if rng.random()<0.5 else k)
   else: k=rng.randrange(K)
   p=rng.randrange(P)
   allowed=[d for d in range(D) if (p==0 or abs(x[k][p-1]-d)<=1) and (p==P-1 or abs(x[k][p+1]-d)<=1) and d!=x[k][p]]
   if not allowed: continue
   old=x[k][p]; d=rng.choice(allowed); x[k][p]=d; nv,nb=evalx(x,D,P,K,locks); delta=nv-cur
   if delta<=0 or rng.random()<math.exp(-delta/T): cur=nv; bad=nb
   else: x[k][p]=old
 return None
if __name__=='__main__':
 D,P,K,locks=load(sys.argv[1]); print(D,P,K,len(locks)); sol=solve(D,P,K,locks,float(sys.argv[2]) if len(sys.argv)>2 else 120); print('SOL',sol is not None); print(sol if sol else '')
