initial implementation of MoveValueStats
This commit is contained in:
@@ -71,9 +71,11 @@ pub fn run() {
|
||||
.to_vec()
|
||||
})
|
||||
.flat_map(move |prev_c| {
|
||||
[ChildrenEvalMethod::MinMax].map(move |method| FutureMoveConfig {
|
||||
children_eval_method: method,
|
||||
..prev_c
|
||||
[ChildrenEvalMethod::MinMax, ChildrenEvalMethod::MinMaxProb].map(move |method| {
|
||||
FutureMoveConfig {
|
||||
children_eval_method: method,
|
||||
..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::{
|
||||
logic::r#move::Move,
|
||||
repr::{Board, Piece, Winner},
|
||||
@@ -92,6 +92,8 @@ impl std::fmt::Display for FutureMoveConfig {
|
||||
pub enum ChildrenEvalMethod {
|
||||
/// Best so far?
|
||||
MinMax,
|
||||
|
||||
MinMaxProb,
|
||||
}
|
||||
|
||||
impl Default for ChildrenEvalMethod {
|
||||
@@ -296,25 +298,57 @@ impl FutureMoves {
|
||||
.map(|&child| self.arena[child].value)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let children_value = match self.config.children_eval_method {
|
||||
match self.config.children_eval_method {
|
||||
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
|
||||
// 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 {
|
||||
children_values.into_iter().max()
|
||||
children_values
|
||||
.into_iter()
|
||||
.max_by_key(|x| x.value)
|
||||
.map(|x| x.value)
|
||||
}
|
||||
.unwrap_or(0);
|
||||
// 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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
.unwrap_or(0);
|
||||
|
||||
// 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)
|
||||
self.arena[idx].value = self.arena[idx].self_value as i32 + children_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,48 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::board_value::BoardValueMap;
|
||||
use crate::repr::{Board, CoordPair, Piece, Winner};
|
||||
use allocative::Allocative;
|
||||
|
||||
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)]
|
||||
pub struct Move {
|
||||
/// Coordinates (i, j) of the move (if it exists)
|
||||
@@ -23,7 +62,7 @@ pub struct Move {
|
||||
pub children: Vec<usize>,
|
||||
|
||||
/// Value of this move (including children)
|
||||
pub value: i32,
|
||||
pub value: MoveValueStats,
|
||||
|
||||
/// What is the inherit value of this move (not including children)
|
||||
pub self_value: i16,
|
||||
@@ -50,7 +89,11 @@ impl Move {
|
||||
winner: board.game_winner(),
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
value: i32::MIN,
|
||||
value: MoveValueStats {
|
||||
wins: 0,
|
||||
losses: 0,
|
||||
value: 0,
|
||||
},
|
||||
color,
|
||||
is_trimmed: false,
|
||||
self_value: 0,
|
||||
|
||||
Reference in New Issue
Block a user