diff --git a/src/board.rs b/src/board.rs index b585f7e..67b76a7 100644 --- a/src/board.rs +++ b/src/board.rs @@ -6,7 +6,7 @@ use std::{cmp::Ordering, fmt}; pub const BOARD_SIZE: usize = 8; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] pub struct Board { board: [[Option; BOARD_SIZE]; BOARD_SIZE], } @@ -78,7 +78,7 @@ impl Board { Box::new( (0..BOARD_SIZE) .flat_map(|i| (0..BOARD_SIZE).map(move |j| (i, j))) - .filter(move |(i, j)| self.what_if(*i, *j, color).is_some()), + .filter(move |(i, j)| self.would_prop(*i, *j, color)), ) } @@ -111,6 +111,10 @@ impl Board { Some((self_copy, how_many_prop)) } + pub fn would_prop(&self, i: usize, j: usize, piece: Piece) -> bool { + !self.propegate_from_dry(i, j, piece).is_empty() + } + pub fn place(&mut self, i: usize, j: usize, piece: Piece) -> Result<(), String> { if let Some(what_if_result) = self.what_if(i, j, piece) { if what_if_result.1 > 0 { @@ -121,15 +125,24 @@ impl Board { Err("move would not propegate".to_string()) } - /// Propegate piece captures originating from (i, j) - /// DO NOT USE THIS ALONE, this should be called as a part of - /// [`Board::place`] or [`Board::place_and_prop_unchecked`] fn propegate_from(&mut self, i: usize, j: usize) -> usize { - // returns if that place is empty let Some(starting_color) = *self.get(i, j) else { return 0; }; + let pos_s = self.propegate_from_dry(i, j, starting_color); + let pos_len = pos_s.len(); + for (i, j) in pos_s { + self.place_unchecked(i, j, starting_color); + } + + pos_len + } + + /// Propegate piece captures originating from (i, j) + /// DO NOT USE THIS ALONE, this should be called as a part of + /// [`Board::place`] or [`Board::place_and_prop_unchecked`] + fn propegate_from_dry(&self, i: usize, j: usize, starting_color: Piece) -> Vec<(usize, usize)> { // Create all chains from the piece being propegated from in `i` and `j` coordinates let (i_chain, j_chain) = ( split_from(0, BOARD_SIZE - 1, i), @@ -152,7 +165,7 @@ impl Board { // handle diagonals chains.extend(diag(i, j, 0, 0, BOARD_SIZE - 1, BOARD_SIZE - 1)); - let mut captured: usize = 0; + let mut fill: Vec<(usize, usize)> = Vec::new(); for chain in chains { for (chain_length, &(new_i, new_j)) in chain.iter().enumerate() { @@ -166,11 +179,10 @@ impl Board { let Some(history) = chain.get(..chain_length) else { break; }; - captured += history.len(); // fill all opposite colors with this color for &(i_o, j_o) in history { - self.place_unchecked(i_o, j_o, starting_color); + fill.push((i_o, j_o)); } // either the other pieces were replaced, or this was an invalid chain, // in both cases, the loop needs to be breaked @@ -178,7 +190,7 @@ impl Board { } } } - captured + fill } /// Returns (White score, Black score) diff --git a/src/complexagent.rs b/src/complexagent.rs index 98d89a6..deaef5a 100644 --- a/src/complexagent.rs +++ b/src/complexagent.rs @@ -2,8 +2,10 @@ use crate::{agent::Agent, board::Board, piece::Piece}; pub struct ComplexAgent { color: Piece, + curr_move: Option, } +#[derive(Clone)] struct Move { i: usize, j: usize, @@ -44,6 +46,10 @@ impl Move { value } + + pub const fn coords(&self) -> (usize, usize) { + (self.i, self.j) + } } fn problem_space(board: &Board, color: Piece) -> Box + '_> { @@ -65,14 +71,38 @@ fn problem_space(board: &Board, color: Piece) -> Box + impl Agent for ComplexAgent { fn next_move(&mut self, board: &Board) -> Option<(usize, usize)> { const LOOPS: usize = 5; - problem_space(board, self.color) - .map(|mut x| { - x.populate_next_moves(LOOPS); - x - }) - .map(|m| ((m.i, m.j), m.value(self.color))) - .max_by_key(|a| a.1) - .map(|a| a.0) + + let curr_move: Move = self.curr_move.take().unwrap_or_else(|| Move { + i: 0, + j: 0, + captured: 0, + color: self.color, + board: *board, + next_move: vec![Move { + i: 0, + j: 0, + captured: 0, + color: !self.color, + board: *board, + next_move: problem_space(board, self.color).collect(), + }], + }); + + let mut other_player_move = curr_move + .next_move + .into_iter() + .filter(|x| &x.board == board) + .last() + .unwrap(); + + other_player_move.populate_next_moves(LOOPS); + + self.curr_move = other_player_move + .next_move + .into_iter() + .max_by_key(|m| m.value(self.color)); + + self.curr_move.as_ref().map(Move::coords) } fn name(&self) -> &'static str { @@ -86,6 +116,9 @@ impl Agent for ComplexAgent { impl ComplexAgent { pub fn new(color: Piece) -> Self { - Self { color } + Self { + color, + curr_move: None, + } } }