use super::board_value::BoardValueMap; use crate::repr::{Board, CoordPair, Piece, Winner}; use allocative::Allocative; use std::sync::LazyLock; #[derive(Clone, Debug, Allocative)] pub struct Move { /// Coordinates (i, j) of the move (if it exists) pub coord: Option, /// Current winner of the match pub winner: Winner, /// Index of this move's parent pub parent: Option, /// Indices of this Move's Children // PERF! this accounts for ~40% of memory usage // I'm thinking maybe switching to this actually being `Vec>` // and ditching the entire `Arena` idea, that would have // cascading effects though, something to think about pub children: Vec, /// Has this [`Move`] already attempted to create children? pub tried_children: bool, /// Value of this move (including children) pub value: Option, /// What is the inherit value of this move (not including children) pub self_value: i16, /// Which color made a move on this move? pub color: Piece, /// Was this move's children previously trimmed? pub is_trimmed: bool, } impl Move { pub fn new(coord: Option, board: Board, color: Piece, agent_color: Piece) -> Self { let mut m = Move { coord, winner: board.game_winner(), parent: None, children: Vec::new(), value: None, color, is_trimmed: false, self_value: 0, tried_children: false, }; m.self_value = m.compute_self_value(agent_color, &board, true); m } fn compute_self_value(&self, agent_color: Piece, board: &Board, use_weighted_bvm: bool) -> i16 { if self.winner == Winner::Player(!agent_color) { // if this board results in the opponent winning, MAJORLY negatively weigh this move // NOTE! this branch isn't completely deleted because if so, the bot wouldn't make a move. // We shouldn't prune branches because we still need to always react to the opponent's moves return i16::MIN + 1; } else if self.winner == Winner::Player(agent_color) { // results in a win for the agent return i16::MAX - 1; } // else if self.winner == Winner::Tie { // // idk what a Tie should be valued? // return 0; // } // I guess ignore Ties here, don't give them an explicit value, // because even in the case of ties, we want to have a higher score match use_weighted_bvm { true => const { BoardValueMap::weighted() }, false => const { BoardValueMap::flat() }, } .board_value(board, agent_color) } /// Sort children of the [`Move`] by their self_value in `arena` pub fn sort_children(&mut self, arena: &[Move]) { self.children.sort_by(|&a, &b| { arena[b].value.cmp(&arena[a].value) // Descending order for agent's max nodes }); } }