def solveBoard(board): global numUnique, printResult, checkUnique, checkUnique def assumeBoard(printBoard): for v in checkAssumps: cnf.assume(-v) row = 0 col = 0 for b in board: if printBoard: sys.stdout.write(b) if b == ".": pass else: i = -1 if N < 10: i = int(b) - 1 else: i = ord(b) - ord("A") # print '(%d,%d) = i = %d' % (row,col,i) cnf.assume(p[i][row][col]) col += 1 if col == N: col = 0 row += 1 if row == N: break if printBoard: sys.stdout.write("\n") assumeBoard(printResult) result = cnf.solve() assert result == cnf.RESULT_SAT if printResult: showBoard(board) if checkUnique: v = cnf.newVar("uniq") c = [-v] for j in range(0, N): for k in range(0, N): for i in range(0, N): if cnf.assignment(p[i][j][k]): c.append(-p[i][j][k]) cnf.addClause("uniq", c) assumeBoard(False) cnf.assume(v) checkAssumps.append(v) result = cnf.solve() if result == cnf.RESULT_SAT: print "non-unique board" showBoard(board) return False elif result == cnf.RESULT_UNSAT: numUnique += 1 return True
def __init__(self, name, rows, cols): self.tbl = {} self.rows = rows self.cols = cols for r in rows: self.tbl[r] = {} clause = [] for c in cols: self.tbl[r][c] = cnf.newVar(name) clause.append( self.tbl[r][c] ) cnf.addClause('>=1', clause) for r in rows: for c1 in cols: for c2 in cols: if c1 != c2: cnf.addClause('<=1', [-self.tbl[r][c1], -self.tbl[r][c2]]) def entry(row, col): assert row in self.rows assert col in self.cols return self.tbl[row][col]
def setup(): """ Sets up universal sudoku constraints. Nothing set up here is specific to the actual board being solved. """ cnf.init() cnf.pico.picosat_set_seed(0) # cnf.pico.picosat_set_global_default_phase(0) # 1361274 cnf.pico.picosat_set_global_default_phase(1) # 1353908 # create vars for i in range(0, N): p[i] = {} for j in range(0, N): p[i][j] = {} for k in range(0, N): p[i][j][k] = cnf.newVar("[%d][%d] = %d" % (j, k, i)) # must choose at least one possibility per square for j in range(0, N): for k in range(0, N): clause = [] for i in range(0, N): clause.append(p[i][j][k]) cnf.addClause(">=1", clause) # must choose at most one possibility per square for j in range(0, N): for k in range(0, N): for i in range(0, N): for l in range(0, N): if i != l: cnf.addClause("<=1", [-p[i][j][k], -p[l][j][k]]) # columns have 1-9 at most once for i in range(0, N): for r in range(0, N): for c in range(0, N): for r2 in range(0, N): if r2 != r: cnf.addClause("col_val", [-p[i][r][c], -p[i][r2][c]]) # rows have 1-9 at most once for i in range(0, N): for r in range(0, N): for c in range(0, N): for c2 in range(0, N): if c2 != c: cnf.addClause("row_val", [-p[i][r][c], -p[i][r][c2]]) # 3x3 grids have 1-9 at most once for s in range(0, N / Sq): for t in range(0, N / Sq): for r in range(s * (N / Sq), (s + 1) * (N / Sq)): for c in range(t * (N / Sq), (t + 1) * (N / Sq)): for r2 in range(s * (N / Sq), (s + 1) * (N / Sq)): for c2 in range(t * (N / Sq), (t + 1) * (N / Sq)): # comment this out to see if your python doesn't suck. # it doesn't error iff it sucks for i in range(0, N): if r != r2 and c != c2: # print "%d %d %d -- %d %d %d" % (i,r,c, i,r2,c2) cnf.addClause("3x3", [-p[i][r][c], -p[i][r2][c2]])