Skip to main content

GameEngine

Struct GameEngine 

Source
pub struct GameEngine {
    pub current_player: Player,
    pub ai_enabled: bool,
    /* private fields */
}
Expand description

The core Tic-Tac-Toe game engine.

This struct manages the board, enforces rules, and provides an unbeatable AI opponent using the Minimax algorithm if enabled.

§Board Representation

The board is stored internally as a flat array of 9 cells.
Indices map to positions like this:

 0 | 1 | 2
-----------
 3 | 4 | 5
-----------
 6 | 7 | 8

§Game Modes

  • Human vs Human: Both players call [make_move] manually.
  • Human vs AI: calls [make_move], then queries [get_best_move] to find the AI’s move and applies it with [make_move].

§Examples

§Human vs Human

use xo_core::{GameEngine, Player};

let mut game = GameEngine::with_ai(false);

game.make_move(0).unwrap(); // X plays top-left
game.make_move(4).unwrap(); // O plays center

assert_eq!(game.current_player, Player::X);

§Human vs AI

use xo_core::GameEngine;

let mut game = GameEngine::with_ai(true);

game.make_move(0).unwrap(); // Human plays top-left

if let Some(ai_move) = game.get_best_move() {
    game.make_move(ai_move).unwrap(); // Apply AI move
}

Fields§

§current_player: Player

The player whose turn it is.

§ai_enabled: bool

Whether the AI is enabled.

  • true: Single-player vs AI
  • false: Human vs Human

Implementations§

Source§

impl GameEngine

Source

pub fn new() -> Self

Creates a new instance of the game engine with an empty board.

The game always starts with Player::X.
By default, AI is enabled.

§Example
use xo_core::{GameEngine, Player, Cell};

let game = GameEngine::new();
assert_eq!(game.current_player, Player::X);
assert!(game.get_board().iter().all(|&c| c == Cell::Empty));
assert!(game.ai_enabled);
Source

pub fn with_ai(ai_enabled: bool) -> Self

Creates a new instance of the game engine with an option to disable AI.

§Parameters
  • ai_enabled:
    • true: Single-player vs AI
    • false: Human vs Human
§Example
use xo_core::GameEngine;

let game = GameEngine::with_ai(false);
assert!(!game.ai_enabled);
Source

pub fn get_board(&self) -> &[Cell; 9]

Returns a reference to the current board.

Source

pub fn make_move(&mut self, index: usize) -> Result<(), MoveError>

Attempts to make a move for the current player at the given board index.

§Parameters
  • index: The 0-based cell index (0–8).
§Returns
  • Ok(()) if the move was made successfully.
  • Err(MoveError) if the move is invalid:
    • MoveError::OutOfBounds if index >= 9
    • MoveError::CellOccupied if the cell already has a mark
§Example
use xo_core::{GameEngine, MoveError};

let mut game = GameEngine::new();
assert!(game.make_move(0).is_ok());
assert_eq!(game.make_move(0), Err(MoveError::CellOccupied));
Source

pub fn check_state(&self) -> GameState

Returns the current state of the game.

Possible values:

  • GameState::InProgress
  • GameState::Tie
  • GameState::Won(Player::X)
  • GameState::Won(Player::O)
Source

pub fn is_over(&self) -> bool

Returns true if the game is finished (either win or draw).

Source

pub fn get_best_move(&self) -> Option<usize>

Calculates the best move for the current player using Minimax with pruning.

Returns:

  • Some(index) for the best move when AI is enabled.
  • None if the game is over or AI is disabled.
§Example
use xo_core::GameEngine;

let game = GameEngine::with_ai(false);
assert_eq!(game.get_best_move(), None); // AI disabled
§Example with AI
use xo_core::GameEngine;

let mut game = GameEngine::new();
game.make_move(0).unwrap(); // X
game.make_move(4).unwrap(); // O
game.make_move(1).unwrap(); // X

// O should block X's winning move at index 2
assert_eq!(game.get_best_move(), Some(2));

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.