initial implementation of MoveValueStats
This commit is contained in:
@@ -71,9 +71,11 @@ pub fn run() {
|
|||||||
.to_vec()
|
.to_vec()
|
||||||
})
|
})
|
||||||
.flat_map(move |prev_c| {
|
.flat_map(move |prev_c| {
|
||||||
[ChildrenEvalMethod::MinMax].map(move |method| FutureMoveConfig {
|
[ChildrenEvalMethod::MinMax, ChildrenEvalMethod::MinMaxProb].map(move |method| {
|
||||||
|
FutureMoveConfig {
|
||||||
children_eval_method: method,
|
children_eval_method: method,
|
||||||
..prev_c
|
..prev_c
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.flat_map(move |prev_c| {
|
.flat_map(move |prev_c| {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::r#move::{MoveCoord, MoveValueConfig};
|
use super::r#move::{MoveCoord, MoveValueConfig, MoveValueStats};
|
||||||
use crate::{
|
use crate::{
|
||||||
logic::r#move::Move,
|
logic::r#move::Move,
|
||||||
repr::{Board, Piece, Winner},
|
repr::{Board, Piece, Winner},
|
||||||
@@ -92,6 +92,8 @@ impl std::fmt::Display for FutureMoveConfig {
|
|||||||
pub enum ChildrenEvalMethod {
|
pub enum ChildrenEvalMethod {
|
||||||
/// Best so far?
|
/// Best so far?
|
||||||
MinMax,
|
MinMax,
|
||||||
|
|
||||||
|
MinMaxProb,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ChildrenEvalMethod {
|
impl Default for ChildrenEvalMethod {
|
||||||
@@ -296,25 +298,57 @@ impl FutureMoves {
|
|||||||
.map(|&child| self.arena[child].value)
|
.map(|&child| self.arena[child].value)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let children_value = match self.config.children_eval_method {
|
match self.config.children_eval_method {
|
||||||
ChildrenEvalMethod::MinMax => {
|
ChildrenEvalMethod::MinMax => {
|
||||||
if self.arena[idx].color == self.agent_color {
|
let children_value = if self.arena[idx].color == self.agent_color {
|
||||||
// get best (for the adversary) enemy play
|
// get best (for the adversary) enemy play
|
||||||
// this assumes the adversary is playing optimally
|
// this assumes the adversary is playing optimally
|
||||||
|
|
||||||
children_values.into_iter().min()
|
children_values
|
||||||
|
.into_iter()
|
||||||
|
.min_by_key(|x| x.value)
|
||||||
|
.map(|x| x.value)
|
||||||
} else {
|
} else {
|
||||||
children_values.into_iter().max()
|
children_values
|
||||||
}
|
.into_iter()
|
||||||
}
|
.max_by_key(|x| x.value)
|
||||||
|
.map(|x| x.value)
|
||||||
}
|
}
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
// we use `depth` and divided `self_value` by it, idk if this is worth it
|
// we use `depth` and divided `self_value` by it, idk if this is worth it
|
||||||
// we should really setup some sort of ELO rating for each commit, playing them against
|
// we should really setup some sort of ELO rating for each commit, playing them against
|
||||||
// each other or something, could be cool to benchmark these more subjective things, not
|
// each other or something, could be cool to benchmark these more subjective things, not
|
||||||
// just performance (cycles/time wise)
|
// just performance (cycles/time wise)
|
||||||
self.arena[idx].value = self.arena[idx].self_value as i32 + children_value;
|
self.arena[idx].value.value =
|
||||||
|
self.arena[idx].self_value as i32 + children_value;
|
||||||
|
}
|
||||||
|
ChildrenEvalMethod::MinMaxProb => {
|
||||||
|
let children_value = if self.arena[idx].color == self.agent_color {
|
||||||
|
// get best (for the adversary) enemy play
|
||||||
|
// this assumes the adversary is playing optimally
|
||||||
|
|
||||||
|
children_values.iter().min()
|
||||||
|
} else {
|
||||||
|
children_values.iter().max()
|
||||||
|
}
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(Default::default());
|
||||||
|
// we use `depth` and divided `self_value` by it, idk if this is worth it
|
||||||
|
// we should really setup some sort of ELO rating for each commit, playing them against
|
||||||
|
// each other or something, could be cool to benchmark these more subjective things, not
|
||||||
|
// just performance (cycles/time wise)
|
||||||
|
|
||||||
|
let wins = children_values.iter().map(|x| x.wins).sum();
|
||||||
|
let losses = children_values.iter().map(|x| x.losses).sum();
|
||||||
|
|
||||||
|
let final_value = MoveValueStats {
|
||||||
|
wins,
|
||||||
|
losses,
|
||||||
|
value: self.arena[idx].self_value as i32 + children_value.value,
|
||||||
|
};
|
||||||
|
self.arena[idx].value = final_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,48 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use super::board_value::BoardValueMap;
|
use super::board_value::BoardValueMap;
|
||||||
use crate::repr::{Board, CoordPair, Piece, Winner};
|
use crate::repr::{Board, CoordPair, Piece, Winner};
|
||||||
use allocative::Allocative;
|
use allocative::Allocative;
|
||||||
|
|
||||||
pub type MoveCoord = Option<CoordPair>;
|
pub type MoveCoord = Option<CoordPair>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Allocative, PartialEq, Eq, Default)]
|
||||||
|
pub struct MoveValueStats {
|
||||||
|
pub wins: u16,
|
||||||
|
pub losses: u16,
|
||||||
|
pub value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MoveValueStats {
|
||||||
|
pub fn chance_win(&self) -> f32 {
|
||||||
|
self.wins as f32 / (self.losses + self.wins) as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for MoveValueStats {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for MoveValueStats {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
if self.wins != 0 || self.losses != 0 || other.wins != 0 || other.losses != 0 {
|
||||||
|
let s_cw = self.chance_win();
|
||||||
|
let o_cw = other.chance_win();
|
||||||
|
if s_cw > o_cw {
|
||||||
|
Ordering::Greater
|
||||||
|
} else if o_cw > s_cw {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.value.cmp(&other.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Allocative)]
|
#[derive(Clone, Debug, Allocative)]
|
||||||
pub struct Move {
|
pub struct Move {
|
||||||
/// Coordinates (i, j) of the move (if it exists)
|
/// Coordinates (i, j) of the move (if it exists)
|
||||||
@@ -23,7 +62,7 @@ pub struct Move {
|
|||||||
pub children: Vec<usize>,
|
pub children: Vec<usize>,
|
||||||
|
|
||||||
/// Value of this move (including children)
|
/// Value of this move (including children)
|
||||||
pub value: i32,
|
pub value: MoveValueStats,
|
||||||
|
|
||||||
/// What is the inherit value of this move (not including children)
|
/// What is the inherit value of this move (not including children)
|
||||||
pub self_value: i16,
|
pub self_value: i16,
|
||||||
@@ -50,7 +89,11 @@ impl Move {
|
|||||||
winner: board.game_winner(),
|
winner: board.game_winner(),
|
||||||
parent: None,
|
parent: None,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
value: i32::MIN,
|
value: MoveValueStats {
|
||||||
|
wins: 0,
|
||||||
|
losses: 0,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
color,
|
color,
|
||||||
is_trimmed: false,
|
is_trimmed: false,
|
||||||
self_value: 0,
|
self_value: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user