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;
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Board {
board: [[Option<Piece>; 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)

View File

@ -2,8 +2,10 @@ use crate::{agent::Agent, board::Board, piece::Piece};
pub struct ComplexAgent {
color: Piece,
curr_move: Option<Move>,
}
#[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<dyn Iterator<Item = Move> + '_> {
@ -65,14 +71,38 @@ fn problem_space(board: &Board, color: Piece) -> Box<dyn Iterator<Item = Move> +
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,
}
}
}