-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnsolver.py
142 lines (123 loc) · 3.1 KB
/
nsolver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import json
from itertools import product
from copy import deepcopy
with open('example15x15.json', 'r') as f:
puzzle = json.load(f)
nrows = puzzle['nrows']
ncols = puzzle['ncols']
row_clues = puzzle['row_clues']
col_clues = puzzle['col_clues']
BLANK = ' '
FILLED = '1'
EMPTY = '0'
solution = [BLANK for _ in range(nrows * ncols)]
def get_row(solution, r, nrows, ncols):
starti = r * ncols
endi = starti + ncols
ret = []
for i in range(starti, endi):
ret.append(solution[i])
return ret
def set_row(solution, row, r, nrows, ncols):
starti = r * ncols
endi = starti + ncols
ri = 0
for i in range(starti, endi):
solution[i] = row[ri]
ri += 1
return solution
def get_col(solution, c, nrows, ncols):
starti = c
endi = nrows * ncols
ret = []
for i in range(starti, endi, ncols):
ret.append(solution[i])
return ret
def set_col(solution, col, c, nrows, ncols):
starti = c
endi = nrows * ncols
ri = 0
for i in range(starti, endi, ncols):
solution[i] = col[ri]
ri += 1
return solution
def count_blank(grid):
count = 0
for cell in grid:
if cell == BLANK:
count += 1
return count
def is_solved(grid):
return count_blank(grid) == 0
def gen_clue(grid):
clue = []
n = 0
for cell in grid:
if cell == FILLED:
n += 1
elif cell == EMPTY:
if n == 0:
pass
elif n > 0:
clue.append(n)
n = 0
if n > 0:
clue.append(n)
return clue
def is_clue_matched(clue, grid):
return gen_clue(grid) == clue
def and_candidates(grid, candidates):
ret = deepcopy(grid)
for i, cell in enumerate(ret):
if cell != BLANK:
continue
can_set = set([candidate[i] for candidate in candidates])
if len(can_set) == 1:
answer = can_set.pop()
ret[i] = answer
return ret
def solve_row(clue, grid):
candidates = []
num_blank = count_blank(grid)
bstrings = product('01', repeat=num_blank)
for bstring in bstrings:
candidate = []
bi = 0
for cell in grid:
if cell == BLANK:
candidate.append(bstring[bi])
bi += 1
else:
candidate.append(cell)
if is_clue_matched(clue, candidate):
candidates.append(candidate)
return and_candidates(grid, candidates)
def solve_rows(row_clues, solution):
for r in range(nrows):
soln_row = solve_row(row_clues[r], get_row(solution, r, nrows, ncols))
set_row(solution, soln_row, r, nrows, ncols)
return solution
def solve_cols(col_clues, solution):
for c in range(ncols):
soln_row = solve_row(col_clues[c], get_col(solution, c, nrows, ncols))
set_col(solution, soln_row, c, nrows, ncols)
return solution
def print_grid(grid, nrows, ncols):
print('---')
for r in range(nrows):
row = get_row(grid, r, nrows, ncols)
print(str(row))
print('---')
num_passes = 0
for i in range(nrows * ncols):
print(f'Pass {num_passes}:')
solution = solve_rows(row_clues, solution)
print_grid(solution, nrows, ncols)
solution = solve_cols(col_clues, solution)
print_grid(solution, nrows, ncols)
print()
print()
if is_solved(solution):
print(f'Solved it in {num_passes}!')
break
num_passes += 1