Move some functionality into the new Engine mod
This will help with separating the "thinking" logic from the move rules and stuff.
This commit is contained in:
@@ -247,7 +247,7 @@ impl Board {
|
|||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_at(&self, position: &Position) -> Option<&Piece> {
|
pub fn get_at(&self, position: &Position) -> Option<&Piece> {
|
||||||
self.state.get(position)
|
self.state.get(position)
|
||||||
}
|
}
|
||||||
pub fn set_at(
|
pub fn set_at(
|
||||||
@@ -260,7 +260,7 @@ impl Board {
|
|||||||
None => self.state.remove(&position),
|
None => self.state.remove(&position),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn relocate(
|
pub fn relocate(
|
||||||
&mut self,
|
&mut self,
|
||||||
source: &Position,
|
source: &Position,
|
||||||
target: Position,
|
target: Position,
|
||||||
@@ -269,9 +269,6 @@ impl Board {
|
|||||||
self.set_at(target, Some(piece));
|
self.set_at(target, Some(piece));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.state.clear();
|
|
||||||
}
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.state.clear();
|
self.state.clear();
|
||||||
for piece_type in &[PieceType::Pawn] {
|
for piece_type in &[PieceType::Pawn] {
|
||||||
@@ -286,7 +283,7 @@ impl Board {
|
|||||||
fn cut_move_ray(&self, ray: Ray) -> impl Iterator<Item = Position> + '_ {
|
fn cut_move_ray(&self, ray: Ray) -> impl Iterator<Item = Position> + '_ {
|
||||||
ray.into_iter().take_while(|position| self.get_at(position).is_none())
|
ray.into_iter().take_while(|position| self.get_at(position).is_none())
|
||||||
}
|
}
|
||||||
fn find_capture(&self, ray: Ray) -> Option<Position> {
|
fn find_capture_along_ray(&self, ray: Ray) -> Option<Position> {
|
||||||
// I'm not expecting to call this if there's no piece in the position
|
// I'm not expecting to call this if there's no piece in the position
|
||||||
let crt_piece = self.get_at(&ray.source).unwrap();
|
let crt_piece = self.get_at(&ray.source).unwrap();
|
||||||
ray.into_iter().find(|p| match self.get_at(p) {
|
ray.into_iter().find(|p| match self.get_at(p) {
|
||||||
@@ -294,34 +291,30 @@ impl Board {
|
|||||||
Some(piece) => piece.color != crt_piece.color,
|
Some(piece) => piece.color != crt_piece.color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn get_legal_moves(
|
pub fn find_moves(
|
||||||
&self,
|
&self,
|
||||||
position: &Position,
|
position: &Position,
|
||||||
) -> Option<Vec<Position>> {
|
) -> Result<impl Iterator<Item = Position> + '_, ()> {
|
||||||
let piece = match self.get_at(position) {
|
if let Some(piece) = self.get_at(position) {
|
||||||
None => return None,
|
Ok(piece
|
||||||
Some(piece) => piece,
|
|
||||||
};
|
|
||||||
let valid_moves = piece
|
|
||||||
.get_move_rays(position)
|
.get_move_rays(position)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|ray| self.cut_move_ray(ray));
|
.flat_map(|ray| self.cut_move_ray(ray)))
|
||||||
let valid_captures = piece
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn find_captures(
|
||||||
|
&self,
|
||||||
|
position: &Position,
|
||||||
|
) -> Result<impl Iterator<Item = Position> + '_, ()> {
|
||||||
|
if let Some(piece) = self.get_at(position) {
|
||||||
|
Ok(piece
|
||||||
.get_capture_rays(position)
|
.get_capture_rays(position)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|ray| self.find_capture(ray));
|
.filter_map(|ray| self.find_capture_along_ray(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(())
|
|
||||||
} else {
|
} else {
|
||||||
// We checked that there is a piece at source in get_legal_moves
|
Err(())
|
||||||
self.relocate(source, target)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
rs/src/engine.rs
Normal file
43
rs/src/engine.rs
Normal file
@@ -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<Vec<board::Position>, ()> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
mod board;
|
mod board;
|
||||||
|
mod engine;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
fn main() -> Result<(), ()> {
|
fn main() -> Result<(), ()> {
|
||||||
|
|||||||
28
rs/src/ui.rs
28
rs/src/ui.rs
@@ -1,5 +1,6 @@
|
|||||||
use crate::board;
|
use crate::board;
|
||||||
use crate::board::GridAxis;
|
use crate::board::GridAxis;
|
||||||
|
use crate::engine;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
|
|
||||||
impl std::fmt::Display for board::Color {
|
impl std::fmt::Display for board::Color {
|
||||||
@@ -140,20 +141,18 @@ impl board::Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
board: board::Board,
|
engine: engine::Engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut board = board::Board::new();
|
|
||||||
board.reset();
|
|
||||||
Ui {
|
Ui {
|
||||||
board,
|
engine: engine::Engine::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_state(&self, args: &[&str]) -> Result<String, String> {
|
fn get_state(&self, args: &[&str]) -> Result<String, String> {
|
||||||
if let [] = args {
|
if let [] = args {
|
||||||
let result = format!("{}", self.board);
|
let result = format!("{}", self.engine.get_state());
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err("get_state takes no args".to_owned())
|
Err("get_state takes no args".to_owned())
|
||||||
@@ -161,9 +160,12 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
fn set_state(&mut self, args: &[&str]) -> Result<String, String> {
|
fn set_state(&mut self, args: &[&str]) -> Result<String, String> {
|
||||||
if let [state_str] = args {
|
if let [state_str] = args {
|
||||||
self.board = board::Board::parse(state_str)
|
self.engine.set_state(
|
||||||
.map_err(|_| format!("Error parsing state {}", state_str))?;
|
board::Board::parse(state_str).map_err(|_| {
|
||||||
let result = format!("{}", self.board);
|
format!("Error parsing state {}", state_str)
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
let result = format!("{}", self.engine.get_state());
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err("set_state takes 1 arg".to_owned())
|
Err("set_state takes 1 arg".to_owned())
|
||||||
@@ -175,12 +177,12 @@ impl Ui {
|
|||||||
board::Position::parse(position_str).map_err(|_| {
|
board::Position::parse(position_str).map_err(|_| {
|
||||||
format!("Error parsing position {}", position_str)
|
format!("Error parsing position {}", position_str)
|
||||||
})?;
|
})?;
|
||||||
match self.board.get_legal_moves(&position) {
|
match self.engine.get_legal_moves(&position) {
|
||||||
None => {
|
Err(_) => {
|
||||||
let error = format!("No moves possible from {}", position);
|
let error = format!("No moves possible from {}", position);
|
||||||
Err(error)
|
Err(error)
|
||||||
}
|
}
|
||||||
Some(positions) => Ok(positions
|
Ok(positions) => Ok(positions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pos| format!("{}", pos))
|
.map(|pos| format!("{}", pos))
|
||||||
.collect()),
|
.collect()),
|
||||||
@@ -195,12 +197,12 @@ impl Ui {
|
|||||||
.map_err(|_| format!("Error parsing source {}", source_str))?;
|
.map_err(|_| format!("Error parsing source {}", source_str))?;
|
||||||
let target = board::Position::parse(target_str)
|
let target = board::Position::parse(target_str)
|
||||||
.map_err(|_| format!("Error parsing target {}", 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!(
|
Err(()) => Err(format!(
|
||||||
"Move not possible {}-{}",
|
"Move not possible {}-{}",
|
||||||
source_str, target_str
|
source_str, target_str
|
||||||
)),
|
)),
|
||||||
Ok(()) => Ok(self.board.to_string()),
|
Ok(()) => Ok(format!("{}", self.engine.get_state())),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err("make_move takes 2 args".to_owned())
|
Err("make_move takes 2 args".to_owned())
|
||||||
|
|||||||
Reference in New Issue
Block a user