|
| 1 | +import itertools |
| 2 | +import os |
| 3 | + |
| 4 | +puzzle=[ |
| 5 | + "5***1***4", |
| 6 | + "***2*6***", |
| 7 | + "**8*9*6**", |
| 8 | + "*4*****1*", |
| 9 | + "7*1*8*4*6", |
| 10 | + "*5*****3*", |
| 11 | + "**6*4*1**", |
| 12 | + "***5*2***", |
| 13 | + "2***6***8", |
| 14 | +] |
| 15 | + |
| 16 | +clauses = [] |
| 17 | + |
| 18 | +digits = range(1, 10) |
| 19 | + |
| 20 | +def varnum(i, j, k): |
| 21 | + assert(i in digits and j in digits and k in digits) |
| 22 | + return 100 * i + 10 * j + k |
| 23 | + |
| 24 | +def exactly_one_of(literals): |
| 25 | + clauses.append([l for l in literals]) |
| 26 | + |
| 27 | + for pair in itertools.combinations(literals, 2): |
| 28 | + clauses.append([-l for l in pair]) |
| 29 | + |
| 30 | +# cell [i, j] contains exactly on digit |
| 31 | +for (i, j) in itertools.product(digits, repeat=2): |
| 32 | + exactly_one_of([varnum(i, j, k) for k in digits]) |
| 33 | + |
| 34 | +# k appears exactly once in row i |
| 35 | +for (i, k) in itertools.product(digits, repeat=2): |
| 36 | + exactly_one_of([varnum(i, j, k) for k in digits]) |
| 37 | + |
| 38 | +# k appears exactly once in column j |
| 39 | +for (j, k) in itertools.product(digits, repeat=2): |
| 40 | + exactly_one_of([varnum(i, j, k) for k in digits]) |
| 41 | + |
| 42 | +# k appears exactly once in a 3x3 block: |
| 43 | +for (i, j) in itertools.product([1, 4, 7], repeat=2): |
| 44 | + for k in digits: |
| 45 | + exactly_one_of([varnum(i + deltai, j + deltaj, k) for (deltai, deltaj) in itertools.product(range(3), repeat = 2)]) |
| 46 | + |
| 47 | +for (i, j) in itertools.product(digits, repeat=2): |
| 48 | + if puzzle[i - 1][j - 1] != "*": |
| 49 | + k = int(puzzle[i - 1][j - 1]) |
| 50 | + assert(k in digits) |
| 51 | + #[i,j] already contains k: |
| 52 | + clauses.append(varnum(i, j, k)) |
| 53 | + |
| 54 | +with open('temp.cnf', 'w') as f: |
| 55 | + f.write("p cnf {} {}\n".format(999, len(clauses))) |
| 56 | + for c in clauses: |
| 57 | + c.append(0) |
| 58 | + f.write(" ".join(map(str, c))+"\n") |
| 59 | + |
| 60 | +os.system("minisat tmp.cnf tmp.sat") |
| 61 | + |
| 62 | +with open("tmp.sat", "r") as satfile: |
| 63 | + for line in satfile: |
| 64 | + if line.split()[0] == "UNSAT": |
| 65 | + print("There is no solution") |
| 66 | + |
| 67 | + elif line.split()[0] == "SAT": |
| 68 | + pass |
| 69 | + |
| 70 | + else: |
| 71 | + assignment = [int(x) for x in line.split()] |
| 72 | + |
| 73 | + for i in digits: |
| 74 | + for j in digits: |
| 75 | + for k in digits: |
| 76 | + if varnum(i, j, k) in assignment: |
| 77 | + print(k, end="") |
| 78 | + break |
| 79 | + |
| 80 | + print("") |
0 commit comments