-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
Copy pathn_queens.rs
221 lines (211 loc) · 6.25 KB
/
n_queens.rs
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! This module provides functionality to solve the N-Queens problem.
//!
//! The N-Queens problem is a classic chessboard puzzle where the goal is to
//! place N queens on an NxN chessboard so that no two queens threaten each
//! other. Queens can attack each other if they share the same row, column, or
//! diagonal.
//!
//! This implementation solves the N-Queens problem using a backtracking algorithm.
//! It starts with an empty chessboard and iteratively tries to place queens in
//! different rows, ensuring they do not conflict with each other. If a valid
//! solution is found, it's added to the list of solutions.
/// Solves the N-Queens problem for a given size and returns a vector of solutions.
///
/// # Arguments
///
/// * `n` - The size of the chessboard (NxN).
///
/// # Returns
///
/// A vector containing all solutions to the N-Queens problem.
pub fn n_queens_solver(n: usize) -> Vec<Vec<String>> {
let mut solver = NQueensSolver::new(n);
solver.solve()
}
/// Represents a solver for the N-Queens problem.
struct NQueensSolver {
// The size of the chessboard
size: usize,
// A 2D vector representing the chessboard where '.' denotes an empty space and 'Q' denotes a queen
board: Vec<Vec<char>>,
// A vector to store all valid solutions
solutions: Vec<Vec<String>>,
}
impl NQueensSolver {
/// Creates a new `NQueensSolver` instance with the given size.
///
/// # Arguments
///
/// * `size` - The size of the chessboard (N×N).
///
/// # Returns
///
/// A new `NQueensSolver` instance.
fn new(size: usize) -> Self {
NQueensSolver {
size,
board: vec![vec!['.'; size]; size],
solutions: Vec::new(),
}
}
/// Solves the N-Queens problem and returns a vector of solutions.
///
/// # Returns
///
/// A vector containing all solutions to the N-Queens problem.
fn solve(&mut self) -> Vec<Vec<String>> {
self.solve_helper(0);
std::mem::take(&mut self.solutions)
}
/// Checks if it's safe to place a queen at the specified position (row, col).
///
/// # Arguments
///
/// * `row` - The row index of the position to check.
/// * `col` - The column index of the position to check.
///
/// # Returns
///
/// `true` if it's safe to place a queen at the specified position, `false` otherwise.
fn is_safe(&self, row: usize, col: usize) -> bool {
// Check column and diagonals
for i in 0..row {
if self.board[i][col] == 'Q'
|| (col >= row - i && self.board[i][col - (row - i)] == 'Q')
|| (col + row - i < self.size && self.board[i][col + (row - i)] == 'Q')
{
return false;
}
}
true
}
/// Recursive helper function to solve the N-Queens problem.
///
/// # Arguments
///
/// * `row` - The current row being processed.
fn solve_helper(&mut self, row: usize) {
if row == self.size {
self.solutions
.push(self.board.iter().map(|row| row.iter().collect()).collect());
return;
}
for col in 0..self.size {
if self.is_safe(row, col) {
self.board[row][col] = 'Q';
self.solve_helper(row + 1);
self.board[row][col] = '.';
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! test_n_queens_solver {
($($name:ident: $tc:expr,)*) => {
$(
#[test]
fn $name() {
let (n, expected_solutions) = $tc;
let solutions = n_queens_solver(n);
assert_eq!(solutions, expected_solutions);
}
)*
};
}
test_n_queens_solver! {
test_0_queens: (0, vec![Vec::<String>::new()]),
test_1_queen: (1, vec![vec!["Q"]]),
test_2_queens:(2, Vec::<Vec<String>>::new()),
test_3_queens:(3, Vec::<Vec<String>>::new()),
test_4_queens: (4, vec![
vec![".Q..",
"...Q",
"Q...",
"..Q."],
vec!["..Q.",
"Q...",
"...Q",
".Q.."],
]),
test_5_queens:(5, vec![
vec!["Q....",
"..Q..",
"....Q",
".Q...",
"...Q."],
vec!["Q....",
"...Q.",
".Q...",
"....Q",
"..Q.."],
vec![".Q...",
"...Q.",
"Q....",
"..Q..",
"....Q"],
vec![".Q...",
"....Q",
"..Q..",
"Q....",
"...Q."],
vec!["..Q..",
"Q....",
"...Q.",
".Q...",
"....Q"],
vec!["..Q..",
"....Q",
".Q...",
"...Q.",
"Q...."],
vec!["...Q.",
"Q....",
"..Q..",
"....Q",
".Q..."],
vec!["...Q.",
".Q...",
"....Q",
"..Q..",
"Q...."],
vec!["....Q",
".Q...",
"...Q.",
"Q....",
"..Q.."],
vec!["....Q",
"..Q..",
"Q....",
"...Q.",
".Q..."],
]),
test_6_queens: (6, vec![
vec![".Q....",
"...Q..",
".....Q",
"Q.....",
"..Q...",
"....Q."],
vec!["..Q...",
".....Q",
".Q....",
"....Q.",
"Q.....",
"...Q.."],
vec!["...Q..",
"Q.....",
"....Q.",
".Q....",
".....Q",
"..Q..."],
vec!["....Q.",
"..Q...",
"Q.....",
".....Q",
"...Q..",
".Q...."],
]),
}
}