1
- /*
2
- The N-Queens problem is a classic chessboard puzzle where the goal is to
3
- place N queens on an N×N chessboard so that no two queens threaten each
4
- other. Queens can attack each other if they share the same row, column, or
5
- diagonal.
6
-
7
- We solve this problem using a backtracking algorithm. We start with an empty
8
- chessboard and iteratively try to place queens in different rows, ensuring
9
- they do not conflict with each other. If a valid solution is found, it's added
10
- to the list of solutions.
11
-
12
- Time Complexity: O(N!), where N is the size of the chessboard.
13
-
14
- nqueens_solver(4) => Returns two solutions:
15
- Solution 1:
16
- [
17
- ".Q..",
18
- "...Q",
19
- "Q...",
20
- "..Q."
21
- ]
22
-
23
- Solution 2:
24
- [
25
- "..Q.",
26
- "Q...",
27
- "...Q",
28
- ".Q.."
29
- ]
30
- */
31
-
1
+ //! This module provides functionality to solve the N-Queens problem.
2
+ //!
3
+ //! The N-Queens problem is a classic chessboard puzzle where the goal is to
4
+ //! place N queens on an NxN chessboard so that no two queens threaten each
5
+ //! other. Queens can attack each other if they share the same row, column, or
6
+ //! diagonal.
7
+ //!
8
+ //! This implementation solves the N-Queens problem using a backtracking algorithm.
9
+ //! It starts with an empty chessboard and iteratively tries to place queens in
10
+ //! different rows, ensuring they do not conflict with each other. If a valid
11
+ //! solution is found, it's added to the list of solutions.
12
+
13
+ /// Solves the N-Queens problem for a given size and returns a vector of solutions.
14
+ ///
15
+ /// # Arguments
16
+ ///
17
+ /// * `n` - The size of the chessboard (NxN).
18
+ ///
19
+ /// # Returns
20
+ ///
21
+ /// A vector containing all solutions to the N-Queens problem.
32
22
pub fn n_queens_solver ( n : usize ) -> Vec < Vec < String > > {
33
- let mut board = vec ! [ vec![ '.' ; n] ; n] ;
34
- let mut solutions = Vec :: new ( ) ;
35
- solve ( & mut board, 0 , & mut solutions) ;
36
- solutions
23
+ let mut solver = NQueensSolver :: new ( n) ;
24
+ solver. solve ( )
25
+ }
26
+
27
+ /// Represents a solver for the N-Queens problem.
28
+ struct NQueensSolver {
29
+ // The size of the chessboard
30
+ size : usize ,
31
+ // A 2D vector representing the chessboard where '.' denotes an empty space and 'Q' denotes a queen
32
+ board : Vec < Vec < char > > ,
33
+ // A vector to store all valid solutions
34
+ solutions : Vec < Vec < String > > ,
37
35
}
38
36
39
- fn is_safe ( board : & [ Vec < char > ] , row : usize , col : usize ) -> bool {
40
- // Check if there is a queen in the same column
41
- for ( i, _) in board. iter ( ) . take ( row) . enumerate ( ) {
42
- if board[ i] [ col] == 'Q' {
43
- return false ;
37
+ impl NQueensSolver {
38
+ /// Creates a new `NQueensSolver` instance with the given size.
39
+ ///
40
+ /// # Arguments
41
+ ///
42
+ /// * `size` - The size of the chessboard (N×N).
43
+ ///
44
+ /// # Returns
45
+ ///
46
+ /// A new `NQueensSolver` instance.
47
+ fn new ( size : usize ) -> Self {
48
+ NQueensSolver {
49
+ size,
50
+ board : vec ! [ vec![ '.' ; size] ; size] ,
51
+ solutions : Vec :: new ( ) ,
44
52
}
45
53
}
46
54
47
- // Check if there is a queen in the left upper diagonal
48
- for i in ( 0 ..row) . rev ( ) {
49
- let j = col as isize - ( row as isize - i as isize ) ;
50
- if j >= 0 && board[ i] [ j as usize ] == 'Q' {
51
- return false ;
52
- }
55
+ /// Solves the N-Queens problem and returns a vector of solutions.
56
+ ///
57
+ /// # Returns
58
+ ///
59
+ /// A vector containing all solutions to the N-Queens problem.
60
+ fn solve ( & mut self ) -> Vec < Vec < String > > {
61
+ self . solve_helper ( 0 ) ;
62
+ std:: mem:: take ( & mut self . solutions )
53
63
}
54
64
55
- // Check if there is a queen in the right upper diagonal
56
- for i in ( 0 ..row) . rev ( ) {
57
- let j = col + row - i;
58
- if j < board. len ( ) && board[ i] [ j] == 'Q' {
59
- return false ;
65
+ /// Checks if it's safe to place a queen at the specified position (row, col).
66
+ ///
67
+ /// # Arguments
68
+ ///
69
+ /// * `row` - The row index of the position to check.
70
+ /// * `col` - The column index of the position to check.
71
+ ///
72
+ /// # Returns
73
+ ///
74
+ /// `true` if it's safe to place a queen at the specified position, `false` otherwise.
75
+ fn is_safe ( & self , row : usize , col : usize ) -> bool {
76
+ // Check column and diagonals
77
+ for i in 0 ..row {
78
+ if self . board [ i] [ col] == 'Q'
79
+ || ( col >= row - i && self . board [ i] [ col - ( row - i) ] == 'Q' )
80
+ || ( col + row - i < self . size && self . board [ i] [ col + ( row - i) ] == 'Q' )
81
+ {
82
+ return false ;
83
+ }
60
84
}
85
+ true
61
86
}
62
87
63
- true
64
- }
65
-
66
- fn solve ( board : & mut Vec < Vec < char > > , row : usize , solutions : & mut Vec < Vec < String > > ) {
67
- let n = board. len ( ) ;
68
- if row == n {
69
- let solution: Vec < String > = board. iter ( ) . map ( |row| row. iter ( ) . collect ( ) ) . collect ( ) ;
70
- solutions. push ( solution) ;
71
- return ;
72
- }
88
+ /// Recursive helper function to solve the N-Queens problem.
89
+ ///
90
+ /// # Arguments
91
+ ///
92
+ /// * `row` - The current row being processed.
93
+ fn solve_helper ( & mut self , row : usize ) {
94
+ if row == self . size {
95
+ self . solutions
96
+ . push ( self . board . iter ( ) . map ( |row| row. iter ( ) . collect ( ) ) . collect ( ) ) ;
97
+ return ;
98
+ }
73
99
74
- for col in 0 ..n {
75
- if is_safe ( board, row, col) {
76
- board[ row] [ col] = 'Q' ;
77
- solve ( board, row + 1 , solutions) ;
78
- board[ row] [ col] = '.' ;
100
+ for col in 0 ..self . size {
101
+ if self . is_safe ( row, col) {
102
+ self . board [ row] [ col] = 'Q' ;
103
+ self . solve_helper ( row + 1 ) ;
104
+ self . board [ row] [ col] = '.' ;
105
+ }
79
106
}
80
107
}
81
108
}
@@ -84,17 +111,111 @@ fn solve(board: &mut Vec<Vec<char>>, row: usize, solutions: &mut Vec<Vec<String>
84
111
mod tests {
85
112
use super :: * ;
86
113
87
- #[ test]
88
- fn test_n_queens_solver ( ) {
89
- // Test case: Solve the 4-Queens problem
90
- let solutions = n_queens_solver ( 4 ) ;
91
-
92
- assert_eq ! ( solutions. len( ) , 2 ) ; // There are two solutions for the 4-Queens problem
93
-
94
- // Verify the first solution
95
- assert_eq ! ( solutions[ 0 ] , vec![ ".Q.." , "...Q" , "Q..." , "..Q." ] ) ;
114
+ macro_rules! test_n_queens_solver {
115
+ ( $( $name: ident: $tc: expr, ) * ) => {
116
+ $(
117
+ #[ test]
118
+ fn $name( ) {
119
+ let ( n, expected_solutions) = $tc;
120
+ let solutions = n_queens_solver( n) ;
121
+ assert_eq!( solutions, expected_solutions) ;
122
+ }
123
+ ) *
124
+ } ;
125
+ }
96
126
97
- // Verify the second solution
98
- assert_eq ! ( solutions[ 1 ] , vec![ "..Q." , "Q..." , "...Q" , ".Q.." ] ) ;
127
+ test_n_queens_solver ! {
128
+ test_0_queens: ( 0 , vec![ Vec :: <String >:: new( ) ] ) ,
129
+ test_1_queen: ( 1 , vec![ vec![ "Q" ] ] ) ,
130
+ test_2_queens: ( 2 , Vec :: <Vec <String >>:: new( ) ) ,
131
+ test_3_queens: ( 3 , Vec :: <Vec <String >>:: new( ) ) ,
132
+ test_4_queens: ( 4 , vec![
133
+ vec![ ".Q.." ,
134
+ "...Q" ,
135
+ "Q..." ,
136
+ "..Q." ] ,
137
+ vec![ "..Q." ,
138
+ "Q..." ,
139
+ "...Q" ,
140
+ ".Q.." ] ,
141
+ ] ) ,
142
+ test_5_queens: ( 5 , vec![
143
+ vec![ "Q...." ,
144
+ "..Q.." ,
145
+ "....Q" ,
146
+ ".Q..." ,
147
+ "...Q." ] ,
148
+ vec![ "Q...." ,
149
+ "...Q." ,
150
+ ".Q..." ,
151
+ "....Q" ,
152
+ "..Q.." ] ,
153
+ vec![ ".Q..." ,
154
+ "...Q." ,
155
+ "Q...." ,
156
+ "..Q.." ,
157
+ "....Q" ] ,
158
+ vec![ ".Q..." ,
159
+ "....Q" ,
160
+ "..Q.." ,
161
+ "Q...." ,
162
+ "...Q." ] ,
163
+ vec![ "..Q.." ,
164
+ "Q...." ,
165
+ "...Q." ,
166
+ ".Q..." ,
167
+ "....Q" ] ,
168
+ vec![ "..Q.." ,
169
+ "....Q" ,
170
+ ".Q..." ,
171
+ "...Q." ,
172
+ "Q...." ] ,
173
+ vec![ "...Q." ,
174
+ "Q...." ,
175
+ "..Q.." ,
176
+ "....Q" ,
177
+ ".Q..." ] ,
178
+ vec![ "...Q." ,
179
+ ".Q..." ,
180
+ "....Q" ,
181
+ "..Q.." ,
182
+ "Q...." ] ,
183
+ vec![ "....Q" ,
184
+ ".Q..." ,
185
+ "...Q." ,
186
+ "Q...." ,
187
+ "..Q.." ] ,
188
+ vec![ "....Q" ,
189
+ "..Q.." ,
190
+ "Q...." ,
191
+ "...Q." ,
192
+ ".Q..." ] ,
193
+ ] ) ,
194
+ test_6_queens: ( 6 , vec![
195
+ vec![ ".Q...." ,
196
+ "...Q.." ,
197
+ ".....Q" ,
198
+ "Q....." ,
199
+ "..Q..." ,
200
+ "....Q." ] ,
201
+ vec![ "..Q..." ,
202
+ ".....Q" ,
203
+ ".Q...." ,
204
+ "....Q." ,
205
+ "Q....." ,
206
+ "...Q.." ] ,
207
+ vec![ "...Q.." ,
208
+ "Q....." ,
209
+ "....Q." ,
210
+ ".Q...." ,
211
+ ".....Q" ,
212
+ "..Q..." ] ,
213
+ vec![ "....Q." ,
214
+ "..Q..." ,
215
+ "Q....." ,
216
+ ".....Q" ,
217
+ "...Q.." ,
218
+ ".Q...." ] ,
219
+ ] ) ,
99
220
}
100
221
}
0 commit comments