mod game_engine;
mod types;
pub use game_engine::GameEngine;
pub use types::{Cell, GameState, MoveError, Player};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn x_wins_top_row() {
let mut game = GameEngine::new();
game.make_move(0).unwrap(); game.make_move(3).unwrap(); game.make_move(1).unwrap(); game.make_move(4).unwrap(); game.make_move(2).unwrap(); assert_eq!(game.check_state(), GameState::Win(Player::X));
}
#[test]
fn o_wins_diagonal() {
let mut game = GameEngine::new();
game.make_move(0).unwrap(); game.make_move(2).unwrap(); game.make_move(1).unwrap(); game.make_move(4).unwrap(); game.make_move(3).unwrap(); game.make_move(6).unwrap(); assert_eq!(game.check_state(), GameState::Win(Player::O));
}
#[test]
fn tie_game() {
let mut game = GameEngine::new();
let moves = [0, 1, 2, 4, 3, 5, 7, 6, 8];
for &i in &moves {
game.make_move(i).unwrap();
}
assert_eq!(game.check_state(), GameState::Tie);
}
#[test]
fn cannot_play_out_of_bounds() {
let mut game = GameEngine::new();
assert_eq!(game.make_move(9), Err(MoveError::OutOfBounds));
assert_eq!(game.make_move(99), Err(MoveError::OutOfBounds));
}
#[test]
fn cannot_play_on_occupied_cell() {
let mut game = GameEngine::new();
game.make_move(0).unwrap();
assert_eq!(game.make_move(0), Err(MoveError::CellOccupied));
}
#[test]
fn board_updates_correctly() {
let mut game = GameEngine::new();
game.make_move(0).unwrap();
let board = game.get_board();
assert_eq!(board[0], Cell::X);
}
#[test]
fn ai_blocks_win() {
let mut game = GameEngine::new();
game.make_move(0).unwrap(); game.make_move(4).unwrap(); game.make_move(1).unwrap(); assert_eq!(game.get_best_move(), Some(2));
}
#[test]
fn ai_chooses_winning_move() {
let mut game = GameEngine::new();
game.make_move(0).unwrap(); game.make_move(4).unwrap(); game.make_move(2).unwrap(); game.make_move(1).unwrap(); game.make_move(3).unwrap(); assert_eq!(game.get_best_move(), Some(7));
}
}