@@ -0,0 +1,256 @@
use super::*;
use rand;
use std::default::Default;
use std::fmt;
pub const SIZE: usize = 3;
pub const REQ: usize = 3;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Marker {
X,
O,
}

impl Marker {
fn flip(&self) -> Marker {
match *self {
Marker::X => Marker::O,
Marker::O => Marker::X,
}
}
}

impl rand::Rand for Marker {
fn rand<R: rand::Rng>(rng: &mut R) -> Marker {
if rng.gen() {
return Marker::X;
}
Marker::O
}
}

impl fmt::Display for Marker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match *self {
Marker::X => "X",
Marker::O => "O",
}
)
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Square(Option<Marker>);

impl fmt::Display for Square {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
None => write!(f, " "),
Some(x) => write!(f, "{}", x),
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Board {
board: [Square; SIZE * SIZE],
}

impl Board {
pub fn get(&self, i: usize, j: usize) -> Square {
self.board[i * SIZE + j]
}

pub fn set(&mut self, i: usize, j: usize, x: Marker) {
(*self).board[i * SIZE + j] = Square(Some(x));
}
}

impl Default for Board {
fn default() -> Self {
Board { board: [Square(None); SIZE * SIZE] }
}
}

impl fmt::Display for Board {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let dashes: String = (0..SIZE * 3).map(|_| "-").collect();
// for row in self.board.iter().rev() {
writeln!(f, "|{}|", dashes.as_str())?;
for i in 0..SIZE {
write!(f, "|")?;
for j in 0..SIZE {
write!(f, " {} ", self.get(i, j))?;
}
writeln!(f, "|")?;
}
writeln!(f, "|{}|", dashes.as_str())?;
write!(f, " ")?;
for i in 0..SIZE {
write!(f, " {} ", i + 1)?;
}
writeln!(f, " ")
}
}

#[derive(Clone, Hash, PartialEq, Eq)]
pub struct TicTacToe {
state: Board,
to_act: Marker,
ref_player: Marker,
winner: Option<Marker>,
}

impl fmt::Display for TicTacToe {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Acting: {}, Ref: {}", self.to_act, self.ref_player)?;
writeln!(f, "{}", self.state)
}
}

impl Game for TicTacToe {
type Move = (usize, usize, Self::Agent);
type Agent = Marker;

fn agent_id(&self, &a: &Self::Agent) -> u32 {
match a {
Marker::X => 0,
Marker::O => 1,
}
}

fn winner(&self) -> Option<Self::Agent> {
self.winner
}

fn ref_player(&self) -> Self::Agent {
self.ref_player
}

fn move_valid(&self, &m: &Self::Move) -> bool {
// TODO : Is this fine?
!self.state.get(m.0, m.1).0.is_some()
}

fn new(&start: &Self::Agent) -> Self {
let board = Board::default();
TicTacToe {
to_act: start,
ref_player: start,
state: board,
winner: None,
}
}

fn to_act(&self) -> Self::Agent {
self.to_act
}

fn player_weight(&self, &p: &Self::Agent) -> Score {
if p == self.ref_player() {
return 1;
}

-1
}

fn possible_moves(&self) -> Vec<ValidMove<Self>> {
let marker = self.to_act();
let mut moves = Vec::new();
for i in 0..SIZE {
for j in 0..SIZE {
if !self.state.get(i, j).0.is_some() {
moves.push(ValidMove {
valid_move: (i, j, marker),
valid_for: self.clone(),
});
}
}
}
moves
}


fn apply(&mut self, m: Self::Move) {
let (i, j, marker) = m;
match self.state.get(i, j) {
Square(Some(_)) => (),
Square(None) => {
self.state.set(i, j, marker);
if self.has_won(&marker) {
self.winner = Some(marker);
}
self.to_act = self.to_act.flip();
return;
}
}
panic!("This shouldn't happen for validated moves.");
}

fn has_won(&self, &marker: &Marker) -> bool {
// horizontalCheck
let value = |i, j, m| {
if i < SIZE && j < SIZE{
if self.state.get(i,j) == m {
return 1;
}
}
0
};
let marker = Square(Some(marker));
let get = |i, j| self.state.get(j, i);
for i in 0..SIZE {
for j in 0..SIZE {
if (0..REQ).map(|n| value(i, j + n, marker)).sum::<usize>() == REQ {
return true;
}
if (0..REQ).map(|n| value(i + n, j, marker)).sum::<usize>() == REQ {
return true;
}
if (0..REQ).map(|n| value(i + n, j + n, marker)).sum::<usize>() == REQ {
return true;
}
if (0..REQ).map(|n| value(i + n, j - n, marker)).sum::<usize>() == REQ {
return true;
}
}
}
false
}
}

impl ParseGame for TicTacToe {
fn parse_move(&self, input: &str) -> Option<Self::Move> {
let mut words = input.split_whitespace();
let mut it = Vec::new();
for _ in 0..2 {
it.push(
words
.next()
.expect("invalid input.")
.parse::<usize>()
.expect("invalid input"),
);
}
Some((it[0], it[1], self.to_act()))

}
}

impl RandGame for TicTacToe {
fn random_move<R: rand::Rng>(&mut self, rng: &mut R) -> Option<ValidMoveMut<Self>> {
let mut moves = self.possible_moves();
if moves.len() == 0 {
None
} else {
rng.shuffle(&mut moves);
Some(ValidMoveMut {
valid_move: moves[0].valid_move,
valid_for: self,
})
}
}
}
@@ -24,9 +24,10 @@ pub struct Negamax<G: Hash> {


impl<G> Negamax<G>
where G: RandGame + Send + fmt::Display + Hash + Eq,
G::Agent: Send,
G::Move: Send + Ord
where
G: RandGame + Send + fmt::Display + Hash + Eq,
G::Agent: Send,
G::Move: Send + Ord,
{
fn heuristic(&mut self, game: G) -> usize {
if let Some(v) = self.state.cache.get(&game) {
@@ -53,7 +54,8 @@ impl<G> Negamax<G>
let weight = game.player_weight(&game.to_act());
return (self.heuristic(game) as Score * weight, None);
}
nexts.into_iter()
nexts
.into_iter()
.map(|mv| {
let m = *mv.valid_move();
let new_game = mv.apply();
@@ -66,9 +68,10 @@ impl<G> Negamax<G>
}

impl<G> Strategy<G> for Negamax<G>
where G: RandGame + Send + fmt::Display + Hash + Eq,
G::Agent: Send,
G::Move: Send + Ord
where
G: RandGame + Send + fmt::Display + Hash + Eq,
G::Agent: Send,
G::Move: Send + Ord,
{
type Params = NegamaxParams;
fn decide(&mut self, game: &G) -> G::Move {