allow move arena to properly handle skipping a move

This commit is contained in:
Simon Gardling 2025-02-26 22:58:47 -05:00
parent 4a82c01d64
commit d3cac6ae91
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
2 changed files with 43 additions and 56 deletions

View File

@ -120,16 +120,22 @@ impl FutureMoves {
// use [`Board::all_positions`] here instead of [`Board::possible_moves`]
// because we use [`Board::what_if`] later and we want to reduce calls to [`Board::propegate_from_dry`]
let new: Vec<Move> = Board::all_positions()
let mut new: Vec<Move> = Board::all_positions()
.flat_map(|(i, j)| {
parent
.board
.what_if(i, j, new_color)
.map(move |x| (i, j, x))
})
.map(|(i, j, new_board)| Move::new(i, j, new_board, new_color, self.agent_color))
.map(|(i, j, new_board)| {
Move::new(Some((i, j)), new_board, new_color, self.agent_color)
})
.collect();
if new.is_empty() {
new.push(Move::new(None, parent.board, new_color, self.agent_color));
}
let start_idx = self.arena.len();
self.arena.extend(new);
@ -224,7 +230,7 @@ impl FutureMoves {
"selected move color should be the same as the color of the agent"
);
})
.map(|&x| self.arena[x].coords())
.and_then(|&x| self.arena[x].coord)
}
/// Updates `FutureMoves` based on the current state of the board
@ -248,13 +254,8 @@ impl FutureMoves {
/// Clear the arena and create and set a root which contains a Board
pub fn set_root_from_board(&mut self, board: Board) {
self.arena.clear();
self.arena.push(Move::new(
0, // dummy
0, // dummy
board,
!self.agent_color,
self.agent_color,
));
self.arena
.push(Move::new(None, board, !self.agent_color, self.agent_color));
// because we have to regenerate root from a [`Board`]
// we need to reset the current_depth (fixes `skip_move_recovery`)
self.current_depth = 0;
@ -275,7 +276,7 @@ impl FutureMoves {
self.arena
.iter()
.enumerate()
.find(|(_, node)| node.parent == self.current_root && node.coords() == (i, j))
.find(|(_, node)| node.parent == self.current_root && node.coord == Some((i, j)))
.map(|x| x.0)
// do raw set so we can prune it on the next move (in `update`)
.inspect(|&root| self.update_root_idx_raw(root))
@ -470,8 +471,7 @@ mod tests {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.arena.push(Move {
i: 0,
j: 0,
coord: None,
board: Board::new(),
winner: Winner::None,
parent: None,
@ -487,13 +487,12 @@ mod tests {
// child 1
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(0, 1);
// dummy (2)
futm.arena.push(Move::new(
1234,
1234,
Some((1234, 1234)),
Board::new(),
Piece::White,
Piece::Black,
@ -501,12 +500,12 @@ mod tests {
// 3
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(0, 3);
// 4
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(0, 4);
assert_eq!(futm.arena_len(), 5);
@ -515,7 +514,11 @@ mod tests {
assert_eq!(futm.arena_len(), 4);
assert_eq!(futm.arena[0].children.len(), 3);
assert_ne!(futm.arena[2].i, 1234, "dummy value still exists");
assert_ne!(
futm.arena[2].coord,
Some((1234, 1234)),
"dummy value still exists"
);
}
#[test]
@ -524,8 +527,7 @@ mod tests {
futm.config.max_depth = 1;
futm.arena.push(Move::new(
0,
0,
None,
Board::new().starting_pos(),
Piece::Black,
Piece::Black,
@ -556,8 +558,7 @@ mod tests {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.arena.push(Move {
i: 0,
j: 0,
coord: None,
board: Board::new(),
winner: Winner::None,
parent: None,
@ -573,25 +574,20 @@ mod tests {
// child 1
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(0, 1);
// dummy
futm.arena.push(Move::new(
1234,
1234,
Board::new(),
Piece::White,
Piece::Black,
));
futm.arena
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(1, 3);
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(0, 4);
@ -603,8 +599,7 @@ mod tests {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.arena.push(Move {
i: 0,
j: 0,
coord: None,
board: Board::new(),
winner: Winner::None,
parent: None,
@ -620,20 +615,15 @@ mod tests {
// child 1
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(0, 1);
// dummy
futm.arena.push(Move::new(
1234,
1234,
Board::new(),
Piece::White,
Piece::Black,
));
futm.arena
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.arena
.push(Move::new(0, 0, Board::new(), Piece::White, Piece::Black));
.push(Move::new(None, Board::new(), Piece::White, Piece::Black));
futm.set_parent_child(1, 3);
assert_eq!(

View File

@ -4,11 +4,8 @@ use lazy_static::lazy_static;
#[derive(Clone, Debug)]
pub struct Move {
/// `i` position of move
pub i: usize,
/// `j` position of move
pub j: usize,
/// Coordinates (i, j) of the move (if it exists)
pub coord: Option<(usize, usize)>,
/// [`Board`] state after move is made
pub board: Board,
@ -43,10 +40,14 @@ lazy_static! {
}
impl Move {
pub fn new(i: usize, j: usize, board: Board, color: Piece, agent_color: Piece) -> Self {
pub fn new(
coord: Option<(usize, usize)>,
board: Board,
color: Piece,
agent_color: Piece,
) -> Self {
let mut m = Move {
i,
j,
coord,
board,
winner: board.game_winner(),
parent: None,
@ -61,10 +62,6 @@ impl Move {
m
}
pub const fn coords(&self) -> (usize, usize) {
(self.i, self.j)
}
fn compute_self_value(&self, agent_color: Piece) -> i64 {
if self.winner == Winner::Player(!agent_color) {
// if this board results in the opponent winning, MAJORLY negatively weigh this move