-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path101-nqueens.py
142 lines (119 loc) · 3.85 KB
/
101-nqueens.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
#!/usr/bin/python3
"""Solves the N-queens puzzle.
Determines all possible solutions to placing N
N non-attacking queens on an NxN chessboard.
Example:
$ ./101-nqueens.py N
N must be an integer greater than or equal to 4.
Attributes:
board (list): A list of lists representing the chessboard.
solutions (list): A list of lists containing solutions.
Solutions are represented in the format [[r, c], [r, c], [r, c], [r, c]]
where `r` and `c` represent the row and column, respectively, where a
queen must be placed on the chessboard.
"""
import sys
def init_board(n):
"""Initialize an `n`x`n` sized chessboard with 0's."""
board = []
[board.append([]) for i in range(n)]
[row.append(' ') for i in range(n) for row in board]
return (board)
def board_deepcopy(board):
"""Return a deepcopy of a chessboard."""
if isinstance(board, list):
return list(map(board_deepcopy, board))
return (board)
def get_solution(board):
"""Return the list of lists representation of a solved chessboard."""
solution = []
for r in range(len(board)):
for c in range(len(board)):
if board[r][c] == "Q":
solution.append([r, c])
break
return (solution)
def xout(board, row, col):
"""X out spots on a chessboard.
All spots where non-attacking queens can no
longer be played are X-ed out.
Args:
board (list): The current working chessboard.
row (int): The row where a queen was last played.
col (int): The column where a queen was last played.
"""
# X out all forward spots
for c in range(col + 1, len(board)):
board[row][c] = "x"
# X out all backwards spots
for c in range(col - 1, -1, -1):
board[row][c] = "x"
# X out all spots below
for r in range(row + 1, len(board)):
board[r][col] = "x"
# X out all spots above
for r in range(row - 1, -1, -1):
board[r][col] = "x"
# X out all spots diagonally down to the right
c = col + 1
for r in range(row + 1, len(board)):
if c >= len(board):
break
board[r][c] = "x"
c += 1
# X out all spots diagonally up to the left
c = col - 1
for r in range(row - 1, -1, -1):
if c < 0:
break
board[r][c]
c -= 1
# X out all spots diagonally up to the right
c = col + 1
for r in range(row - 1, -1, -1):
if c >= len(board):
break
board[r][c] = "x"
c += 1
# X out all spots diagonally down to the left
c = col - 1
for r in range(row + 1, len(board)):
if c < 0:
break
board[r][c] = "x"
c -= 1
def recursive_solve(board, row, queens, solutions):
"""Recursively solve an N-queens puzzle.
Args:
board (list): The current working chessboard.
row (int): The current working row.
queens (int): The current number of placed queens.
solutions (list): A list of lists of solutions.
Returns:
solutions
"""
if queens == len(board):
solutions.append(get_solution(board))
return (solutions)
for c in range(len(board)):
if board[row][c] == " ":
tmp_board = board_deepcopy(board)
tmp_board[row][c] = "Q"
xout(tmp_board, row, c)
solutions = recursive_solve(tmp_board, row + 1,
queens + 1, solutions)
return (solutions)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: nqueens N")
sys.exit(1)
if sys.argv[1].isdigit() is False:
print("N must be a number")
sys.exit(1)
if int(sys.argv[1]) < 4:
print("N must be at least 4")
sys.exit(1)
board = init_board(int(sys.argv[1]))
solutions = recursive_solve(board, 0, 0, [])
for sol in solutions:
print(sol)