Skip to content

Commit

Permalink
Select done in MCTS. MCTS for all movement types now. Bot works, but …
Browse files Browse the repository at this point in the history
…isn't very good. Seems to be choosing the same positions, with 100, 500, or 1000 iterations of MCTS
  • Loading branch information
UsAndRufus committed Jan 8, 2018
1 parent 88707ae commit f2310c9
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use montyman::Monty;
use indextree::Arena;

fn main() {
let p1 = Player::new(String::from("Ruth"), 1, Box::new(Random {}));
let p1 = Player::new(String::from("Ruth"), 1, Box::new(Human {}));

let p2 = Player::new(String::from("Monty"), 2,
Box::new(Monty { tree: Arena::new(), root: None, player_id: 2}));
Expand Down
57 changes: 50 additions & 7 deletions src/monty.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use rand::{thread_rng, Rng};
use indextree::*;
use std::collections::HashMap;

use nineman::game::*;
use nineman::game::Ply::*;
use nineman::player::InputHandler;

use statistic::Statistic;

const NUMBER_OF_SIMULATIONS: i8 = 10;
const NUMBER_OF_SIMULATIONS: i16 = 100;

pub struct Monty {
pub tree: Arena<Statistic>,
Expand All @@ -18,20 +19,40 @@ pub struct Monty {
impl Monty {

fn mcts(&mut self) -> Ply {
for _ in 1..NUMBER_OF_SIMULATIONS {
let node_to_expand = self.select(self.root.unwrap());
println!("Monty is thinking...");
for i in 1..NUMBER_OF_SIMULATIONS {
let root = self.root.unwrap();
let node_to_expand = self.select(root);
let new_node = self.expand(node_to_expand);
let payoff = self.simulate(new_node);
self.update(new_node, payoff);

if i % 10 == 0 {
println!("{}",i);
}
}

self.best_move()
}

// Recursively traverse from node, looking for most important expandable node
// Return when you reach non-expandable node
fn select(&self, node_id: NodeId) -> NodeId {
node_id
// NB: not convinced I have this right, it seems counter-intuitive.
// Seems like you will never visit unvisited children of expanded nodes, i.e. you only ever look at leaf nodes?
fn select(&mut self, node_id: NodeId) -> NodeId {
if self.is_expandable(node_id) {
self.expand(node_id)
} else {
let parent = &self.tree[node_id].data;
let children: HashMap<_,_>
= node_id.children(&self.tree)
.map(|c| (parent.uct(&self.tree[c].data), c))
.collect();

let max = children.keys().max().unwrap();

children.get(max).unwrap().clone()
}
}

// Node is expandable if it is non-terminal and has univisited children
Expand Down Expand Up @@ -160,11 +181,33 @@ impl InputHandler for Monty {
}

fn get_move(&mut self, available_moves: Vec<(String, String)>) -> (String, String) {
thread_rng().choose(&available_moves).unwrap().to_owned()
//thread_rng().choose(&available_moves).unwrap().to_owned()

let chosen = self.mcts();

match chosen {
Move {mv, ..} => {
assert!(available_moves.contains(&mv),
format!("Move impossible: available_moves: {:?}, mv: {:?}", available_moves, mv));
mv
},
_ => panic!("Moved from a move node using {:?}", chosen),
}
}

fn get_mill(&mut self, available_mills: Vec<String>) -> String {
thread_rng().choose(&available_mills).unwrap().to_string()
//thread_rng().choose(&available_mills).unwrap().to_string()

let chosen = self.mcts();

match chosen {
Mill {piece_id, ..} => {
assert!(available_mills.contains(&piece_id),
format!("Mill impossible: available_mills: {:?}, piece_id: {}", available_mills, piece_id));
piece_id
},
_ => panic!("Moved from a mill node using {:?}", chosen),
}
}

fn to_string(&self) -> String {
Expand Down
5 changes: 3 additions & 2 deletions src/statistic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ impl Statistic {
self.times_visited += 1;
}

pub fn uct(&self, child: &Statistic) -> f32 {
// this returns an integer as a hack so we can hash on it
pub fn uct(&self, child: &Statistic) -> i64 {
let average_payoff = child.sum_of_payoffs_received_f() /
child.times_visited_f();

Expand All @@ -35,7 +36,7 @@ impl Statistic {

let root_term = UCT_CONST * ln_term.sqrt();

average_payoff + root_term
((average_payoff + root_term) * 100000.0) as i64

}

Expand Down

0 comments on commit f2310c9

Please sign in to comment.