110 lines
2.5 KiB
Rust
110 lines
2.5 KiB
Rust
use crate::board::{
|
|
cmove::CMove,
|
|
{Board, GameState},
|
|
};
|
|
|
|
pub struct Solver {
|
|
pub board: Board,
|
|
moves: Vec<CMove>,
|
|
}
|
|
|
|
impl Solver {
|
|
pub fn new(board: Board) -> Solver {
|
|
Solver {
|
|
board,
|
|
moves: vec![],
|
|
}
|
|
}
|
|
|
|
fn clone(&self, m: CMove) -> Self {
|
|
let mut moves = self.moves.clone();
|
|
let mut board = self.board.clone();
|
|
moves.push(m.clone());
|
|
board.make_move(m);
|
|
Solver { board, moves }
|
|
}
|
|
|
|
pub fn solve(&self) -> Vec<Vec<CMove>> {
|
|
let mut solutions = Vec::new();
|
|
if let GameState::Won = self.board.game_state {
|
|
solutions.push(self.moves.clone());
|
|
return solutions;
|
|
}
|
|
|
|
let GameState::InProgress = self.board.game_state else {
|
|
return solutions;
|
|
};
|
|
|
|
self.board.legal_moves.iter().for_each(|m| {
|
|
let solver = self.clone(m.clone());
|
|
let more_solutions = solver.solve();
|
|
solutions.extend(more_solutions);
|
|
});
|
|
|
|
solutions
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::board::{square::Square, Board};
|
|
|
|
macro_rules! sq {
|
|
($sq:literal) => {
|
|
Square::parse($sq)
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn solver_smoke() {
|
|
let mut board = Board::new();
|
|
// . R . .
|
|
// R . . P
|
|
// B . B N
|
|
// P . N .
|
|
|
|
board.set(sq!("Pa1"));
|
|
board.set(sq!("Ba2"));
|
|
board.set(sq!("Ra3"));
|
|
board.set(sq!("Rb4"));
|
|
board.set(sq!("Nc1"));
|
|
board.set(sq!("Bc2"));
|
|
board.set(sq!("Nd2"));
|
|
board.set(sq!("Pd3"));
|
|
|
|
let solver = Solver::new(board.clone());
|
|
let solutions = solver.solve();
|
|
|
|
for solution in solutions {
|
|
let mut board = board.clone();
|
|
solution
|
|
.into_iter()
|
|
.for_each(|m| assert!(board.make_move(m).is_some()));
|
|
assert_eq!(GameState::Won, board.game_state);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn solver_smoke_no_solution() {
|
|
// . R . .
|
|
// R . . .
|
|
// B . B N
|
|
// P . N .
|
|
|
|
let mut board = Board::new();
|
|
board.set(sq!("Pa1"));
|
|
board.set(sq!("Ba2"));
|
|
board.set(sq!("Ra3"));
|
|
board.set(sq!("Rb4"));
|
|
board.set(sq!("Nc1"));
|
|
board.set(sq!("Bc2"));
|
|
board.set(sq!("Nd2"));
|
|
|
|
let solver = Solver::new(board.clone());
|
|
let solutions = solver.solve();
|
|
|
|
assert_eq!(0, solutions.len());
|
|
}
|
|
}
|