dlx_rs/
queens.rs

1use crate::Solver;
2
3/// Implements solution to the N queens problem
4///
5/// ```
6///# use dlx_rs::queens::Queens;
7/// let n_queens_solutions = vec![0,1,0,0,2,10,4,40,92,352,724];
8/// for i in 1..=10 {
9///     let qi = Queens::new(i);
10///     assert_eq!(qi.count(), n_queens_solutions[i]);
11/// }
12/// ```
13pub struct Queens {
14    n: usize,
15    solver: Solver<String>,
16}
17
18impl Queens {
19    /// Creates new `Queens` set up with constraints for the `n` queens problem
20    pub fn new(n: usize) -> Queens {
21        // Create blank solver
22
23        // Add constraints
24
25        // What are the constraints?
26        // We are putting N queens on an NxN chess board
27
28        // 1. Each of the N columns must have exactly 1 queen on it
29        // 2. Each of the N rows must have exactly 1 queen on it
30        // 3. Each of the 2*N-1 right diagonals may have at most one queen
31        // 4. Each of the 2*N-1 left diagonals may have at most one queen
32        // 5. Each of the N^2 squares may have at most one queen
33
34        // So this gives us 2*N mandatory items, and N^2 + 6*N -2 optional ones
35
36        let mut solver = Solver::new_optional(2 * n, n * n + 6 * n - 2);
37
38        // Now add options: each option corresponds to a queen in a particular
39
40        for r in 1..=n {
41            for c in 1..=n {
42                let con_name = format!("R{}C{}", r, c);
43                // 1 -> N
44                let col_con = c;
45                // N+1 -> 2*N
46                let row_con = n + r;
47                // 2*N+1 -> 4*N - 1
48                let rd_con = 2 * n + c - r + n;
49                // 4*N ->  6*N - 2
50                let ld_con = 4 * n - 1 + r + c - 1;
51                // 6*N-1 -> N**2 + 6*N - 2
52                let is_queen = 6 * n - 2 + r + n * (c - 1);
53
54                solver.add_option(con_name, &[col_con, row_con, rd_con, ld_con, is_queen]);
55            }
56        }
57
58        Queens { solver, n }
59    }
60}
61
62impl Iterator for Queens {
63    type Item = Vec<(usize, usize)>;
64    /// Returns the next solution, which is a vector of tuples denoting the Row and Column of the N queens in the solution
65    fn next(&mut self) -> Option<Self::Item> {
66        if let Some(sol) = self.solver.next() {
67            let mut n_queens_solved = Vec::with_capacity(self.n);
68            for i in sol {
69                let i = i.as_str();
70                let s: Vec<&str> = i.split(&['R', 'C']).collect(); //.split('C').split('#');
71                let r: usize = s[1].parse().unwrap();
72                let c: usize = s[2].parse().unwrap();
73                n_queens_solved.push((r, c));
74            }
75            Some(n_queens_solved)
76        } else {
77            None
78        }
79    }
80}