pub struct Game { /* private fields */ }Expand description
Represents the state of a Second Best game.
This struct maintains the complete game state including the board, player turns, action history, and legal moves.
§Examples
use secondbest::prelude::*;
// Create a new game
let mut game = Game::new();
// Apply some actions
game.apply_action(Action::Put(Position::N, Color::B)).unwrap();
game.apply_action(Action::Put(Position::S, Color::W)).unwrap();
// Check if second best can be declared
if game.can_declare_second_best() {
game.declare_second_best().unwrap();
}
// Check the game result
match game.result() {
GameResult::Finished { winner } => println!("Winner: {:?}", winner),
GameResult::InProgress => println!("Game still in progress"),
}Implementations§
Source§impl Game
impl Game
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new game with the default initial state.
The game starts with an empty board and Black as the first player.
§Examples
use secondbest::prelude::*;
let game = Game::new();
assert!(matches!(game.result(), GameResult::InProgress));Sourcepub fn board(&self) -> &Board
pub fn board(&self) -> &Board
Returns a reference to the current game board.
§Examples
use secondbest::prelude::*;
let game = Game::new();
let board = game.board();
assert_eq!(board.count_pieces(Color::B), 0);
assert_eq!(board.count_pieces(Color::W), 0);Sourcepub fn current_player(&self) -> Color
pub fn current_player(&self) -> Color
Returns the current player.
§Examples
use secondbest::prelude::*;
let game = Game::new();
assert_eq!(game.current_player(), Color::B);Sourcepub fn is_legal_action(&self, action: Action) -> bool
pub fn is_legal_action(&self, action: Action) -> bool
Checks if a given action is legal in the current game state.
§Examples
use secondbest::prelude::*;
let game = Game::new();
// In a new game, placing a black piece at any position is legal
assert!(game.is_legal_action(Action::Put(Position::N, Color::B)));
// But placing a white piece is not (it's not white's turn)
assert!(!game.is_legal_action(Action::Put(Position::N, Color::W)));Sourcepub fn legal_actions(&self) -> &[Action]
pub fn legal_actions(&self) -> &[Action]
Returns a slice of all legal actions for the current player.
§Examples
use secondbest::prelude::*;
let game = Game::new();
let legal_actions = game.legal_actions();
// In a new game, there are 8 legal actions (placing a black piece at any position)
assert_eq!(legal_actions.len(), 8);Sourcepub fn apply_action(&mut self, action: Action) -> Result<(), GameError>
pub fn apply_action(&mut self, action: Action) -> Result<(), GameError>
Applies an action to the game state.
This method updates the board, switches the current player, and recalculates legal actions for the next player.
§Errors
Returns GameError::GameAlreadyOver if the game has already finished.
Returns GameError::IllegalAction if the action is not legal in the current state.
§Examples
use secondbest::prelude::*;
let mut game = Game::new();
// Apply a legal action
assert!(game.apply_action(Action::Put(Position::N, Color::B)).is_ok());
// Trying to apply an illegal action (not white's turn)
let current_player = game.current_player();
assert_eq!(current_player, Color::W);
assert!(game.apply_action(Action::Put(Position::S, Color::B)).is_err());Sourcepub fn can_declare_second_best(&self) -> bool
pub fn can_declare_second_best(&self) -> bool
Checks if the current player can declare “second best”.
A player can declare “second best” only after their opponent’s first move in a turn (not after a second move following a previous “second best” declaration).
§Examples
use secondbest::prelude::*;
let mut game = Game::new();
// Initially, second best cannot be declared
assert!(!game.can_declare_second_best());
// After an action, the next player can declare second best
game.apply_action(Action::Put(Position::N, Color::B)).unwrap();
assert!(game.can_declare_second_best());
assert_eq!(game.current_player(), Color::W);Sourcepub fn declare_second_best(&mut self) -> Result<(), GameError>
pub fn declare_second_best(&mut self) -> Result<(), GameError>
Declares “second best”, forcing the opponent to choose a different action.
This method reverts the board to its previous state, switches back to the previous player, and marks the previous action as forbidden.
§Errors
Returns GameError::CannotDeclareSecondBest if “second best” cannot be declared
in the current state.
§Examples
use secondbest::prelude::*;
let mut game = Game::new();
// Apply an action
game.apply_action(Action::Put(Position::N, Color::B)).unwrap();
assert_eq!(game.current_player(), Color::W);
// Declare second best
assert!(game.declare_second_best().is_ok());
// The turn goes back to the previous player
assert_eq!(game.current_player(), Color::B);
// The previous action is now forbidden
assert!(!game.is_legal_action(Action::Put(Position::N, Color::B)));Sourcepub fn result(&self) -> GameResult
pub fn result(&self) -> GameResult
Determines the current result of the game.
The game is considered finished when:
- A player has achieved a winning condition (3 pieces in a stack or 4 consecutive top pieces)
- If both players achieve a winning condition simultaneously, the player who made the last move wins
- If a player has no legal moves available, they lose
Note: Winning conditions are only checked after all “second best” declarations have been used.
§Examples
use secondbest::prelude::*;
let mut game = Game::new();
// Initially, the game is in progress
assert!(matches!(game.result(), GameResult::InProgress));
// Create a sequence of moves
game.apply_action(Action::Put(Position::N, Color::B)).unwrap();
game.apply_action(Action::Put(Position::S, Color::W)).unwrap();
// Game is still in progress at this intermediate stage
assert!(matches!(game.result(), GameResult::InProgress));
game.apply_action(Action::Put(Position::N, Color::B)).unwrap();
game.apply_action(Action::Put(Position::S, Color::W)).unwrap();
game.apply_action(Action::Put(Position::E, Color::B)).unwrap();
// White declares "second best"
assert_eq!(game.current_player(), Color::W);
game.declare_second_best().unwrap();
// Black makes a winning move by stacking 3 pieces at North
assert_eq!(game.current_player(), Color::B);
game.apply_action(Action::Put(Position::N, Color::B)).unwrap();
// Game is finished with Black as the winner
assert_eq!(game.result().winner(), Some(Color::B));Sourcepub fn is_finished(&self) -> bool
pub fn is_finished(&self) -> bool
Checks if the game has finished.
This is a convenience method that checks the result of result().
It returns the same result as calling game.result().is_finished().
§Examples
use secondbest::prelude::*;
let game = Game::new();
assert!(!game.is_finished());
// After a winning move, the game would be finished
// let mut game = create_winning_game();
// assert!(game.is_finished());Sourcepub fn is_in_progress(&self) -> bool
pub fn is_in_progress(&self) -> bool
Checks if the game is still in progress.
This is a convenience method that checks the result of result().
It returns the same result as calling game.result().is_in_progress().
§Examples
use secondbest::prelude::*;
let game = Game::new();
assert!(game.is_in_progress());
// After a winning move, the game would no longer be in progress
// let mut game = create_winning_game();
// assert!(!game.is_in_progress());