-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQueens.py
155 lines (127 loc) · 4.06 KB
/
Queens.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
143
144
145
146
147
148
149
150
151
152
153
154
155
from itertools import product
from AlgorithmX import *
def solve_queens(grid):
"""
A n-Queens solver using Algorithm X.
https://en.wikipedia.org/wiki/Eight_queens_puzzle
:param grid:
:return:
"""
rows, columns = len(grid), len(grid[0])
N = rows # the grid should be square
'''X is our universe - as a list'''
X = ([("r", r) for r in range(N)] + # each row in the grid
[("c", c) for c in range(N)] + # each column in the grid
[("rd", rd, SECONDARY) for rd in right_diagonal_set(N)] + # each right diagonal in the grid
[("ld", ld, SECONDARY) for ld in left_diagonal_set(N)]) # each left diagonal in the grid
# There are probably more diagonals than there are Queens to cover them all, so those are secondary
Y = dict()
'''
Y separates our universe into subsets
where (row, column) covers
- row
- column
- right_diagonal
- left_diagonal
'''
for r, c in product(range(N), range(N)):
Y[(r, c, "Q")] = [("r", r), ("c", c)]
# Every row and column has to be covered by a Queen
rd_moves = right_diagonal((r, c), N)
if rd_moves:
Y[(r, c, "Q")].append(("rd", rd_moves[0], SECONDARY))
ld_moves = left_diagonal((r, c), N)
if ld_moves:
Y[(r, c, "Q")].append(("ld", ld_moves[0], SECONDARY))
X, Y = exact_cover(X, Y)
'''Select the known elements of the puzzle grid'''
for i, row in enumerate(grid):
for j, p in enumerate(row):
if p != "":
select(X, Y, (i, j, p))
for solution in solve(X, Y, []):
for r, c in product(range(N), range(N)):
grid[r][c] = ""
for p in ("Q", "B", "R", "K"):
if (r, c, p) in solution:
grid[r][c] = p
yield grid
def queen_moves(rc, N):
return row_move(rc, N) + column_move(rc, N) + diagonal_move(rc, N)
def row_move(rc, N):
moves = list()
for i, j in [(1, 0), (-1, 0)]:
r = rc[0] + i
c = rc[1] + j
while (0 <= r < N) and (0 <= c < N):
moves.append((r, c))
r += i
c += j
return moves
def column_move(rc, N):
moves = list()
for i, j in [(0, 1), (0, -1)]:
r = rc[0] + i
c = rc[1] + j
while (0 <= r < N) and (0 <= c < N):
moves.append((r, c))
r += i
c += j
return moves
def diagonal_move(rc, N):
return right_diagonal(rc, N) + left_diagonal(rc, N)
def right_diagonal(rc, N):
moves = list()
for i, j in [(1, 1), (-1, -1)]:
r = rc[0] + i
c = rc[1] + j
while (0 <= r < N) and (0 <= c < N):
moves.append((r, c))
r += i
c += j
if moves:
moves.append(rc)
return sorted(moves)
def left_diagonal(rc, N):
moves = list()
for i, j in [(1, -1), (-1, 1)]:
r = rc[0] + i
c = rc[1] + j
while (0 <= r < N) and (0 <= c < N):
moves.append((r, c))
r += i
c += j
if moves:
moves.append(rc)
return sorted(moves)
def right_diagonal_set(N):
rd = set()
for rc in product(range(N), range(N)):
rd_moves = right_diagonal(rc, N)
if rd_moves:
rd.add(rd_moves[0])
return sorted(list(rd))
def left_diagonal_set(N):
ld = set()
for rc in product(range(N), range(N)):
ld_moves = left_diagonal(rc, N)
if ld_moves:
ld.add(ld_moves[0])
return sorted(list(ld))
if __name__ == "__main__":
puzzle = [
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", ""]]
count = 0
for sol in solve_queens(puzzle):
count += 1
for line in sol:
print(line)
print()
print("%s solutions found" % count)