#![allow(dead_code)]
extern crate minimax;
use std::default::Default;
use std::fmt::{Display, Formatter, Result};
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum Square {
Empty,
X,
O,
}
impl Square {
fn invert(&self) -> Self {
match *self {
Square::Empty => Square::Empty,
Square::X => Square::O,
Square::O => Square::X,
}
}
}
impl Default for Square {
fn default() -> Square {
Square::Empty
}
}
impl Display for Square {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(
f,
"{}",
match *self {
Square::Empty => ' ',
Square::X => 'X',
Square::O => 'O',
}
)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Board {
squares: [Square; 9],
to_move: Square,
}
impl Board {
fn just_moved(&self) -> Square {
self.to_move.invert()
}
}
impl Default for Board {
fn default() -> Board {
Board { squares: [Square::default(); 9], to_move: Square::X }
}
}
impl Display for Board {
fn fmt(&self, f: &mut Formatter) -> Result {
writeln!(f, "{} | {} | {}", self.squares[0], self.squares[1], self.squares[2])?;
writeln!(f, "{} | {} | {}", self.squares[3], self.squares[4], self.squares[5])?;
writeln!(f, "{} | {} | {}", self.squares[6], self.squares[7], self.squares[8])?;
Ok(())
}
}
pub struct Game;
impl minimax::Game for Game {
type S = Board;
type M = Place;
fn generate_moves(b: &Board, ms: &mut Vec<Place>) -> Option<minimax::Winner> {
if let Some(winner) = Self::get_winner(b) {
return Some(winner);
}
for i in 0..b.squares.len() {
if b.squares[i] == Square::Empty {
ms.push(Place { i: i as u8 });
}
}
None
}
fn get_winner(b: &Board) -> Option<minimax::Winner> {
if b.squares[0] == b.just_moved()
&& b.squares[0] == b.squares[1]
&& b.squares[1] == b.squares[2]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[3] == b.just_moved()
&& b.squares[3] == b.squares[4]
&& b.squares[4] == b.squares[5]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[6] == b.just_moved()
&& b.squares[6] == b.squares[7]
&& b.squares[7] == b.squares[8]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[0] == b.just_moved()
&& b.squares[0] == b.squares[3]
&& b.squares[3] == b.squares[6]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[1] == b.just_moved()
&& b.squares[1] == b.squares[4]
&& b.squares[4] == b.squares[7]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[2] == b.just_moved()
&& b.squares[2] == b.squares[5]
&& b.squares[5] == b.squares[8]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[0] == b.just_moved()
&& b.squares[0] == b.squares[4]
&& b.squares[4] == b.squares[8]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares[2] == b.just_moved()
&& b.squares[2] == b.squares[4]
&& b.squares[4] == b.squares[6]
{
return Some(minimax::Winner::PlayerJustMoved);
}
if b.squares.iter().all(|s| *s != Square::Empty) {
Some(minimax::Winner::Draw)
} else {
None
}
}
fn apply(b: &mut Board, m: Place) -> Option<Board> {
b.squares[m.i as usize] = b.to_move;
b.to_move = b.to_move.invert();
None
}
fn undo(b: &mut Board, m: Place) {
b.squares[m.i as usize] = Square::Empty;
b.to_move = b.to_move.invert();
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Place {
i: u8,
}
impl Display for Place {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "@{}", self.i)
}
}
pub struct Evaluator;
impl Default for Evaluator {
fn default() -> Self {
Self {}
}
}
impl minimax::Evaluator for Evaluator {
type G = Game;
fn evaluate(&self, b: &Board) -> minimax::Evaluation {
let mut score = 0;
for i in 0..3 {
let line = i * 3;
if b.squares[line + 0] == b.squares[line + 1] {
if b.squares[line + 0] == Square::X {
score += 5;
} else if b.squares[line + 0] == Square::O {
score -= 5;
}
}
if b.squares[line + 1] == b.squares[line + 2] {
if b.squares[line + 1] == Square::X {
score += 5;
} else if b.squares[line + 1] == Square::O {
score += 5;
}
}
if b.squares[i] == b.squares[3 + i] {
if b.squares[i] == Square::X {
score += 5;
} else if b.squares[i] == Square::O {
score -= 5;
}
}
if b.squares[3 + i] == b.squares[6 + i] {
if b.squares[3 + i] == Square::X {
score += 5;
} else if b.squares[3 + i] == Square::O {
score -= 5;
}
}
}
if b.squares[4] == Square::X {
score += 5;
}
if b.squares[4] == Square::O {
score -= 5;
}
if b.to_move == Square::X { score } else { -score }
}
}
fn main() {
use minimax::strategies::negamax::Negamax;
use minimax::{Game, Strategy};
let mut b = Board::default();
let mut strategies =
vec![Negamax::new(Evaluator::default(), 10), Negamax::new(Evaluator::default(), 10)];
let mut s = 0;
while self::Game::get_winner(&b).is_none() {
println!("{}", b);
let ref mut strategy = strategies[s];
match strategy.choose_move(&mut b) {
Some(m) => self::Game::apply(&mut b, m),
None => break,
};
s = 1 - s;
}
println!("{}", b);
}