game_player/lib.rs
1//! Game Player
2//!
3//! This crate provides the foundational traits and structures needed to implement a player for two-person perfect and hidden
4//! information games.
5//!
6//! # Minimax Search
7//!
8//! The crate includes a minimax search implementation with alpha-beta pruning and a transposition table to optimize performance.
9//!
10//! ## Key Integration Points
11//!
12//! 1. **Implement [`State`] trait**: Provides game state management and move application with associated Action type
13//! 2. **Implement [`StaticEvaluator`] trait**: Evaluates how good a position is for each player
14//! 3. **Implement [`ResponseGenerator`](minimax::ResponseGenerator) trait**: Generates all possible moves from a position
15//! 4. **Use [`search`](minimax::search)**: Combines everything to find the optimal move
16//! 5. **Use [`TranspositionTable`]**: Caches evaluations for better performance
17//!
18//! ## Example
19//!
20//! ```rust
21//! use std::cell::RefCell;
22//! use std::rc::Rc;
23//! use game_player::{PlayerId, State, StaticEvaluator, TranspositionTable};
24//! use game_player::minimax::{ResponseGenerator, search};
25//!
26//! // Simple game structures (chess-like for demonstration)
27//! #[derive(Debug, Clone, PartialEq)]
28//! struct GameMove { from: (u8, u8), to: (u8, u8) }
29//!
30//! #[derive(Debug, Clone)]
31//! struct GameState {
32//! board: u64, // Simplified board representation
33//! current_player: bool, // true = white/alice, false = black/bob
34//! move_count: u32,
35//! }
36//!
37//! impl GameState {
38//! fn new() -> Self {
39//! Self { board: 0x1234567890abcdef, current_player: true, move_count: 0 }
40//! }
41//!
42//! fn is_game_over(&self) -> bool { self.move_count > 50 }
43//!
44//! fn get_possible_moves(&self) -> Vec<GameMove> {
45//! // Simplified: generate a few dummy moves
46//! vec![
47//! GameMove { from: (0, 0), to: (1, 1) },
48//! GameMove { from: (0, 1), to: (1, 0) },
49//! GameMove { from: (1, 0), to: (2, 0) },
50//! ]
51//! }
52//! }
53//!
54//! // 1. Implement the State trait for your game
55//! impl State for GameState {
56//! type Action = GameMove;
57//!
58//! fn fingerprint(&self) -> u64 {
59//! // Create unique hash for transposition table
60//! self.board ^ (self.current_player as u64) << 63 ^ self.move_count as u64
61//! }
62//!
63//! fn whose_turn(&self) -> u8 {
64//! if self.current_player { PlayerId::ALICE as u8 } else { PlayerId::BOB as u8 }
65//! }
66//!
67//! fn is_terminal(&self) -> bool {
68//! self.is_game_over()
69//! }
70//!
71//! fn apply(&self, game_move: &Self::Action) -> Self {
72//! // Apply move and return new state
73//! Self {
74//! board: self.board.wrapping_add(1), // Simplified board update
75//! current_player: !self.current_player,
76//! move_count: self.move_count + 1,
77//! }
78//! }
79//! }
80//!
81//! // 2. Implement static evaluation for your game
82//! struct GameEvaluator;
83//!
84//! impl StaticEvaluator<GameState> for GameEvaluator {
85//! fn evaluate(&self, state: &GameState) -> f32 {
86//! if state.is_game_over() {
87//! return 0.0; // Draw
88//! }
89//! // Simple evaluation: favor the player with more "material" (simplified)
90//! (state.board.count_ones() as f32 - 16.0) * if state.current_player { 1.0 } else { -1.0 }
91//! }
92//!
93//! fn alice_wins_value(&self) -> f32 { 1000.0 }
94//! fn bob_wins_value(&self) -> f32 { -1000.0 }
95//! }
96//!
97//! // 3. Implement move generation for your game
98//! struct GameMoveGenerator;
99//!
100//! impl ResponseGenerator for GameMoveGenerator {
101//! type State = GameState;
102//!
103//! fn generate(&self, state: &Rc<Self::State>, _depth: i32) -> Vec<Box<Self::State>> {
104//! state.get_possible_moves()
105//! .into_iter()
106//! .map(|game_move| Box::new(state.apply(&game_move)))
107//! .collect()
108//! }
109//! }
110//!
111//! // 4. Use the minimax search to find the best move
112//! fn find_best_move() -> Option<GameState> {
113//! // Set up the game components
114//! let initial_state = Rc::new(GameState::new());
115//! let evaluator = GameEvaluator;
116//! let move_generator = GameMoveGenerator;
117//! let transposition_table = Rc::new(RefCell::new(TranspositionTable::new(10000, 100)));
118//!
119//! // Perform minimax search to find best move
120//! search(&transposition_table, &evaluator, &move_generator, &initial_state, 6)
121//! .map(|best_state| (*best_state).clone())
122//! }
123//!
124//! // Usage: Create an AI that can play your game
125//! let best_move = find_best_move();
126//! match best_move {
127//! Some(new_state) => println!("AI found best move, new state: {:?}", new_state),
128//! None => println!("No moves available"),
129//! }
130//! ```
131
132pub mod mcts;
133pub mod minimax;
134pub mod state;
135pub mod static_evaluator;
136pub mod transposition_table;
137
138pub use state::{PlayerId, State};
139pub use static_evaluator::StaticEvaluator;
140pub use transposition_table::TranspositionTable;