1use std::fmt::{self, Display, Formatter};
2
3use backtracking::{Problem, Solutions};
4
5fn main() {
6 let board = NQueens::new(8);
7 for solution in Solutions::new(board) {
8 println!("{solution}")
9 }
10}
11
12#[derive(Clone)]
13struct NQueens {
14 n: u32,
15}
16
17impl NQueens {
18 fn new(n: u32) -> Self {
19 Self { n }
20 }
21}
22
23#[derive(Clone, Copy)]
25struct QueenAt {
26 row: u32,
27 column: u32,
28}
29
30impl QueenAt {
31 fn conflicts(self, other: QueenAt) -> bool {
33 self.row == other.row
34 || self.column == other.column
35 || self.row.abs_diff(other.row) == self.column.abs_diff(other.column)
36 }
37}
38
39impl Problem for NQueens {
40 type Posibility = QueenAt;
41 type Solution = NQueensSolution;
42
43 fn extend_possibilities(&self, possible_moves: &mut Vec<QueenAt>, history: &[QueenAt]) {
44 if history.len() == self.n as usize {
45 return;
46 }
47 let possibilities = (0..self.n)
49 .map(|col| QueenAt {
50 row: history.len() as u32,
51 column: col,
52 })
53 .filter(|candidate| history.iter().all(|q| !q.conflicts(*candidate)));
54 possible_moves.extend(possibilities);
55 }
56
57 fn undo(&mut self, _last: &Self::Posibility, _history: &[Self::Posibility]) {}
58
59 fn what_if(&mut self, _next: QueenAt) {}
60
61 fn is_solution(&self, history: &[QueenAt]) -> Option<NQueensSolution> {
62 if history.len() == self.n as usize {
63 let mut solution = vec![0; self.n as usize];
64 for queen in history {
65 solution[queen.row as usize] = queen.column;
66 }
67 Some(NQueensSolution(solution))
68 } else {
69 None
70 }
71 }
72}
73
74struct NQueensSolution(Vec<u32>);
76
77impl Display for NQueensSolution {
78 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
79 let repeat_point = |f: &mut Formatter, n| {
80 for _ in 0..n {
81 write!(f, ".")?;
82 }
83 Ok(())
84 };
85
86 for &pos in &self.0 {
87 repeat_point(f, pos)?;
88 write!(f, "Q")?;
89 repeat_point(f, self.0.len() as u32 - pos - 1)?;
90 writeln!(f)?;
91 }
92 Ok(())
93 }
94}