Skip to content

Commit

Permalink
added FullSearchStrategy
Browse files Browse the repository at this point in the history
  • Loading branch information
SrTobi committed Sep 20, 2019
1 parent 6f21df0 commit 566e517
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 38 deletions.
37 changes: 5 additions & 32 deletions ailib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use rand::Rng;
use std::fmt;
use std::iter::{once, Once};

#[macro_use]
extern crate derive_builder;

pub mod strategies;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub enum Winner<P: fmt::Display> {
Player(P),
Draw,
Expand All @@ -24,7 +26,7 @@ impl <P: fmt::Display> fmt::Display for Winner<P> {

pub trait State: Clone {
type Action: fmt::Display;
type Player: fmt::Display;
type Player: Eq + Copy + fmt::Display;
type ActionEffect;
type ActionEffectIterator: Iterator<Item = Self::ActionEffect>;

Expand All @@ -40,7 +42,7 @@ pub trait State: Clone {

pub trait DeterministicState: Clone {
type Action: fmt::Display;
type Player: fmt::Display;
type Player: Eq + Copy + fmt::Display;

fn possible_actions(&self) -> Vec<Self::Action>;

Expand Down Expand Up @@ -111,35 +113,6 @@ pub trait Strategy<State: crate::State> {



/*
pub struct FullSearchStrategy;
impl FullSearchStrategy {
pub fn new() -> FullSearchStrategy {
FullSearchStrategy
}
}
impl <S: State> Strategy<S> for FullSearchStrategy {
type Rating = bool;
fn rated_actions(&self, state: &S) -> Vec<(S::Action, Self::Rating)> {
let actions = state.possible_actions();
for action in actions {
}
unimplemented!();
}
fn find_best_action(&self, state: &S)
}
*/



mod test {
#![allow(dead_code)]

Expand Down
97 changes: 97 additions & 0 deletions ailib/src/strategies/full_search_strategy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use crate::*;
use noisy_float::prelude::*;

#[derive(Builder, Copy, Clone, PartialEq)]
pub struct FullSearchStrategy {
#[builder(default = "n64(1.0)")]
win_reward: N64,

#[builder(default = "n64(0.2)")]
draw_reward: N64,

#[builder(default = "n64(0.0)")]
loose_reward: N64,
}

impl FullSearchStrategy {
pub fn new() -> FullSearchStrategy {
Default::default()
}

fn rate_action<S: State>(&self, state: &mut S, action: &S::Action, player: S::Player) -> N64 {
state
.action_effects(action)
.map(|effect| {
let possibility = n64(state.apply_effect(&effect));
let rating = self.rate_state(state, player);
state.unapply_effect(&effect);
possibility * rating
})
.sum()
}

fn rate_state<S: State>(&self, state: &mut S, player: S::Player) -> N64 {
if let Some(result) = state.winner() {
match result {
Winner::Draw => return self.draw_reward,
Winner::Player(winner) => {
return
if winner == player {
self.win_reward
} else {
self.loose_reward
}
}
}
}

let try_win = state.player() == player;

let actions = state.possible_actions();
let mut best =
if try_win {
-N64::infinity()
} else {
N64::infinity()
};
assert!(!actions.is_empty());
for action in actions {
let rate = self.rate_action(state, &action, player);
let is_better =
if try_win {
rate > best
} else {
rate < best
};
if is_better {
best = rate;
}
}
best
}
}


impl <S: State> Strategy<S> for FullSearchStrategy {
type Rating = N64;

fn rated_actions(&self, state: &S) -> Vec<(S::Action, Self::Rating)> {
let mut mut_state = state.clone();
state
.possible_actions()
.into_iter()
.map(|action| {
let rating = self.rate_action(&mut mut_state, &action, state.player());
(action, rating)
})
.collect()
}
}

impl Default for FullSearchStrategy {
fn default() -> FullSearchStrategy {
FullSearchStrategyBuilder::default()
.build()
.unwrap()
}
}
4 changes: 3 additions & 1 deletion ailib/src/strategies/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod random_strategy;
mod full_search_strategy;

pub use random_strategy::RandomStrategy;
pub use random_strategy::RandomStrategy;
pub use full_search_strategy::FullSearchStrategy;
15 changes: 12 additions & 3 deletions tictactoe-console/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
use tictactoe::*;
use ailib::{Strategy, DeterministicState};
use ailib::strategies::RandomStrategy;
use ailib::strategies::{RandomStrategy, FullSearchStrategy};
use std::collections::HashMap;

fn main() {
let mut state = TicTacToeState::initial();

fn to_fn(strat: impl Strategy<TicTacToeState>)
-> impl Fn(&TicTacToeState) -> Option<TicTacToeAction> {
move |state| strat.best_action(state)
}
loop {
println!("{}\n", state);

let strat: &dyn Strategy<TicTacToeState, Rating = u32> = &RandomStrategy::new();
let mut strats: HashMap<Stone, &dyn Fn(&TicTacToeState) -> Option<TicTacToeAction>> = Default::default();
let random_strat = to_fn(RandomStrategy::default());
let fullsearch_strat = to_fn(FullSearchStrategy::default());
strats.insert(Stone::Circle, &random_strat);
strats.insert(Stone::Cross, &fullsearch_strat);

match strat.best_action(&state) {
match strats[&state.player()](&state) {
Some(action) => state.apply_action(&action),
None => {
println!("Winner: {}\n", state.winner().unwrap());
Expand Down
4 changes: 2 additions & 2 deletions tictactoe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use ailib::{Winner, DeterministicState};
use std::fmt;
use std::fmt::Display;

#[derive(Copy, Clone, Eq, PartialEq, Display, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Display, Debug, Hash)]
pub enum Stone {
Circle,
Cross
}

#[derive(Clone)]
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct TicTacToeState {
fields: [[Option<Stone>; 3]; 3],
turn: u32,
Expand Down

0 comments on commit 566e517

Please sign in to comment.