From ed5ad738e36115f09767e41cabdcf663ea46a1df Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Thu, 13 Mar 2025 09:33:56 -0400 Subject: [PATCH] Revert "Move: bit madness" This reverts commit afa80ac597ab34072c12dda0b35cd6644c6253a4. Only made a 3% memory decrease, Most memory is used in the children Vec --- src/elo.rs | 6 +-- src/logic/future_moves.rs | 21 ++++---- src/logic/move.rs | 101 ++++++-------------------------------- src/main.rs | 4 +- src/repr/board.rs | 23 --------- 5 files changed, 30 insertions(+), 125 deletions(-) diff --git a/src/elo.rs b/src/elo.rs index 708f2eb..e8106bf 100644 --- a/src/elo.rs +++ b/src/elo.rs @@ -29,7 +29,7 @@ pub fn run() { children_eval_method: ChildrenEvalMethod::AverageDivDepth, }; - let configs = [4, 6, 7] + let configs = [6] .into_iter() .map(move |d| FutureMoveConfig { max_depth: d, @@ -41,9 +41,9 @@ pub fn run() { }) .filter(move |move_c| { if move_c.do_prune { - move_c.max_depth >= 7 + move_c.max_depth >= 8 } else { - move_c.max_depth < 7 + move_c.max_depth < 8 } }) // .flat_map(move |prev_c| { diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index 51d1bca..79770db 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -104,9 +104,7 @@ impl FutureMoves { // we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated) .filter(|&idx| { let got = &self.arena[idx]; - !got.data.get_trimmed() - && !got.data.get_tried_children() - && got.data.get_winner() == Winner::None + !got.is_trimmed && !got.tried_children && got.winner == Winner::None }) .filter(|&idx| self.is_connected_to_root(idx)) .collect::>(); @@ -152,7 +150,7 @@ impl FutureMoves { .progress_with_style(ProgressStyle::with_template(pstyle_inner).unwrap()) .try_for_each(|node_idx| { self.generate_children(node_idx); - self.arena[node_idx].data.set_tried_children(true); + self.arena[node_idx].tried_children = true; if self.arena_len() >= self.config.max_arena_size { ControlFlow::Break(()) @@ -201,7 +199,7 @@ impl FutureMoves { fn generate_children(&mut self, parent_idx: usize) { let parent = &self.arena[parent_idx]; - let new_color = !parent.data.get_piece(); + let new_color = !parent.color; let parent_board = self .get_board_from_idx(parent_idx) .expect("unable to get board"); @@ -316,7 +314,7 @@ impl FutureMoves { } let n = &self.arena[parent_idx]; - hist.push((n.coord, n.data.get_piece())); + hist.push((n.coord, n.color)); current = n.parent; } hist.reverse(); @@ -357,8 +355,7 @@ impl FutureMoves { }) .inspect(|&&x| { assert_eq!( - self.arena[x].data.get_piece(), - self.agent_color, + self.arena[x].color, self.agent_color, "selected move color should be the same as the color of the agent" ); }) @@ -374,7 +371,7 @@ impl FutureMoves { // match the agent_color usually root or great-grand child .filter(|&idx| self.depth_of(idx) % 2 == 0) .find(|&idx| { - self.arena[idx].data.get_piece() == !self.agent_color + self.arena[idx].color == !self.agent_color && self.get_board_from_idx(idx).as_ref() == Some(board) }); @@ -473,16 +470,16 @@ impl FutureMoves { } // only prune moves of the agent - if indexes.first().map(|&i| self.arena[i].data.get_piece()) != Some(self.agent_color) { + if indexes.first().map(|&i| self.arena[i].color) != Some(self.agent_color) { continue; } for idx in indexes { let mut m = self.arena[idx].clone(); - if m.data.get_trimmed() { + if m.is_trimmed { continue; } - m.data.set_trimmed(true); + m.is_trimmed = true; m.sort_children(&self.arena); if m.children.len() > self.config.top_k_children { let drained = m.children.drain(self.config.top_k_children..); diff --git a/src/logic/move.rs b/src/logic/move.rs index 7d89848..f014948 100644 --- a/src/logic/move.rs +++ b/src/logic/move.rs @@ -7,67 +7,29 @@ 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 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, - pub data: MoveData, -} + /// Which color made a move on this move? + pub color: Piece, -#[derive(Clone, Debug, Copy)] -pub struct MoveData(u8); - -impl MoveData { - const WINNER_LOC: usize = 0; // uses 2 bits - - pub const fn set_winner(&mut self, winner: Winner) { - self.0 &= !(0b11 << Self::WINNER_LOC); - self.0 |= winner.raw() << Self::WINNER_LOC; - } - - pub const fn get_winner(&self) -> Winner { - Winner::from_raw(((self.0 >> Self::WINNER_LOC) & 0b11) as u8) - } - - const PIECE_LOC: usize = 2; - pub const fn set_piece(&mut self, piece: Piece) { - self.0 &= !(0b1 << Self::PIECE_LOC); - self.0 |= (unsafe { std::mem::transmute::(piece) }) << Self::PIECE_LOC; - } - - pub const fn get_piece(&self) -> Piece { - unsafe { std::mem::transmute(((self.0 >> Self::PIECE_LOC) & 0b1) as u8) } - } - - const TRIMMED_LOC: usize = 3; - - pub const fn set_trimmed(&mut self, trimmed: bool) { - self.0 &= !(0b1 << Self::TRIMMED_LOC); - self.0 |= (trimmed as u8) << Self::TRIMMED_LOC; - } - - pub const fn get_trimmed(&self) -> bool { - ((self.0 >> Self::TRIMMED_LOC) & 0b1) != 0 - } - - const TRIED_CHILDREN_LOC: usize = 4; - - pub const fn set_tried_children(&mut self, tried_children: bool) { - self.0 &= !(0b1 << Self::TRIED_CHILDREN_LOC); - self.0 |= (tried_children as u8) << Self::TRIED_CHILDREN_LOC; - } - - pub const fn get_tried_children(&self) -> bool { - ((self.0 >> Self::TRIED_CHILDREN_LOC) & 0b1) != 0 - } + /// Was this move's children previously trimmed? + pub is_trimmed: bool, } static BVM: LazyLock = LazyLock::new(BoardValueMap::new); @@ -76,28 +38,26 @@ 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, - data: MoveData(0), + tried_children: false, }; - let winner = board.game_winner(); - m.data.set_winner(winner); - m.data.set_piece(color); - m.data.set_trimmed(false); - m.data.set_tried_children(false); m.self_value = m.compute_self_value(agent_color, &board); m } fn compute_self_value(&self, agent_color: Piece, board: &Board) -> i16 { - if self.data.get_winner() == Winner::Player(!agent_color) { + 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.data.get_winner() == Winner::Player(agent_color) { + } else if self.winner == Winner::Player(agent_color) { // results in a win for the agent return i16::MAX - 1; } @@ -118,32 +78,3 @@ impl Move { }); } } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn move_data_winner() { - let mut m = MoveData(0); - macro_rules! test_winner { - ($winner:expr) => { - m.set_winner($winner); - assert_eq!(m.get_winner(), $winner); - }; - } - test_winner!(Winner::Player(Piece::Black)); - test_winner!(Winner::Player(Piece::White)); - test_winner!(Winner::Tie); - test_winner!(Winner::None); - } - - #[test] - fn move_data_trimmed() { - let mut m = MoveData(0); - m.set_trimmed(false); - assert!(!m.get_trimmed()); - m.set_trimmed(true); - assert!(m.get_trimmed()); - } -} diff --git a/src/main.rs b/src/main.rs index cb14744..709efc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,8 +12,8 @@ pub mod repr; // TODO! make this agent configuration a config option via `clap-rs` fn main() { - elo::run(); - return; + // elo::run(); + // return; let player1 = complexagent::ComplexAgent::new( Piece::Black, FutureMoveConfig { diff --git a/src/repr/board.rs b/src/repr/board.rs index 39ed6ab..ba9e76f 100644 --- a/src/repr/board.rs +++ b/src/repr/board.rs @@ -46,16 +46,6 @@ pub enum Winner { None, } -impl Winner { - pub const fn raw(self) -> u8 { - unsafe { std::mem::transmute(self) } - } - - pub const fn from_raw(value: u8) -> Self { - unsafe { std::mem::transmute(value) } - } -} - macro_rules! get_board { // Immutable static access ($self:expr, Piece::White) => { @@ -549,17 +539,4 @@ mod test { assert_eq!(board.get((6, 0).into()), Some(Piece::Black), "\n{}", board); } - - #[test] - fn winner_repr() { - assert_eq!(Winner::Player(Piece::Black).raw(), 0b00); - assert_eq!(Winner::Player(Piece::White).raw(), 0b01); - assert_eq!(Winner::Tie.raw(), 0b10); - assert_eq!(Winner::None.raw(), 0b11); - - assert_eq!(Winner::from_raw(0b00), Winner::Player(Piece::Black)); - assert_eq!(Winner::from_raw(0b01), Winner::Player(Piece::White)); - assert_eq!(Winner::from_raw(0b10), Winner::Tie); - assert_eq!(Winner::from_raw(0b11), Winner::None); - } }