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.
3222pub 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 > > ,
3735}
3836
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 ( ) ,
4452 }
4553 }
4654
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 )
5363 }
5464
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+ }
6084 }
85+ true
6186 }
6287
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+ }
7399
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+ }
79106 }
80107 }
81108}
@@ -84,17 +111,111 @@ fn solve(board: &mut Vec<Vec<char>>, row: usize, solutions: &mut Vec<Vec<String>
84111mod tests {
85112 use super :: * ;
86113
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+ }
96126
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+ ] ) ,
99220 }
100221}
0 commit comments