pub trait State: Sized {
type Action: Clone;
// Required methods
fn fingerprint(&self) -> u64;
fn whose_turn(&self) -> u8;
fn is_terminal(&self) -> bool;
fn apply(&self, action: &Self::Action) -> Self;
}Expand description
A trait representing the state.
This trait defines the core interface that a game-specific state must implement.
§Core Concepts
§Fingerprinting
A state must provide a unique fingerprint (hash) that can be used for:
- Transposition tables in game tree search
- Duplicate position detection
- State caching and memoization
§Turn Management
The trait tracks which player should move next, enabling:
- Alternating play enforcement
- Player-specific evaluation functions
- Turn-based game logic
§State Transitions
Game states can store references to expected responses, allowing:
- Pre-computed move sequences
- Principal variation storage
- Game tree navigation
§Examples
#[derive(Clone, Default)]
struct MyAction;
#[derive(Clone, Copy)]
struct MyGameState {
board: [u8; 64],
current_player: PlayerId,
game_over: bool,
// other game-specific fields...
}
impl State for MyGameState {
type Action = MyAction;
fn fingerprint(&self) -> u64 {
// Generate unique hash for this position
// Implementation depends on game specifics
42 // placeholder
}
fn whose_turn(&self) -> u8 {
self.current_player as u8
}
fn is_terminal(&self) -> bool {
self.game_over
}
fn apply(&self, _action: &MyAction) -> Self {
MyGameState {
board: self.board,
current_player: self.current_player.other(),
game_over: false,
}
}
}Required Associated Types§
Required Methods§
Sourcefn fingerprint(&self) -> u64
fn fingerprint(&self) -> u64
Returns a unique fingerprint (hash) for this state.
The fingerprint must be statistically unique across all possible game states to avoid hash collisions in transposition tables and state caches. Identical game positions must always produce identical fingerprints.
§Implementation Requirements
- Deterministic: Same position always produces same fingerprint
- Collision-resistant: Different positions should produce different and uncorrelated fingerprints
- Fast: Called frequently during game tree search
- Position-dependent: Only depends on the current state and independent of move history.
§Returns
A 64-bit unsigned integer representing the unique fingerprint
§Examples
let state = create_initial_state();
let fingerprint = state.fingerprint();
// Same position should produce same fingerprint
let same_state = create_initial_state();
assert_eq!(fingerprint, same_state.fingerprint());Sourcefn whose_turn(&self) -> u8
fn whose_turn(&self) -> u8
Returns the ID of the player whose turn it is to move.
§Returns
The id of the player of the player who should move next
§Examples
let state = MyGameState { current_player: PlayerId::ALICE };
match state.whose_turn() {
0 => println!("Alice to move"), // PlayerId::ALICE as u8
1 => println!("Bob to move"), // PlayerId::BOB as u8
_ => unreachable!(),
}Sourcefn is_terminal(&self) -> bool
fn is_terminal(&self) -> bool
Sourcefn apply(&self, action: &Self::Action) -> Self
fn apply(&self, action: &Self::Action) -> Self
Applies an action to the current state, returning a new state as a result of the action.
This method creates a new state by applying the given action to the current state. The original state remains unchanged (immutable transformation).
§Arguments
action- The action to apply to the current state
§Returns
A new state representing the position after applying the action
§Examples
let initial_state = MyGameState {
current_player: PlayerId::ALICE,
move_count: 0,
game_over: false
};
let action = MyAction { move_type: "play_tile".to_string() };
let new_state = initial_state.apply(&action);
// State should be updated
assert_eq!(new_state.whose_turn(), PlayerId::BOB as u8);
assert_ne!(new_state.fingerprint(), initial_state.fingerprint());
// Original state unchanged
assert_eq!(initial_state.whose_turn(), PlayerId::ALICE as u8);Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.