From 95c0ccfbd280f3a82be2e25f52669585c4671f21 Mon Sep 17 00:00:00 2001 From: Pavel Lutskov Date: Tue, 21 Dec 2021 21:07:19 +0100 Subject: [PATCH] Move some functionality into the new Engine mod This will help with separating the "thinking" logic from the move rules and stuff. --- rs/src/board.rs | 55 +++++++++++++++++++++--------------------------- rs/src/engine.rs | 43 +++++++++++++++++++++++++++++++++++++ rs/src/main.rs | 1 + rs/src/ui.rs | 28 ++++++++++++------------ 4 files changed, 83 insertions(+), 44 deletions(-) create mode 100644 rs/src/engine.rs diff --git a/rs/src/board.rs b/rs/src/board.rs index f365fc8..ced1619 100644 --- a/rs/src/board.rs +++ b/rs/src/board.rs @@ -247,7 +247,7 @@ impl Board { state: Default::default(), } } - fn get_at(&self, position: &Position) -> Option<&Piece> { + pub fn get_at(&self, position: &Position) -> Option<&Piece> { self.state.get(position) } pub fn set_at( @@ -260,7 +260,7 @@ impl Board { None => self.state.remove(&position), }; } - fn relocate( + pub fn relocate( &mut self, source: &Position, target: Position, @@ -269,9 +269,6 @@ impl Board { self.set_at(target, Some(piece)); Ok(()) } - pub fn clear(&mut self) { - self.state.clear(); - } pub fn reset(&mut self) { self.state.clear(); for piece_type in &[PieceType::Pawn] { @@ -286,7 +283,7 @@ impl Board { fn cut_move_ray(&self, ray: Ray) -> impl Iterator + '_ { ray.into_iter().take_while(|position| self.get_at(position).is_none()) } - fn find_capture(&self, ray: Ray) -> Option { + fn find_capture_along_ray(&self, ray: Ray) -> Option { // I'm not expecting to call this if there's no piece in the position let crt_piece = self.get_at(&ray.source).unwrap(); ray.into_iter().find(|p| match self.get_at(p) { @@ -294,34 +291,30 @@ impl Board { Some(piece) => piece.color != crt_piece.color, }) } - pub fn get_legal_moves( + pub fn find_moves( &self, position: &Position, - ) -> Option> { - let piece = match self.get_at(position) { - None => return None, - Some(piece) => piece, - }; - let valid_moves = piece - .get_move_rays(position) - .into_iter() - .flat_map(|ray| self.cut_move_ray(ray)); - let valid_captures = piece - .get_capture_rays(position) - .into_iter() - .filter_map(|ray| self.find_capture(ray)); - Some(valid_moves.chain(valid_captures).collect()) - } - pub fn make_move( - &mut self, - source: &Position, - target: Position, - ) -> Result<(), ()> { - if !self.get_legal_moves(source).ok_or(())?.contains(&target) { - Err(()) + ) -> Result + '_, ()> { + if let Some(piece) = self.get_at(position) { + Ok(piece + .get_move_rays(position) + .into_iter() + .flat_map(|ray| self.cut_move_ray(ray))) } else { - // We checked that there is a piece at source in get_legal_moves - self.relocate(source, target) + Err(()) + } + } + pub fn find_captures( + &self, + position: &Position, + ) -> Result + '_, ()> { + if let Some(piece) = self.get_at(position) { + Ok(piece + .get_capture_rays(position) + .into_iter() + .filter_map(|ray| self.find_capture_along_ray(ray))) + } else { + Err(()) } } } diff --git a/rs/src/engine.rs b/rs/src/engine.rs new file mode 100644 index 0000000..053d0b4 --- /dev/null +++ b/rs/src/engine.rs @@ -0,0 +1,43 @@ +use crate::board; + +pub struct Engine { + board: board::Board, +} + +impl Engine { + pub fn new() -> Self { + let mut board = board::Board::new(); + board.reset(); + Engine { + board, + } + } + pub fn get_state(&self) -> &board::Board { + &self.board + } + pub fn set_state(&mut self, board: board::Board) { + self.board = board; + } + pub fn get_legal_moves( + &self, + position: &board::Position, + ) -> Result, ()> { + Ok(self + .board + .find_moves(position)? + .chain(self.board.find_captures(position)?) + .collect()) + } + pub fn make_move( + &mut self, + source: &board::Position, + target: board::Position, + ) -> Result<(), ()> { + if !self.get_legal_moves(source)?.contains(&target) { + Err(()) + } else { + // We checked that there is a piece at source in get_legal_moves + self.board.relocate(source, target) + } + } +} diff --git a/rs/src/main.rs b/rs/src/main.rs index 70313b0..e97219f 100644 --- a/rs/src/main.rs +++ b/rs/src/main.rs @@ -1,4 +1,5 @@ mod board; +mod engine; mod ui; fn main() -> Result<(), ()> { diff --git a/rs/src/ui.rs b/rs/src/ui.rs index ea3a413..f041103 100644 --- a/rs/src/ui.rs +++ b/rs/src/ui.rs @@ -1,5 +1,6 @@ use crate::board; use crate::board::GridAxis; +use crate::engine; use std::io::BufRead; impl std::fmt::Display for board::Color { @@ -140,20 +141,18 @@ impl board::Board { } pub struct Ui { - board: board::Board, + engine: engine::Engine, } impl Ui { pub fn new() -> Self { - let mut board = board::Board::new(); - board.reset(); Ui { - board, + engine: engine::Engine::new(), } } fn get_state(&self, args: &[&str]) -> Result { if let [] = args { - let result = format!("{}", self.board); + let result = format!("{}", self.engine.get_state()); Ok(result) } else { Err("get_state takes no args".to_owned()) @@ -161,9 +160,12 @@ impl Ui { } fn set_state(&mut self, args: &[&str]) -> Result { if let [state_str] = args { - self.board = board::Board::parse(state_str) - .map_err(|_| format!("Error parsing state {}", state_str))?; - let result = format!("{}", self.board); + self.engine.set_state( + board::Board::parse(state_str).map_err(|_| { + format!("Error parsing state {}", state_str) + })?, + ); + let result = format!("{}", self.engine.get_state()); Ok(result) } else { Err("set_state takes 1 arg".to_owned()) @@ -175,12 +177,12 @@ impl Ui { board::Position::parse(position_str).map_err(|_| { format!("Error parsing position {}", position_str) })?; - match self.board.get_legal_moves(&position) { - None => { + match self.engine.get_legal_moves(&position) { + Err(_) => { let error = format!("No moves possible from {}", position); Err(error) } - Some(positions) => Ok(positions + Ok(positions) => Ok(positions .iter() .map(|pos| format!("{}", pos)) .collect()), @@ -195,12 +197,12 @@ impl Ui { .map_err(|_| format!("Error parsing source {}", source_str))?; let target = board::Position::parse(target_str) .map_err(|_| format!("Error parsing target {}", target_str))?; - match self.board.make_move(&source, target) { + match self.engine.make_move(&source, target) { Err(()) => Err(format!( "Move not possible {}-{}", source_str, target_str )), - Ok(()) => Ok(self.board.to_string()), + Ok(()) => Ok(format!("{}", self.engine.get_state())), } } else { Err("make_move takes 2 args".to_owned())