From 72eb60f3229482b6e11389e3f3146a6781b84a9c Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Fri, 27 Feb 2026 18:08:21 +0100 Subject: [PATCH] fix(bot): raise error on empty get_legal_actions --- store/src/cxxengine.rs | 33 +++++++++++++++++---------------- store/src/pyengine.rs | 4 ++-- store/src/training_common.rs | 15 ++++++++------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/store/src/cxxengine.rs b/store/src/cxxengine.rs index 86aa382..e6027f6 100644 --- a/store/src/cxxengine.rs +++ b/store/src/cxxengine.rs @@ -57,7 +57,7 @@ pub mod ffi { /// Legal action indices for `player_idx` in [0, 513]. /// Returns an empty vector when it is not that player's turn. - fn get_legal_actions(self: &TricTracEngine, player_idx: u64) -> Vec; + fn get_legal_actions(self: &TricTracEngine, player_idx: u64) -> Result>; /// Human-readable description of an action index. fn action_to_string(self: &TricTracEngine, player_idx: u64, action_idx: u64) -> String; @@ -123,21 +123,16 @@ impl TricTracEngine { self.game_state.active_player_id - 1 } - fn get_legal_actions(&self, player_idx: u64) -> Vec { + fn get_legal_actions(&self, player_idx: u64) -> anyhow::Result> { if player_idx != self.current_player_idx() { - return vec![]; + return Ok(vec![]); } if player_idx == 0 { get_valid_action_indices(&self.game_state) - .into_iter() - .map(|i| i as u64) - .collect() + .map(|v| v.into_iter().map(|i| i as u64).collect()) } else { let mirror = self.game_state.mirror(); - get_valid_action_indices(&mirror) - .into_iter() - .map(|i| i as u64) - .collect() + get_valid_action_indices(&mirror).map(|v| v.into_iter().map(|i| i as u64).collect()) } } @@ -184,8 +179,10 @@ impl TricTracEngine { fn apply_dice_roll(&mut self, dice: ffi::DicePair) -> anyhow::Result<()> { if self.game_state.turn_stage != TurnStage::RollWaiting { - anyhow::bail!("apply_dice_roll: not in RollWaiting stage (currently {:?})", - self.game_state.turn_stage); + anyhow::bail!( + "apply_dice_roll: not in RollWaiting stage (currently {:?})", + self.game_state.turn_stage + ); } let player_id = self.game_state.active_player_id; let dice = Dice { @@ -214,10 +211,14 @@ impl TricTracEngine { self.game_state.consume(&evt); Ok(()) } - Some(_) => anyhow::bail!("apply_action: action {} is not valid in current state", - action_idx), - None => anyhow::bail!("apply_action: could not build event from action index {}", - action_idx), + Some(_) => anyhow::bail!( + "apply_action: action {} is not valid in current state", + action_idx + ), + None => anyhow::bail!( + "apply_action: could not build event from action index {}", + action_idx + ), } } } diff --git a/store/src/pyengine.rs b/store/src/pyengine.rs index 7577954..593fa00 100644 --- a/store/src/pyengine.rs +++ b/store/src/pyengine.rs @@ -43,10 +43,10 @@ impl TricTrac { fn get_legal_actions(&self, player_idx: u64) -> Vec { if player_idx == self.current_player_idx() { if player_idx == 0 { - get_valid_action_indices(&self.game_state) + get_valid_action_indices(&self.game_state).unwrap() } else { let mirror = self.game_state.mirror(); - get_valid_action_indices(&mirror) + get_valid_action_indices(&mirror).unwrap() } } else { vec![] diff --git a/store/src/training_common.rs b/store/src/training_common.rs index 6427ea4..0cc635c 100644 --- a/store/src/training_common.rs +++ b/store/src/training_common.rs @@ -195,7 +195,7 @@ impl TrictracAction { } /// Obtient les actions valides pour l'état de jeu actuel -pub fn get_valid_actions(game_state: &GameState) -> Vec { +pub fn get_valid_actions(game_state: &GameState) -> anyhow::Result> { use crate::TurnStage; let mut valid_actions = Vec::new(); @@ -246,9 +246,9 @@ pub fn get_valid_actions(game_state: &GameState) -> Vec { } if valid_actions.is_empty() { - panic!("empty valid_actions for state {game_state}"); + anyhow::bail!("empty valid_actions for state {game_state}"); } - valid_actions + Ok(valid_actions) } fn checker_moves_to_trictrac_action( @@ -336,11 +336,12 @@ fn white_checker_moves_to_trictrac_action( } /// Retourne les indices des actions valides -pub fn get_valid_action_indices(game_state: &GameState) -> Vec { - get_valid_actions(game_state) +pub fn get_valid_action_indices(game_state: &GameState) -> anyhow::Result> { + let actions = get_valid_actions(game_state)?; + Ok(actions .into_iter() .map(|action| action.to_action_index()) - .collect() + .collect()) } /// Sélectionne une action valide aléatoire @@ -349,7 +350,7 @@ pub fn sample_valid_action(game_state: &GameState) -> Option { let valid_actions = get_valid_actions(game_state); let mut rng = rng(); - valid_actions.choose(&mut rng).cloned() + valid_actions.unwrap().choose(&mut rng).cloned() } #[cfg(test)]