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

def evalx(x,D,P,K,locks):
    v=0; bad=[]
    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 A: continue
            if all((masks[p]>>x[k][p])&1 for p in range(P)):
                v+=1; bad.append((l,k))
    return v,bad

def solve(D,P,K,locks,limit=60):
    rng=random.Random(4); codes=seqs(D,P); t0=time.time(); best=999999
    locksets=[set(A) for A in locks]
    while time.time()-t0<limit:
        x=[list(rng.choice(codes)) for _ in range(K)]
        v,bad=evalx(x,D,P,K,locks)
        for step in range(200000):
            if v<best:
                best=v; print('best',best,'step',step,'time',time.time()-t0, flush=True)
                if v==0: return [tuple(r) for r in x]
            if time.time()-t0>limit: break
            if bad and rng.random()<0.7:
                l,k=rng.choice(bad)
                if rng.random()<0.5: k=rng.choice(list(locks[l]))
            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)]
            old=x[k][p]; bd=old; bv=v
            for d in allowed:
                if d==old: continue
                x[k][p]=d; nv,nb=evalx(x,D,P,K,locks)
                if nv<bv or (nv==bv and rng.random()<0.02): bv=nv; bd=d; bestbad=nb
            if bv>=v and rng.random()<0.05: bd=rng.choice(allowed)
            x[k][p]=bd; v,bad=evalx(x,D,P,K,locks)
    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 60); print('SOL',sol is not None); print(sol if sol else '')
