multi-puzzle-solver 1.0.4__py3-none-any.whl → 1.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of multi-puzzle-solver might be problematic. Click here for more details.
- {multi_puzzle_solver-1.0.4.dist-info → multi_puzzle_solver-1.0.6.dist-info}/METADATA +740 -296
- multi_puzzle_solver-1.0.6.dist-info/RECORD +73 -0
- puzzle_solver/__init__.py +3 -1
- puzzle_solver/core/utils.py +17 -1
- puzzle_solver/core/utils_visualizer.py +257 -201
- puzzle_solver/puzzles/aquarium/aquarium.py +8 -23
- puzzle_solver/puzzles/battleships/battleships.py +39 -53
- puzzle_solver/puzzles/binairo/binairo.py +2 -2
- puzzle_solver/puzzles/black_box/black_box.py +6 -70
- puzzle_solver/puzzles/connect_the_dots/connect_the_dots.py +4 -2
- puzzle_solver/puzzles/filling/filling.py +11 -34
- puzzle_solver/puzzles/galaxies/galaxies.py +4 -2
- puzzle_solver/puzzles/heyawake/heyawake.py +6 -2
- puzzle_solver/puzzles/kakurasu/kakurasu.py +5 -13
- puzzle_solver/puzzles/kakuro/kakuro.py +6 -2
- puzzle_solver/puzzles/lits/lits.py +4 -2
- puzzle_solver/puzzles/mosaic/mosaic.py +8 -18
- puzzle_solver/puzzles/nonograms/nonograms.py +80 -85
- puzzle_solver/puzzles/nonograms/nonograms_colored.py +221 -0
- puzzle_solver/puzzles/norinori/norinori.py +5 -12
- puzzle_solver/puzzles/nurikabe/nurikabe.py +6 -2
- puzzle_solver/puzzles/palisade/palisade.py +4 -3
- puzzle_solver/puzzles/pearl/pearl.py +15 -27
- puzzle_solver/puzzles/pipes/pipes.py +2 -1
- puzzle_solver/puzzles/range/range.py +19 -55
- puzzle_solver/puzzles/rectangles/rectangles.py +4 -2
- puzzle_solver/puzzles/shingoki/shingoki.py +2 -2
- puzzle_solver/puzzles/singles/singles.py +6 -2
- puzzle_solver/puzzles/slant/slant.py +13 -19
- puzzle_solver/puzzles/slitherlink/slitherlink.py +2 -2
- puzzle_solver/puzzles/star_battle/star_battle.py +5 -2
- puzzle_solver/puzzles/stitches/stitches.py +8 -21
- puzzle_solver/puzzles/sudoku/sudoku.py +5 -11
- puzzle_solver/puzzles/tapa/tapa.py +6 -2
- puzzle_solver/puzzles/tents/tents.py +50 -80
- puzzle_solver/puzzles/tracks/tracks.py +19 -66
- puzzle_solver/puzzles/unruly/unruly.py +17 -49
- puzzle_solver/puzzles/yin_yang/yin_yang.py +3 -10
- multi_puzzle_solver-1.0.4.dist-info/RECORD +0 -72
- {multi_puzzle_solver-1.0.4.dist-info → multi_puzzle_solver-1.0.6.dist-info}/WHEEL +0 -0
- {multi_puzzle_solver-1.0.4.dist-info → multi_puzzle_solver-1.0.6.dist-info}/top_level.txt +0 -0
|
@@ -2,8 +2,9 @@ from collections import defaultdict
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
from ortools.sat.python import cp_model
|
|
4
4
|
|
|
5
|
-
from puzzle_solver.core.utils import Pos, get_all_pos,
|
|
5
|
+
from puzzle_solver.core.utils import Pos, get_all_pos, get_char, Direction, in_bounds, get_next_pos, get_row_pos, get_col_pos, get_opposite_direction, get_pos
|
|
6
6
|
from puzzle_solver.core.utils_ortools import force_connected_component, generic_solve_all, SingleSolution
|
|
7
|
+
from puzzle_solver.core.utils_visualizer import combined_function
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Board:
|
|
@@ -11,8 +12,7 @@ class Board:
|
|
|
11
12
|
assert board.ndim == 2, f'board must be 2d, got {board.ndim}'
|
|
12
13
|
assert all((len(c.item()) == 2) and all(ch in [' ', 'U', 'L', 'D', 'R'] for ch in c.item()) for c in np.nditer(board)), 'board must contain only digits or space'
|
|
13
14
|
self.board = board
|
|
14
|
-
self.V = board.shape
|
|
15
|
-
self.H = board.shape[1]
|
|
15
|
+
self.V, self.H = board.shape
|
|
16
16
|
self.side = side
|
|
17
17
|
self.top = top
|
|
18
18
|
self.first_col_start_pos = [p for p in get_col_pos(0, self.V) if 'L' in get_char(self.board, p)]
|
|
@@ -33,75 +33,45 @@ class Board:
|
|
|
33
33
|
for pos in get_all_pos(self.V, self.H):
|
|
34
34
|
self.cell_active[pos] = self.model.NewBoolVar(f'{pos}')
|
|
35
35
|
for direction in Direction:
|
|
36
|
-
|
|
36
|
+
next_pos = get_next_pos(pos, direction)
|
|
37
|
+
opposite_direction = get_opposite_direction(direction)
|
|
38
|
+
if (next_pos, opposite_direction) in self.cell_direction:
|
|
39
|
+
self.cell_direction[(pos, direction)] = self.cell_direction[(next_pos, opposite_direction)]
|
|
40
|
+
else:
|
|
41
|
+
self.cell_direction[(pos, direction)] = self.model.NewBoolVar(f'{pos}:{direction}')
|
|
37
42
|
|
|
38
43
|
def add_all_constraints(self):
|
|
39
|
-
self.force_hints()
|
|
40
|
-
self.force_sides()
|
|
41
|
-
self.force_0_or_2_active()
|
|
42
|
-
self.force_direction_constraints()
|
|
43
|
-
self.force_connected_component()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def force_hints(self):
|
|
47
44
|
# force the already given hints
|
|
45
|
+
str_to_direction = {'U': Direction.UP, 'L': Direction.LEFT, 'D': Direction.DOWN, 'R': Direction.RIGHT}
|
|
48
46
|
for pos in get_all_pos(self.V, self.H):
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
self.model.Add(self.cell_direction[(pos, Direction.UP)] == 1)
|
|
52
|
-
if 'L' in c:
|
|
53
|
-
self.model.Add(self.cell_direction[(pos, Direction.LEFT)] == 1)
|
|
54
|
-
if 'D' in c:
|
|
55
|
-
self.model.Add(self.cell_direction[(pos, Direction.DOWN)] == 1)
|
|
56
|
-
if 'R' in c:
|
|
57
|
-
self.model.Add(self.cell_direction[(pos, Direction.RIGHT)] == 1)
|
|
47
|
+
for char in get_char(self.board, pos).strip():
|
|
48
|
+
self.model.Add(self.cell_direction[(pos, str_to_direction[char])] == 1)
|
|
58
49
|
|
|
59
|
-
def force_sides(self):
|
|
60
50
|
# force the already given sides
|
|
61
51
|
for i in range(self.V):
|
|
62
52
|
self.model.Add(sum([self.cell_active[pos] for pos in get_row_pos(i, self.H)]) == self.side[i])
|
|
63
53
|
for i in range(self.H):
|
|
64
54
|
self.model.Add(sum([self.cell_active[pos] for pos in get_col_pos(i, self.V)]) == self.top[i])
|
|
65
55
|
|
|
66
|
-
def force_0_or_2_active(self):
|
|
67
56
|
# cell active means exactly 2 directions are active, cell not active means no directions are active
|
|
68
57
|
for pos in get_all_pos(self.V, self.H):
|
|
69
58
|
s = sum([self.cell_direction[(pos, direction)] for direction in Direction])
|
|
70
59
|
self.model.Add(s == 2).OnlyEnforceIf(self.cell_active[pos])
|
|
71
60
|
self.model.Add(s == 0).OnlyEnforceIf(self.cell_active[pos].Not())
|
|
72
61
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for pos in get_all_pos(self.V, self.H):
|
|
76
|
-
right_pos = get_next_pos(pos, Direction.RIGHT)
|
|
77
|
-
if in_bounds(right_pos, self.V, self.H):
|
|
78
|
-
self.model.Add(self.cell_direction[(pos, Direction.RIGHT)] == self.cell_direction[(right_pos, Direction.LEFT)])
|
|
79
|
-
down_pos = get_next_pos(pos, Direction.DOWN)
|
|
80
|
-
if in_bounds(down_pos, self.V, self.H):
|
|
81
|
-
self.model.Add(self.cell_direction[(pos, Direction.DOWN)] == self.cell_direction[(down_pos, Direction.UP)])
|
|
82
|
-
left_pos = get_next_pos(pos, Direction.LEFT)
|
|
83
|
-
if in_bounds(left_pos, self.V, self.H):
|
|
84
|
-
self.model.Add(self.cell_direction[(pos, Direction.LEFT)] == self.cell_direction[(left_pos, Direction.RIGHT)])
|
|
85
|
-
top_pos = get_next_pos(pos, Direction.UP)
|
|
86
|
-
if in_bounds(top_pos, self.V, self.H):
|
|
87
|
-
self.model.Add(self.cell_direction[(pos, Direction.UP)] == self.cell_direction[(top_pos, Direction.DOWN)])
|
|
88
|
-
|
|
89
|
-
# first column cant have L unless it is the start position
|
|
90
|
-
for pos in get_col_pos(0, self.V):
|
|
62
|
+
# force borders
|
|
63
|
+
for pos in get_col_pos(0, self.V): # first column cant have L unless it is the start position
|
|
91
64
|
if pos != self.first_col_start_pos:
|
|
92
65
|
self.model.Add(self.cell_direction[(pos, Direction.LEFT)] == 0)
|
|
93
|
-
# last column cant have R
|
|
94
|
-
for pos in get_col_pos(self.H - 1, self.V):
|
|
66
|
+
for pos in get_col_pos(self.H - 1, self.V): # last column cant have R
|
|
95
67
|
self.model.Add(self.cell_direction[(pos, Direction.RIGHT)] == 0)
|
|
96
|
-
# last row cant have D unless it is the end position
|
|
97
|
-
for pos in get_row_pos(self.V - 1, self.H):
|
|
68
|
+
for pos in get_row_pos(self.V - 1, self.H): # last row cant have D unless it is the end position
|
|
98
69
|
if pos != self.last_row_end_pos:
|
|
99
70
|
self.model.Add(self.cell_direction[(pos, Direction.DOWN)] == 0)
|
|
100
|
-
# first row cant have U
|
|
101
|
-
for pos in get_row_pos(0, self.H):
|
|
71
|
+
for pos in get_row_pos(0, self.H): # first row cant have U
|
|
102
72
|
self.model.Add(self.cell_direction[(pos, Direction.UP)] == 0)
|
|
103
73
|
|
|
104
|
-
|
|
74
|
+
# force single connected component
|
|
105
75
|
def is_neighbor(pd1: tuple[Pos, Direction], pd2: tuple[Pos, Direction]) -> bool:
|
|
106
76
|
p1, d1 = pd1
|
|
107
77
|
p2, d2 = pd2
|
|
@@ -112,30 +82,13 @@ class Board:
|
|
|
112
82
|
return False
|
|
113
83
|
force_connected_component(self.model, self.cell_direction, is_neighbor=is_neighbor)
|
|
114
84
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
85
|
def solve_and_print(self, verbose: bool = True):
|
|
120
86
|
def board_to_solution(board: Board, solver: cp_model.CpSolverSolutionCallback) -> SingleSolution:
|
|
121
87
|
assignment: dict[Pos, str] = defaultdict(str)
|
|
122
88
|
for (pos, direction), var in board.cell_direction.items():
|
|
123
89
|
assignment[pos] += direction.name[0] if solver.BooleanValue(var) else ''
|
|
124
|
-
for pos in get_all_pos(self.V, self.H):
|
|
125
|
-
if len(assignment[pos]) == 0:
|
|
126
|
-
assignment[pos] = ' '
|
|
127
|
-
else:
|
|
128
|
-
assignment[pos] = ''.join(sorted(assignment[pos]))
|
|
129
90
|
return SingleSolution(assignment=assignment)
|
|
130
91
|
def callback(single_res: SingleSolution):
|
|
131
92
|
print("Solution found")
|
|
132
|
-
print(single_res.assignment)
|
|
133
|
-
res = np.full((self.V, self.H), ' ', dtype=object)
|
|
134
|
-
pretty_dict = {'DU': '┃ ', 'LR': '━━', 'DL': '━┒', 'DR': '┏━', 'RU': '┗━', 'LU': '━┛', ' ': ' '}
|
|
135
|
-
for pos in get_all_pos(self.V, self.H):
|
|
136
|
-
c = get_char(self.board, pos)
|
|
137
|
-
c = single_res.assignment[pos]
|
|
138
|
-
c = pretty_dict[c]
|
|
139
|
-
set_char(res, pos, c)
|
|
140
|
-
print(res)
|
|
93
|
+
print(combined_function(self.V, self.H, show_grid=False, special_content=lambda r, c: single_res.assignment[get_pos(x=c, y=r)].strip(), center_char=lambda r, c: '.', text_on_shaded_cells=False))
|
|
141
94
|
return generic_solve_all(self, board_to_solution, callback=callback if verbose else None, verbose=verbose, max_solutions=20)
|
|
@@ -2,35 +2,17 @@ import numpy as np
|
|
|
2
2
|
from ortools.sat.python import cp_model
|
|
3
3
|
from ortools.sat.python.cp_model import LinearExpr as lxp
|
|
4
4
|
|
|
5
|
-
from puzzle_solver.core.utils import Pos, get_all_pos,
|
|
5
|
+
from puzzle_solver.core.utils import Pos, get_all_pos, get_char, get_row_pos, get_col_pos, in_bounds, Direction, get_next_pos, get_pos
|
|
6
|
+
from puzzle_solver.core.utils_visualizer import combined_function
|
|
6
7
|
from puzzle_solver.core.utils_ortools import generic_solve_all, SingleSolution
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
def get_3_consecutive_horiz_and_vert(pos: Pos, V: int, H: int) -> tuple[list[Pos], list[Pos]]:
|
|
10
|
-
"""Get 3 consecutive squares, horizontally and vertically, from the given position."""
|
|
11
|
-
horiz = []
|
|
12
|
-
vert = []
|
|
13
|
-
cur_pos = pos
|
|
14
|
-
for _ in range(3):
|
|
15
|
-
if in_bounds(cur_pos, V, H):
|
|
16
|
-
horiz.append(cur_pos)
|
|
17
|
-
cur_pos = get_next_pos(cur_pos, Direction.RIGHT)
|
|
18
|
-
cur_pos = pos
|
|
19
|
-
for _ in range(3):
|
|
20
|
-
if in_bounds(cur_pos, V, H):
|
|
21
|
-
vert.append(cur_pos)
|
|
22
|
-
cur_pos = get_next_pos(cur_pos, Direction.DOWN)
|
|
23
|
-
return horiz, vert
|
|
24
|
-
|
|
25
|
-
|
|
26
10
|
class Board:
|
|
27
11
|
def __init__(self, board: np.array):
|
|
28
12
|
assert board.ndim == 2, f'board must be 2d, got {board.ndim}'
|
|
29
|
-
assert board.shape[0] % 2 == 0, 'board must have even number of rows'
|
|
30
|
-
assert board.shape[1] % 2 == 0, 'board must have even number of columns'
|
|
13
|
+
assert board.shape[0] % 2 == 0 and board.shape[1] % 2 == 0, 'board must have even number of rows and columns'
|
|
31
14
|
self.board = board
|
|
32
|
-
self.V = board.shape
|
|
33
|
-
self.H = board.shape[1]
|
|
15
|
+
self.V, self.H = board.shape
|
|
34
16
|
self.model = cp_model.CpModel()
|
|
35
17
|
self.model_vars: dict[Pos, cp_model.IntVar] = {}
|
|
36
18
|
|
|
@@ -42,24 +24,19 @@ class Board:
|
|
|
42
24
|
self.model_vars[pos] = self.model.NewBoolVar(f'{pos}')
|
|
43
25
|
|
|
44
26
|
def add_all_constraints(self):
|
|
45
|
-
# some cells are already filled
|
|
46
27
|
for pos in get_all_pos(self.V, self.H):
|
|
28
|
+
# enforce hints
|
|
47
29
|
c = get_char(self.board, pos)
|
|
48
|
-
if c
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
self.model.Add(lxp.Sum(horiz) != 3)
|
|
59
|
-
if len(vert) == 3:
|
|
60
|
-
vert = [self.model_vars[v] for v in vert]
|
|
61
|
-
self.model.Add(lxp.Sum(vert) != 0)
|
|
62
|
-
self.model.Add(lxp.Sum(vert) != 3)
|
|
30
|
+
if c.strip():
|
|
31
|
+
self.model.Add(self.model_vars[pos] == (c.strip() == 'B'))
|
|
32
|
+
# no three consecutive squares, horizontally or vertically, are the same colour
|
|
33
|
+
for direction in [Direction.RIGHT, Direction.DOWN]:
|
|
34
|
+
var_list = [pos]
|
|
35
|
+
for _ in range(2):
|
|
36
|
+
var_list.append(get_next_pos(var_list[-1], direction))
|
|
37
|
+
if all(in_bounds(v, self.V, self.H) for v in var_list):
|
|
38
|
+
self.model.Add(lxp.Sum([self.model_vars[v] for v in var_list]) != 0)
|
|
39
|
+
self.model.Add(lxp.Sum([self.model_vars[v] for v in var_list]) != 3)
|
|
63
40
|
# each row and column contains the same number of black and white squares.
|
|
64
41
|
for col in range(self.H):
|
|
65
42
|
var_list = [self.model_vars[pos] for pos in get_col_pos(col, self.V)]
|
|
@@ -70,17 +47,8 @@ class Board:
|
|
|
70
47
|
|
|
71
48
|
def solve_and_print(self, verbose: bool = True):
|
|
72
49
|
def board_to_solution(board: Board, solver: cp_model.CpSolverSolutionCallback) -> SingleSolution:
|
|
73
|
-
assignment:
|
|
74
|
-
for pos, var in board.model_vars.items():
|
|
75
|
-
assignment[pos] = solver.Value(var)
|
|
76
|
-
return SingleSolution(assignment=assignment)
|
|
50
|
+
return SingleSolution(assignment={pos: solver.Value(var) for pos, var in board.model_vars.items()})
|
|
77
51
|
def callback(single_res: SingleSolution):
|
|
78
52
|
print("Solution found")
|
|
79
|
-
|
|
80
|
-
for pos in get_all_pos(self.V, self.H):
|
|
81
|
-
c = get_char(self.board, pos)
|
|
82
|
-
if c == ' ':
|
|
83
|
-
c = 'B' if single_res.assignment[pos] == 1 else 'W'
|
|
84
|
-
set_char(res, pos, c)
|
|
85
|
-
print(res)
|
|
53
|
+
print(combined_function(self.V, self.H, is_shaded=lambda r, c: single_res.assignment[get_pos(x=c, y=r)] == 1))
|
|
86
54
|
return generic_solve_all(self, board_to_solution, callback=callback if verbose else None, verbose=verbose)
|
|
@@ -3,8 +3,9 @@ import numpy as np
|
|
|
3
3
|
from ortools.sat.python import cp_model
|
|
4
4
|
from ortools.sat.python.cp_model import LinearExpr as lxp
|
|
5
5
|
|
|
6
|
-
from puzzle_solver.core.utils import Pos, get_all_pos,
|
|
6
|
+
from puzzle_solver.core.utils import Pos, get_all_pos, get_char, in_bounds, Direction, get_next_pos, get_pos
|
|
7
7
|
from puzzle_solver.core.utils_ortools import and_constraint, generic_solve_all, SingleSolution, force_connected_component
|
|
8
|
+
from puzzle_solver.core.utils_visualizer import combined_function
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class Board:
|
|
@@ -98,13 +99,5 @@ class Board:
|
|
|
98
99
|
return SingleSolution(assignment=assignment)
|
|
99
100
|
def callback(single_res: SingleSolution):
|
|
100
101
|
print("Solution found")
|
|
101
|
-
|
|
102
|
-
for pos in get_all_pos(self.V, self.H):
|
|
103
|
-
c = get_char(self.board, pos)
|
|
104
|
-
c = single_res.assignment[pos]
|
|
105
|
-
set_char(res, pos, c)
|
|
106
|
-
print('[')
|
|
107
|
-
for row in res:
|
|
108
|
-
print(" [ '" + "', '".join(row.tolist()) + "' ],")
|
|
109
|
-
print(']')
|
|
102
|
+
print(combined_function(self.V, self.H, is_shaded=lambda r, c: single_res.assignment[get_pos(x=c, y=r)] == 'B'))
|
|
110
103
|
return generic_solve_all(self, board_to_solution, callback=callback if verbose else None, verbose=verbose)
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
puzzle_solver/__init__.py,sha256=j1j97BCo0zoRY1QF6G4248BMWQCYB9TV55hbkbxbDWI,5178
|
|
2
|
-
puzzle_solver/core/utils.py,sha256=XBW5j-IwtJMPMP-ycmY6SqRCM1NOVl5O6UeoGqNj618,8153
|
|
3
|
-
puzzle_solver/core/utils_ortools.py,sha256=ACV3HgKWpEUTt1lpqsPryK1DeZpu7kdWQKEWTLJ2tfs,10384
|
|
4
|
-
puzzle_solver/core/utils_visualizer.py,sha256=ymuhF75uwJbNhN8XVDYEPqw6sPKoqRaaxlhGeHtXpLs,20201
|
|
5
|
-
puzzle_solver/puzzles/aquarium/aquarium.py,sha256=BUfkAS2d9eG3TdMoe1cOGGeNYgKUebRvn-z9nsC9gvE,5708
|
|
6
|
-
puzzle_solver/puzzles/battleships/battleships.py,sha256=RuYCrs4j0vUjlU139NRYYP-uNPAgO0V7hAzbsHrRwD8,7446
|
|
7
|
-
puzzle_solver/puzzles/binairo/binairo.py,sha256=NmVPIoyVCoMLaSFhsN0TcJQYvav9hi4hSwoAVirYhDU,6835
|
|
8
|
-
puzzle_solver/puzzles/binairo/binairo_plus.py,sha256=TvLG3olwANtft3LuCF-y4OofpU9PNa4IXDqgZqsD-g0,267
|
|
9
|
-
puzzle_solver/puzzles/black_box/black_box.py,sha256=EiCVkbhUP0x94otvQirv7MrggTu0ok8MIUPbxv6jkIU,15544
|
|
10
|
-
puzzle_solver/puzzles/bridges/bridges.py,sha256=QwOhZyO5urbatkNyPmQxZ_lGM01ZejndMr_eoiBkr7g,5394
|
|
11
|
-
puzzle_solver/puzzles/chess_range/chess_melee.py,sha256=D-_Oi8OyxsVe1j3dIKYwRlxgeb3NWLmDWGcv-oclY0c,195
|
|
12
|
-
puzzle_solver/puzzles/chess_range/chess_range.py,sha256=_VHlpUPnqeBstvSIt9RtTV-w2etSK7UrEHg6sErNqtU,21068
|
|
13
|
-
puzzle_solver/puzzles/chess_range/chess_solo.py,sha256=ByDfcRsk5FVmFicpU_DpLoLTJ99Kr___vX4y8ln8_EQ,400
|
|
14
|
-
puzzle_solver/puzzles/chess_sequence/chess_sequence.py,sha256=6ap3Wouf2PxHV4P56B9ol1QT98Ym6VHaxorQZWl6LnY,13692
|
|
15
|
-
puzzle_solver/puzzles/connect_the_dots/connect_the_dots.py,sha256=PvxwoIUDHITxo51uD_JGoFcW33vf0YXTsvlm-gUjMNY,2610
|
|
16
|
-
puzzle_solver/puzzles/dominosa/dominosa.py,sha256=Nmb7pn8U27QJwGy9F3wo8ylqo2_U51OAo3GN2soaNpc,7195
|
|
17
|
-
puzzle_solver/puzzles/filling/filling.py,sha256=R8UIbztk3zNCeNbVClBJoKZHKeHwK_pesjGmMaEEQO0,5536
|
|
18
|
-
puzzle_solver/puzzles/flip/flip.py,sha256=ZngJLUhRNc7qqo2wtNLdMPx4u9w9JTUge27PmdXyDCw,3985
|
|
19
|
-
puzzle_solver/puzzles/flood_it/flood_it.py,sha256=jnCtH1sZIt6K4hbQDSsiM1Cd8FjQNP7cfw2ObUW5fEQ,7948
|
|
20
|
-
puzzle_solver/puzzles/flood_it/parse_map/parse_map.py,sha256=m7gcpvN3THZdYLowdR_Jwx3HyttaV4K2DqrX_U7uFqU,8209
|
|
21
|
-
puzzle_solver/puzzles/galaxies/galaxies.py,sha256=CTSCNqRR35QT7qBiYdXYu9GLnDJmI9Cfd4C5t4_Kqhg,5535
|
|
22
|
-
puzzle_solver/puzzles/galaxies/parse_map/parse_map.py,sha256=XmFqVN_oRfq9AZFWy5ViUJ2Szjgx-srrRkFPJXEEyFo,9358
|
|
23
|
-
puzzle_solver/puzzles/guess/guess.py,sha256=MpyrF6YVu0S1fzX-BllwxGKRGacWJpeLbNn5GetuEyo,10792
|
|
24
|
-
puzzle_solver/puzzles/heyawake/heyawake.py,sha256=L_y44dHArOvO_tDyO35dwkvqdk9eEGItO7n4FDfzNDc,5586
|
|
25
|
-
puzzle_solver/puzzles/inertia/inertia.py,sha256=-Y5fr7aK20zwmGHsZql7pYCq1kyMZglvkVZ6uIDf1HA,5658
|
|
26
|
-
puzzle_solver/puzzles/inertia/tsp.py,sha256=mAhlSjCWespASeN8uLZ0JkYDw-ZqFEpal6NM-ubpCXw,15313
|
|
27
|
-
puzzle_solver/puzzles/inertia/parse_map/parse_map.py,sha256=x0d64gTBd0HC2lO5uOpX2VKWfwj8rRiz0mQM_lqNmWs,8457
|
|
28
|
-
puzzle_solver/puzzles/kakurasu/kakurasu.py,sha256=VNGMJnBHDi6WkghLObRLhUvkmrPaGphTTUDMC0TkQvQ,2064
|
|
29
|
-
puzzle_solver/puzzles/kakuro/kakuro.py,sha256=m22Ju-V2BdQl2Ng_pjVUSrxPCtIfqezdpebutURlhvg,4348
|
|
30
|
-
puzzle_solver/puzzles/keen/keen.py,sha256=adSA_pc1m6F6jV7a-PpQxdci1bv4psCNRNt9hMIQdSY,5034
|
|
31
|
-
puzzle_solver/puzzles/light_up/light_up.py,sha256=iSA1rjZMFsnI0V0Nxivxox4qZkB7PvUrROSHXcoUXds,4541
|
|
32
|
-
puzzle_solver/puzzles/lits/lits.py,sha256=-iKgsdfFHA0aOQD8QCjSCXabQaHFaHN5idk6LBvgqRc,7166
|
|
33
|
-
puzzle_solver/puzzles/magnets/magnets.py,sha256=-Wl49JD_PKeq735zQVMQ3XSQX6gdHiY-7PKw-Sh16jw,6474
|
|
34
|
-
puzzle_solver/puzzles/map/map.py,sha256=sxc57tapB8Tsgam-yoDitln1o-EB_SbIYvO6WEYy3us,2582
|
|
35
|
-
puzzle_solver/puzzles/minesweeper/minesweeper.py,sha256=gSdFsuZ-KrwVxgI1HF2q_pYleZ6vBm9jjRTFlboVnLY,5871
|
|
36
|
-
puzzle_solver/puzzles/mosaic/mosaic.py,sha256=QX_nVpVKQg8OfaUcqFk9tKqsDyVqvZc6-XWvfI3YcSw,2175
|
|
37
|
-
puzzle_solver/puzzles/nonograms/nonograms.py,sha256=dTKfMwBL49hW3bNd34ETXW7lBRPuQeSPNSCHqHmfybg,6066
|
|
38
|
-
puzzle_solver/puzzles/norinori/norinori.py,sha256=iwJ2UgQJfx6JLYPQqJHdg1GJ8IBAjMDOtNybhO1jmNc,4968
|
|
39
|
-
puzzle_solver/puzzles/nurikabe/nurikabe.py,sha256=3cbW7X4kAMQK8PkH_t65fzT5cI0O6tWWOqpQUVyuGT4,6501
|
|
40
|
-
puzzle_solver/puzzles/palisade/palisade.py,sha256=T-LXlaLU5OwUQ24QWJWhBUFUktg0qDODTilNmBaXs4I,5014
|
|
41
|
-
puzzle_solver/puzzles/pearl/pearl.py,sha256=OhzpMYpxqvR3GCd5NH4ETT0NO4X753kRi6p5omYLChM,6798
|
|
42
|
-
puzzle_solver/puzzles/pipes/pipes.py,sha256=SPPgmYXeqjdzijLqdIb_TtlGmxzIad6MHQ31pyDcgUc,4448
|
|
43
|
-
puzzle_solver/puzzles/range/range.py,sha256=q0J3crlGfjYZSA6Dh4iMCwP_gRMWid-_8KPgggOrFKk,4410
|
|
44
|
-
puzzle_solver/puzzles/rectangles/rectangles.py,sha256=MgOhZJGr9DVHb9bB8EAuwus0_8frBqRWqMwrOvMezHQ,6918
|
|
45
|
-
puzzle_solver/puzzles/shakashaka/shakashaka.py,sha256=PRpg_qI7XA3ysAo_g1TRJsT3VwB5Vial2UcFyBOMwKQ,9571
|
|
46
|
-
puzzle_solver/puzzles/shingoki/shingoki.py,sha256=heMuL9sm3jBegItjnqX05ttmDNiHSLB77BRljpeLLWk,7417
|
|
47
|
-
puzzle_solver/puzzles/signpost/signpost.py,sha256=38LlMvP5Fx4qrTXmw4aNCt3yUbG3fhdSk6-YXmhAHFg,3861
|
|
48
|
-
puzzle_solver/puzzles/singles/singles.py,sha256=KKn_Yl-eW874Bl1UmmcqoQ5vhNiO1JbM7fxKczOV5M4,2847
|
|
49
|
-
puzzle_solver/puzzles/slant/slant.py,sha256=xF-N4PuXYfx638NP1f1mi6YncIZB4mLtXtdS79XyPbg,6122
|
|
50
|
-
puzzle_solver/puzzles/slant/parse_map/parse_map.py,sha256=8thQxWbq0qjehKb2VzgUP22PGj-9n9djwbt3LGMVLJw,4811
|
|
51
|
-
puzzle_solver/puzzles/slitherlink/slitherlink.py,sha256=JpyNQk8K4nUziwWKxSvWEkF1RRBGLnCppCWK1Yf5bt0,7052
|
|
52
|
-
puzzle_solver/puzzles/star_battle/star_battle.py,sha256=hFV5IKPQDWrIWr50YpiOS9VF2kUScDQpvAGvZKBwuyM,3937
|
|
53
|
-
puzzle_solver/puzzles/star_battle/star_battle_shapeless.py,sha256=lj05V0Y3A3NjMo1boMkPIwBhMtm6SWydjgAMeCf5EIo,225
|
|
54
|
-
puzzle_solver/puzzles/stitches/stitches.py,sha256=bb5JXyclkbKq350MQ9d8AuGteQwSF8knaJ0DU9M92Uw,6515
|
|
55
|
-
puzzle_solver/puzzles/stitches/parse_map/parse_map.py,sha256=b21SQvlnDM6wOl_1iUhZ7X6akpBZoOnj3kEzImBCh8Q,10497
|
|
56
|
-
puzzle_solver/puzzles/sudoku/sudoku.py,sha256=rLq0N34v3Hb10CiptXtKxX-37OlQIyjIle9Es1FAtpM,13378
|
|
57
|
-
puzzle_solver/puzzles/tapa/tapa.py,sha256=TsOQhnEvlC1JxaWiEjQg2KxRXJR49GrN71DsMvPpia8,5337
|
|
58
|
-
puzzle_solver/puzzles/tents/tents.py,sha256=jccUXWA7KWAtPKpVJJYNI6masTYWQgx0eitcQw0-6Fc,6281
|
|
59
|
-
puzzle_solver/puzzles/thermometers/thermometers.py,sha256=bGcVmpPeqL5AJtj8jkK8gYThzv9aGCd_QrWEiYBCA2s,4011
|
|
60
|
-
puzzle_solver/puzzles/towers/towers.py,sha256=OLyTf9nTFR5L32-S_fhVyBmpz4i5YUNJotwOwbw_Fjg,6500
|
|
61
|
-
puzzle_solver/puzzles/tracks/tracks.py,sha256=98xds9SKNqtOLFTRUX_KSMC7XYmZo567LOFeqotVQaM,7237
|
|
62
|
-
puzzle_solver/puzzles/twiddle/twiddle.py,sha256=3gPoeD0DoiiZbIhtptdXFldO_t1QShL6IxkDqJMzjkk,5446
|
|
63
|
-
puzzle_solver/puzzles/undead/undead.py,sha256=IGFQysgoaKZH8rKjqlrkoHsH28ve4_hKor2f0QOsWY0,6596
|
|
64
|
-
puzzle_solver/puzzles/unequal/unequal.py,sha256=ExY2XDCrqROCDpRLfHo8uVr1zuli1QvbCdNCiDhlCac,6978
|
|
65
|
-
puzzle_solver/puzzles/unruly/unruly.py,sha256=xwOUpC12uHbmlDj2guN60VaaHpLr1Y-WmMD5TKeHbZE,3826
|
|
66
|
-
puzzle_solver/puzzles/yin_yang/yin_yang.py,sha256=5WixT_7K1HwfQ_dWbuBlQfpU8p69zB2KvOg32XJ8vno,5255
|
|
67
|
-
puzzle_solver/puzzles/yin_yang/parse_map/parse_map.py,sha256=drjfoHqmFf6U-ZQUwrBbfGINRxDQpgbvy4U3D9QyMhM,6617
|
|
68
|
-
puzzle_solver/utils/visualizer.py,sha256=T2g5We9J3tkhyXWoN2OrIDIJDjt6w5sDd2ksOub0ZI8,6819
|
|
69
|
-
multi_puzzle_solver-1.0.4.dist-info/METADATA,sha256=JSM2UZgGRSx0oipFuvGnNmKLfXWWfZGxgVWHNtWIH3I,372540
|
|
70
|
-
multi_puzzle_solver-1.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
71
|
-
multi_puzzle_solver-1.0.4.dist-info/top_level.txt,sha256=exwVUQa-anK9vYrpKzBPvH8bX43iElWI4VeNiAyBGJY,14
|
|
72
|
-
multi_puzzle_solver-1.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|