make complexagent so much better

This commit is contained in:
Simon Gardling 2025-02-06 22:47:29 -05:00
parent 3681fd7e41
commit 669af2a56e
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
2 changed files with 64 additions and 19 deletions

View File

@ -6,7 +6,7 @@ use std::{cmp::Ordering, fmt};
pub const BOARD_SIZE: usize = 8; pub const BOARD_SIZE: usize = 8;
#[derive(Copy, Clone)] #[derive(Copy, Clone, PartialEq, Eq)]
pub struct Board { pub struct Board {
board: [[Option<Piece>; BOARD_SIZE]; BOARD_SIZE], board: [[Option<Piece>; BOARD_SIZE]; BOARD_SIZE],
} }
@ -78,7 +78,7 @@ impl Board {
Box::new( Box::new(
(0..BOARD_SIZE) (0..BOARD_SIZE)
.flat_map(|i| (0..BOARD_SIZE).map(move |j| (i, j))) .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)) 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> { 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 let Some(what_if_result) = self.what_if(i, j, piece) {
if what_if_result.1 > 0 { if what_if_result.1 > 0 {
@ -121,15 +125,24 @@ impl Board {
Err("move would not propegate".to_string()) 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 { 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 { let Some(starting_color) = *self.get(i, j) else {
return 0; 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 // Create all chains from the piece being propegated from in `i` and `j` coordinates
let (i_chain, j_chain) = ( let (i_chain, j_chain) = (
split_from(0, BOARD_SIZE - 1, i), split_from(0, BOARD_SIZE - 1, i),
@ -152,7 +165,7 @@ impl Board {
// handle diagonals // handle diagonals
chains.extend(diag(i, j, 0, 0, BOARD_SIZE - 1, BOARD_SIZE - 1)); 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 in chains {
for (chain_length, &(new_i, new_j)) in chain.iter().enumerate() { 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 { let Some(history) = chain.get(..chain_length) else {
break; break;
}; };
captured += history.len();
// fill all opposite colors with this color // fill all opposite colors with this color
for &(i_o, j_o) in history { 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, // either the other pieces were replaced, or this was an invalid chain,
// in both cases, the loop needs to be breaked // in both cases, the loop needs to be breaked
@ -178,7 +190,7 @@ impl Board {
} }
} }
} }
captured fill
} }
/// Returns (White score, Black score) /// Returns (White score, Black score)

View File

@ -2,8 +2,10 @@ use crate::{agent::Agent, board::Board, piece::Piece};
pub struct ComplexAgent { pub struct ComplexAgent {
color: Piece, color: Piece,
curr_move: Option<Move>,
} }
#[derive(Clone)]
struct Move { struct Move {
i: usize, i: usize,
j: usize, j: usize,
@ -44,6 +46,10 @@ impl Move {
value value
} }
pub const fn coords(&self) -> (usize, usize) {
(self.i, self.j)
}
} }
fn problem_space(board: &Board, color: Piece) -> Box<dyn Iterator<Item = Move> + '_> { fn problem_space(board: &Board, color: Piece) -> Box<dyn Iterator<Item = Move> + '_> {
@ -65,14 +71,38 @@ fn problem_space(board: &Board, color: Piece) -> Box<dyn Iterator<Item = Move> +
impl Agent for ComplexAgent { impl Agent for ComplexAgent {
fn next_move(&mut self, board: &Board) -> Option<(usize, usize)> { fn next_move(&mut self, board: &Board) -> Option<(usize, usize)> {
const LOOPS: usize = 5; const LOOPS: usize = 5;
problem_space(board, self.color)
.map(|mut x| { let curr_move: Move = self.curr_move.take().unwrap_or_else(|| Move {
x.populate_next_moves(LOOPS); i: 0,
x j: 0,
}) captured: 0,
.map(|m| ((m.i, m.j), m.value(self.color))) color: self.color,
.max_by_key(|a| a.1) board: *board,
.map(|a| a.0) 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 { fn name(&self) -> &'static str {
@ -86,6 +116,9 @@ impl Agent for ComplexAgent {
impl ComplexAgent { impl ComplexAgent {
pub fn new(color: Piece) -> Self { pub fn new(color: Piece) -> Self {
Self { color } Self {
color,
curr_move: None,
}
} }
} }