Skip to content

Commit 05c14c6

Browse files
DavidBandacclauss
andauthored
N queens math (TheAlgorithms#2175)
* add new file for another solution to the n queens problem * Add the code for the algorithm, add comments and add at the top a general explanation * Update backtracking/n_queens_math.py Co-authored-by: Christian Clauss <cclauss@me.com> * Update backtracking/n_queens_math.py Co-authored-by: Christian Clauss <cclauss@me.com> * Update backtracking/n_queens_math.py Co-authored-by: Christian Clauss <cclauss@me.com> * Update backtracking/n_queens_math.py Co-authored-by: Christian Clauss <cclauss@me.com> * No newline at the end of the file * Type hints * whitespaces fixed * Fixed whitespaces * Add type hints * CodeSpell fixed * update * All changes made except changing the board variable to local * Add doctest * Update * Update * Update * Update n_queens_math.py Co-authored-by: Christian Clauss <cclauss@me.com>
1 parent b6ca263 commit 05c14c6

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed

backtracking/n_queens_math.py

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
r"""
2+
Problem:
3+
4+
The n queens problem is of placing N queens on a N * N chess board such that no queen
5+
can attack any other queens placed on that chess board. This means that one queen
6+
cannot have any other queen on its horizontal, vertical and diagonal lines.
7+
8+
Solution:
9+
10+
To solve this problem we will use simple math. First we know the queen can move in all
11+
the possible ways, we can simplify it in this: vertical, horizontal, diagonal left and
12+
diagonal right.
13+
14+
We can visualize it like this:
15+
16+
left diagonal = \
17+
right diagonal = /
18+
19+
On a chessboard vertical movement could be the rows and horizontal movement could be
20+
the columns.
21+
22+
In programming we can use an array, and in this array each index could be the rows and
23+
each value in the array could be the column. For example:
24+
25+
. Q . . We have this chessboard with one queen in each column and each queen
26+
. . . Q can't attack to each other.
27+
Q . . . The array for this example would look like this: [1, 3, 0, 2]
28+
. . Q .
29+
30+
So if we use an array and we verify that each value in the array is different to each
31+
other we know that at least the queens can't attack each other in horizontal and
32+
vertical.
33+
34+
At this point we have that halfway completed and we will treat the chessboard as a
35+
Cartesian plane. Hereinafter we are going to remember basic math, so in the school we
36+
learned this formula:
37+
38+
Slope of a line:
39+
40+
y2 - y1
41+
m = ----------
42+
x2 - x1
43+
44+
This formula allow us to get the slope. For the angles 45º (right diagonal) and 135º
45+
(left diagonal) this formula gives us m = 1, and m = -1 respectively.
46+
47+
See::
48+
https://www.enotes.com/homework-help/write-equation-line-that-hits-origin-45-degree-1474860
49+
50+
Then we have this another formula:
51+
52+
Slope intercept:
53+
54+
y = mx + b
55+
56+
b is where the line crosses the Y axis (to get more information see:
57+
https://www.mathsisfun.com/y_intercept.html), if we change the formula to solve for b
58+
we would have:
59+
60+
y - mx = b
61+
62+
And like we already have the m values for the angles 45º and 135º, this formula would
63+
look like this:
64+
65+
45º: y - (1)x = b
66+
45º: y - x = b
67+
68+
135º: y - (-1)x = b
69+
135º: y + x = b
70+
71+
y = row
72+
x = column
73+
74+
Applying this two formulas we can check if a queen in some position is being attacked
75+
for another one or vice versa.
76+
77+
"""
78+
from typing import List
79+
80+
81+
def depth_first_search(
82+
possible_board: List[int],
83+
diagonal_right_collisions: List[int],
84+
diagonal_left_collisions: List[int],
85+
boards: List[List[str]],
86+
n: int,
87+
) -> None:
88+
"""
89+
>>> boards = []
90+
>>> depth_first_search([], [], [], boards, 4)
91+
>>> for board in boards:
92+
... print(board)
93+
['. Q . . ', '. . . Q ', 'Q . . . ', '. . Q . ']
94+
['. . Q . ', 'Q . . . ', '. . . Q ', '. Q . . ']
95+
"""
96+
97+
""" Get next row in the current board (possible_board) to fill it with a queen """
98+
row = len(possible_board)
99+
100+
"""
101+
If row is equal to the size of the board it means there are a queen in each row in
102+
the current board (possible_board)
103+
"""
104+
if row == n:
105+
"""
106+
We convert the variable possible_board that looks like this: [1, 3, 0, 2] to
107+
this: ['. Q . . ', '. . . Q ', 'Q . . . ', '. . Q . ']
108+
"""
109+
possible_board = [". " * i + "Q " + ". " * (n - 1 - i) for i in possible_board]
110+
boards.append(possible_board)
111+
return
112+
113+
""" We iterate each column in the row to find all possible results in each row """
114+
for col in range(n):
115+
116+
"""
117+
We apply that we learned previously. First we check that in the current board
118+
(possible_board) there are not other same value because if there is it means
119+
that there are a collision in vertical. Then we apply the two formulas we
120+
learned before:
121+
122+
45º: y - x = b or 45: row - col = b
123+
135º: y + x = b or row + col = b.
124+
125+
And we verify if the results of this two formulas not exist in their variables
126+
respectively. (diagonal_right_collisions, diagonal_left_collisions)
127+
128+
If any or these are True it means there is a collision so we continue to the
129+
next value in the for loop.
130+
"""
131+
if (
132+
col in possible_board
133+
or row - col in diagonal_right_collisions
134+
or row + col in diagonal_left_collisions
135+
):
136+
continue
137+
138+
""" If it is False we call dfs function again and we update the inputs """
139+
depth_first_search(
140+
possible_board + [col],
141+
diagonal_right_collisions + [row - col],
142+
diagonal_left_collisions + [row + col],
143+
boards,
144+
n,
145+
)
146+
147+
148+
def n_queens_solution(n: int) -> None:
149+
boards = []
150+
depth_first_search([], [], [], boards, n)
151+
152+
""" Print all the boards """
153+
for board in boards:
154+
for column in board:
155+
print(column)
156+
print("")
157+
158+
print(len(boards), "solutions were found.")
159+
160+
161+
if __name__ == "__main__":
162+
import doctest
163+
164+
doctest.testmod()
165+
n_queens_solution(4)

0 commit comments

Comments
 (0)