create FutureMoveConfig

This commit is contained in:
Simon Gardling 2025-02-26 11:10:57 -05:00
parent d8f68e7fb1
commit ff87337512
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
5 changed files with 60 additions and 35 deletions

View File

@ -1,12 +1,18 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use othello::{
logic::FutureMoves,
logic::{FutureMoveConfig, FutureMoves},
repr::{Board, Piece},
};
use std::time::Duration;
fn extend_layers_test(depth: usize) {
let mut fut = FutureMoves::new(Piece::Black, depth);
let config = FutureMoveConfig {
max_depth: depth,
start_pruning_at_minus: 4,
top_k_children: 2,
up_to_mod: 4,
};
let mut fut = FutureMoves::new(Piece::Black, config);
fut.set_root_from_board(Board::new().starting_pos());
fut.extend_layers();
}

View File

@ -1,6 +1,6 @@
use crate::{
agent::Agent,
logic::FutureMoves,
logic::{FutureMoveConfig, FutureMoves},
repr::{Board, Piece},
};
@ -12,10 +12,15 @@ pub struct ComplexAgent {
#[allow(dead_code)]
impl ComplexAgent {
pub const fn new(color: Piece) -> Self {
const MAX_DEPTH: usize = 9;
const CONFIG: FutureMoveConfig = FutureMoveConfig {
max_depth: 7,
start_pruning_at_minus: 4,
top_k_children: 2,
up_to_mod: 4,
};
Self {
color,
future_moves: FutureMoves::new(color, MAX_DEPTH),
future_moves: FutureMoves::new(color, CONFIG),
}
}
}

View File

@ -15,21 +15,37 @@ pub struct FutureMoves {
/// Current generated depth of the Arena
current_depth: usize,
/// Target depth of children to generate
max_depth: usize,
/// Color w.r.t
agent_color: Piece,
config: FutureMoveConfig,
}
#[derive(Default)]
pub struct FutureMoveConfig {
/// Max depth of that we should try and traverse
pub max_depth: usize,
/// start pruning at X depth before self.max_depth is reached
/// used for pruning during tree generation before the tree is fully grown
pub start_pruning_at_minus: usize,
/// when pruning, keep the top_k # of children
pub top_k_children: usize,
// the lower the value, the more conservative the pruning is, what level to stop pruning at?
// a lower value allows more possible paths
pub up_to_mod: usize,
}
impl FutureMoves {
pub const fn new(agent_color: Piece, max_depth: usize) -> Self {
pub const fn new(agent_color: Piece, config: FutureMoveConfig) -> Self {
Self {
arena: Vec::new(),
current_root: None,
current_depth: 0,
max_depth,
agent_color,
config,
}
}
@ -41,7 +57,7 @@ impl FutureMoves {
/// Generate children for all children of `nodes`
/// only `pub` for the sake of benchmarking
pub fn extend_layers(&mut self) {
for i in (self.current_depth + 1)..=self.max_depth {
for i in (self.current_depth + 1)..=self.config.max_depth {
(0..self.arena.len())
// we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated)
.filter(|&idx| {
@ -54,7 +70,7 @@ impl FutureMoves {
.progress_with_style(
ProgressStyle::with_template(&format!(
"Generating children (depth: {}/{}): ({{pos}}/{{len}}) {{per_sec}}",
i, self.max_depth
i, self.config.max_depth
))
.unwrap(),
)
@ -66,9 +82,9 @@ impl FutureMoves {
self.current_depth += 1;
}
assert_eq!(
self.current_depth, self.max_depth,
self.current_depth, self.config.max_depth,
"iteration and extention did not extend current_depth ({}) to the max_depth ({})",
self.current_depth, self.max_depth
self.current_depth, self.config.max_depth
);
}
@ -323,23 +339,18 @@ impl FutureMoves {
let by_depth = self.by_depth(0..self.arena.len());
const TOP_K_CHIL: usize = 2;
// the lower the value, the more conservative, what level to stop pruning at?
// a lower value allows more possible paths
let up_to = self.current_depth - 2;
// start pruning at X depth before self.max_depth is reached
// used for pruning during tree generation before the tree is fully grown
const START_PRUNING_AT_MINUS: usize = 3;
if self.max_depth.saturating_sub(START_PRUNING_AT_MINUS) > self.current_depth {
if self
.config
.max_depth
.saturating_sub(self.config.start_pruning_at_minus)
> self.current_depth
{
return;
}
for (depth, indexes) in by_depth {
// TODO! maybe update by_depth every iteration or something?
if depth > up_to {
if depth > self.current_depth.saturating_sub(self.config.up_to_mod) {
return;
}
@ -355,8 +366,8 @@ impl FutureMoves {
}
m.is_trimmed = true;
m.sort_children(&mut self.arena);
if m.children.len() > TOP_K_CHIL {
let drained = m.children.drain(TOP_K_CHIL..);
if m.children.len() > self.config.top_k_children {
let drained = m.children.drain(self.config.top_k_children..);
for idx in drained {
self.arena[idx].parent = None;
}
@ -441,7 +452,8 @@ mod tests {
#[test]
fn prune_tree_test() {
let mut futm = FutureMoves::new(Piece::Black, 0);
let mut futm = FutureMoves::new(Piece::Black, Default::default());
futm.arena.push(Move {
i: 0,
j: 0,
@ -510,7 +522,9 @@ mod tests {
#[test]
fn expand_layer_test() {
let mut futm = FutureMoves::new(Piece::Black, 1);
let mut futm = FutureMoves::new(Piece::Black, Default::default());
futm.config.max_depth = 1;
futm.arena.push(Move::new(
0,
0,
@ -542,7 +556,7 @@ mod tests {
#[test]
fn depth_of_test() {
let mut futm = FutureMoves::new(Piece::Black, 0);
let mut futm = FutureMoves::new(Piece::Black, Default::default());
futm.arena.push(Move {
i: 0,
@ -606,7 +620,7 @@ mod tests {
#[test]
fn by_depth_test() {
let mut futm = FutureMoves::new(Piece::Black, 0);
let mut futm = FutureMoves::new(Piece::Black, Default::default());
futm.arena.push(Move {
i: 0,

View File

@ -1,4 +1,4 @@
mod board_value;
mod future_moves;
mod r#move;
pub use future_moves::FutureMoves;
pub use future_moves::{FutureMoveConfig, FutureMoves};

View File

@ -10,8 +10,8 @@ pub mod repr;
fn main() {
let player1 = complexagent::ComplexAgent::new(Piece::Black);
// let player2 = complexagent::ComplexAgent::new(Piece::White);
let player2 = agent::ManualAgent::new(Piece::White);
// let player2 = agent::RandomAgent::new(Piece::White);
// let player2 = agent::ManualAgent::new(Piece::White);
let player2 = agent::RandomAgent::new(Piece::White);
let mut game = Game::new(Box::new(player1), Box::new(player2));
game.game_loop();
}