use std::collections::{BTreeMap, BTreeSet};
use std::iter::from_generator;
use std::fmt::Display;
use rand::Rng;
mod display;
#[derive(Clone, Debug)]
pub struct NQueensState {
size: isize,
filled: Vec<isize>,
unfilled: BTreeSet<isize>,
}
impl NQueensState {
pub fn new(size: usize) -> Self {
Self {
size: size as isize,
filled: Vec::with_capacity(size),
unfilled: (0..size as isize).collect(),
}
}
pub fn full_filled(&self) -> bool {
self.unfilled.is_empty()
}
pub fn symmetrical(&self, x: isize, y: isize) -> Vec<(isize, isize)> {
let mut symmetry = Vec::with_capacity(8);
let s = self.size;
let x = x % s;
let y = y % s;
symmetry.push((x, y));
symmetry.push((s - x - 1, y));
symmetry.push((x, s - y - 1));
symmetry.push((s - x - 1, s - y - 1));
symmetry.push((y, x));
symmetry.push((s - y - 1, x));
symmetry.push((y, s - x - 1));
symmetry.push((s - y - 1, s - x - 1));
symmetry
}
pub fn is_solution(&self) -> bool {
for i in 0..self.size {
if !self.filled.contains(&i) {
return false;
}
}
true
}
pub fn valid_at(&self, column: isize) -> bool {
let row = self.filled.len() as isize;
self.filled
.iter()
.enumerate()
.all(|(solution_row, &solution_column)| {
column != solution_column &&
column + row != solution_column + solution_row as isize &&
column - row != solution_column - solution_row as isize
})
}
pub fn go_walk(&mut self, column: isize) {
self.filled.push(column);
self.unfilled.remove(&column);
}
pub fn go_back(&mut self) {
match self.filled.pop() {
Some(s) => {
self.unfilled.insert(s);
}
None => {}
}
}
}
pub fn n_queens_backtracking(size: usize) -> impl Iterator<Item=NQueensState> {
let mut stack = vec![NQueensState::new(size)];
from_generator(move || {
while let Some(mut state) = stack.pop() {
if state.full_filled() {
yield state;
continue;
};
for row in state.unfilled.clone() {
if state.valid_at(row) {
state.go_walk(row);
stack.push(state.clone());
state.go_back();
}
}
}
})
}
#[test]
fn test_n_queens_backtracking() {
let mut count = 0;
for solution in n_queens_backtracking(4) {
println!("{}", solution);
count += 1;
}
println!("{} solutions found", count);
}