simple_mcts/game.rs
1//! Module defining traits for games and game evaluators used in MCTS.
2
3/// Trait defining the interface for a game that can be used with MCTS.
4///
5/// Implementations of this trait provide the core game logic,
6/// allowing the MCTS algorithm to simulate and analyze game states.
7///
8/// # Type Parameters
9/// - `N`: The number of possible actions in the game. This is a constant generic
10/// parameter, meaning the number of actions is fixed at compile time.
11pub trait Game<const N: usize>{
12 /// The associated type representing the immutable state of the game.
13 /// This type should ideally be lightweight. It can be use
14 /// in `GameEvaluator` or AI model for make prediction.
15 type State;
16
17 /// Creates a new instance of the game in its initial state.
18 ///
19 /// This is typically the starting point for any new MCTS simulation.
20 ///
21 /// # Returns
22 /// A new game instance initialized to its starting state.
23 ///
24 /// # Examples
25 /// ```rust*
26 /// use simple_mcts::Game;
27 /// use simple_mcts::test_utils::GameTest;
28 /// let game = GameTest::new();
29 /// // game is now in its initial state.
30 /// ```
31 fn new() -> Self;
32
33 /// Returns an array indicating which actions are currently valid from the current game state.
34 ///
35 /// An action is valid if it can be played at this specific moment in the game.
36 /// Actions are identified by their index (from 0 to `N-1`).
37 ///
38 /// # Returns
39 /// An array of booleans where `true` at index `i` means the action `i` is valid,
40 /// and `false` means it's invalid.
41 ///
42 /// # Examples
43 /// ```rust
44 /// use simple_mcts::Game;
45 /// use simple_mcts::test_utils::*;
46 /// let game = GameTest::new();
47 /// let actions = game.get_actions();
48 /// // For GameTest, initially all actions are valid: [true, true, true, true]
49 /// assert_eq!(actions, [true, true, true, true]);
50 /// ```
51 fn get_actions(&self) -> [bool; N];
52
53 /// Determines if the game has reached a terminal state (i.e., it's over).
54 ///
55 /// A game is finished if no more moves can be made, or if a win/loss/draw
56 /// condition has been met.
57 ///
58 /// # Returns
59 /// `true` if the game is finished, `false` otherwise.
60 ///
61 /// # Examples
62 /// ```rust
63 /// use simple_mcts::Game;
64 /// use simple_mcts::test_utils::GameTest;
65 /// let mut game = GameTest::new();
66 /// assert!(!game.is_finish());
67 /// game.play(0); game.play(1); game.play(2); game.play(3);
68 /// assert!(game.is_finish());
69 /// ```
70 fn is_finish(&self) -> bool;
71
72 /// Applies a given action to the game, transitioning it to a new state.
73 ///
74 /// This method modifies the current game instance. It's assumed that the
75 /// `action` provided is valid according to `get_actions`.
76 ///
77 /// # Parameters
78 /// - `action`: The index of the action to be played.
79 ///
80 /// # Panics
81 /// This method typically assumes `action` is valid. If `action` is out of bounds
82 /// or invalid for the current state, the behavior is implementation-defined
83 /// and may lead to a panic or incorrect state.
84 ///
85 /// # Examples
86 /// ```rust
87 /// use simple_mcts::Game;
88 /// use simple_mcts::test_utils::GameTest;
89 /// let mut game = GameTest::new();
90 /// assert_eq!(game.get_state(), [-1, -1, -1, -1]);
91 /// game.play(0);
92 /// assert_eq!(game.get_state(), [0, -1, -1, -1]);
93 /// ```
94 fn play(&mut self, action: usize);
95
96 /// Returns an immutable representation of the current game state.
97 ///
98 /// This state is typically used by `GameEvaluator` to assess the game
99 /// without needing to clone the entire `Game` instance.
100 ///
101 /// # Returns
102 /// The current state of the game.
103 ///
104 /// # Examples
105 /// ```rust
106 /// use simple_mcts::Game;
107 /// use simple_mcts::test_utils::GameTest;
108 /// let mut game = GameTest::new();
109 /// let initial_state = game.get_state();
110 /// // State for GameTest is an array [i32; 4] representing moves made.
111 /// assert_eq!(initial_state, [-1, -1, -1, -1]);
112 /// ```
113 fn get_state(&self) -> Self::State;
114
115 /// Returns the final result of the game if it has finished.
116 ///
117 /// The result is typically a value representing the outcome from the perspective
118 /// of the player whose turn it was when the game finished.
119 /// Common values include:
120 /// - `1.0`: Win for the current player.
121 /// - `0.0`: Draw.
122 /// - `-1.0`: Loss for the current player / win for opponent.
123 ///
124 /// # Returns
125 /// An `Option<f64>`:
126 /// - `Some(value)` if the game is finished and a result can be determined.
127 /// - `None` if the game is not yet finished.
128 ///
129 /// # Examples
130 /// ```rust
131 /// use simple_mcts::Game;
132 /// use simple_mcts::test_utils::GameTest;
133 /// let mut game = GameTest::new();
134 /// assert_eq!(game.get_result(), None);
135 /// game.play(0); game.play(1); game.play(2); game.play(3); // Finish the game
136 /// // The exact result depends on GameTest's internal logic.
137 /// // assert_eq!(game.get_result(), Some(...));
138 /// ```
139 fn get_result(&self) -> Option<f64>;
140
141 /// Creates a deep copy of the current game instance.
142 ///
143 /// This is crucial for MCTS as simulations often require creating independent
144 /// branches from a given game state without affecting the original.
145 ///
146 /// # Returns
147 /// A new, independent instance of the game with the same state.
148 ///
149 /// # Examples
150 /// ```rust
151 /// use simple_mcts::Game;
152 /// use simple_mcts::test_utils::*;
153 /// let original_game = GameTest::new();
154 /// let cloned_game = original_game.clone();
155 /// assert_eq!(original_game.get_state(), cloned_game.get_state());
156 /// ```
157 fn clone(&self) -> Self;
158}
159/// Trait for evaluating game states and providing policy suggestions.
160///
161/// Implementations of this trait are typically used by the MCTS algorithm
162/// during the simulation and expansion phases to assess game states and
163/// determine probabilities for subsequent actions. This trait allows for
164/// plugging in external evaluation models (e.g., neural networks).
165///
166/// # Type Parameters
167/// - `T`: The game type that this evaluator is designed for, implementing the `Game` trait.
168/// - `N`: The number of possible actions in the game, a constant generic parameter.
169
170pub trait GameEvaluator<T: Game<N>, const N: usize>{
171 /// Evaluates a given game state and returns an estimated value and
172 /// a probability distribution over possible actions (policy).
173 ///
174 /// The value estimate typically represents the likelihood of winning from this state,
175 /// often from the perspective of the current player, and commonly in the range `[-1.0, 1.0]`.
176 /// The policy array gives probabilities for each action, where `policy[i]` is the probability
177 /// of taking action `i`. The sum of probabilities for valid actions should ideally be 1.0.
178 ///
179 /// # Parameters
180 /// - `state`: The game state to evaluate. This is typically a `Game::State` type.
181 ///
182 /// # Returns
183 /// A tuple containing:
184 /// - `f64`: The estimated value of the state (e.g., from the current player's perspective).
185 /// - `[f64; N]`: An array of action probabilities (policy), where each element corresponds
186 /// to the probability of taking that action from the given state.
187 ///
188 /// # Examples
189 /// ```rust
190 /// use simple_mcts::{test_utils::{GameTest, GameEvaluatorTest2}, Game, GameEvaluator};
191 /// let evaluator = GameEvaluatorTest2::new();
192 /// let game = GameTest::new();
193 /// let initial_state = game.get_state();
194 /// let (value, policy) = evaluator.evaluate(initial_state);
195 /// println!("Initial state value: {}, policy: {:?}", value, policy);
196 /// ```
197 fn evaluate(&self, state: T::State) -> (f64, [f64; N]);
198}