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;