create FutureMoveConfig
This commit is contained in:
parent
d8f68e7fb1
commit
ff87337512
@ -1,12 +1,18 @@
|
|||||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||||
use othello::{
|
use othello::{
|
||||||
logic::FutureMoves,
|
logic::{FutureMoveConfig, FutureMoves},
|
||||||
repr::{Board, Piece},
|
repr::{Board, Piece},
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
fn extend_layers_test(depth: usize) {
|
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.set_root_from_board(Board::new().starting_pos());
|
||||||
fut.extend_layers();
|
fut.extend_layers();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
agent::Agent,
|
agent::Agent,
|
||||||
logic::FutureMoves,
|
logic::{FutureMoveConfig, FutureMoves},
|
||||||
repr::{Board, Piece},
|
repr::{Board, Piece},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12,10 +12,15 @@ pub struct ComplexAgent {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl ComplexAgent {
|
impl ComplexAgent {
|
||||||
pub const fn new(color: Piece) -> Self {
|
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 {
|
Self {
|
||||||
color,
|
color,
|
||||||
future_moves: FutureMoves::new(color, MAX_DEPTH),
|
future_moves: FutureMoves::new(color, CONFIG),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,21 +15,37 @@ pub struct FutureMoves {
|
|||||||
/// Current generated depth of the Arena
|
/// Current generated depth of the Arena
|
||||||
current_depth: usize,
|
current_depth: usize,
|
||||||
|
|
||||||
/// Target depth of children to generate
|
|
||||||
max_depth: usize,
|
|
||||||
|
|
||||||
/// Color w.r.t
|
/// Color w.r.t
|
||||||
agent_color: Piece,
|
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 {
|
impl FutureMoves {
|
||||||
pub const fn new(agent_color: Piece, max_depth: usize) -> Self {
|
pub const fn new(agent_color: Piece, config: FutureMoveConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
arena: Vec::new(),
|
arena: Vec::new(),
|
||||||
current_root: None,
|
current_root: None,
|
||||||
current_depth: 0,
|
current_depth: 0,
|
||||||
max_depth,
|
|
||||||
agent_color,
|
agent_color,
|
||||||
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +57,7 @@ impl FutureMoves {
|
|||||||
/// Generate children for all children of `nodes`
|
/// Generate children for all children of `nodes`
|
||||||
/// only `pub` for the sake of benchmarking
|
/// only `pub` for the sake of benchmarking
|
||||||
pub fn extend_layers(&mut self) {
|
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())
|
(0..self.arena.len())
|
||||||
// we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated)
|
// we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated)
|
||||||
.filter(|&idx| {
|
.filter(|&idx| {
|
||||||
@ -54,7 +70,7 @@ impl FutureMoves {
|
|||||||
.progress_with_style(
|
.progress_with_style(
|
||||||
ProgressStyle::with_template(&format!(
|
ProgressStyle::with_template(&format!(
|
||||||
"Generating children (depth: {}/{}): ({{pos}}/{{len}}) {{per_sec}}",
|
"Generating children (depth: {}/{}): ({{pos}}/{{len}}) {{per_sec}}",
|
||||||
i, self.max_depth
|
i, self.config.max_depth
|
||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
@ -66,9 +82,9 @@ impl FutureMoves {
|
|||||||
self.current_depth += 1;
|
self.current_depth += 1;
|
||||||
}
|
}
|
||||||
assert_eq!(
|
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 ({})",
|
"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());
|
let by_depth = self.by_depth(0..self.arena.len());
|
||||||
|
|
||||||
const TOP_K_CHIL: usize = 2;
|
if self
|
||||||
|
.config
|
||||||
// the lower the value, the more conservative, what level to stop pruning at?
|
.max_depth
|
||||||
// a lower value allows more possible paths
|
.saturating_sub(self.config.start_pruning_at_minus)
|
||||||
let up_to = self.current_depth - 2;
|
> self.current_depth
|
||||||
|
{
|
||||||
// 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 {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (depth, indexes) in by_depth {
|
for (depth, indexes) in by_depth {
|
||||||
// TODO! maybe update by_depth every iteration or something?
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,8 +366,8 @@ impl FutureMoves {
|
|||||||
}
|
}
|
||||||
m.is_trimmed = true;
|
m.is_trimmed = true;
|
||||||
m.sort_children(&mut self.arena);
|
m.sort_children(&mut self.arena);
|
||||||
if m.children.len() > TOP_K_CHIL {
|
if m.children.len() > self.config.top_k_children {
|
||||||
let drained = m.children.drain(TOP_K_CHIL..);
|
let drained = m.children.drain(self.config.top_k_children..);
|
||||||
for idx in drained {
|
for idx in drained {
|
||||||
self.arena[idx].parent = None;
|
self.arena[idx].parent = None;
|
||||||
}
|
}
|
||||||
@ -441,7 +452,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prune_tree_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 {
|
futm.arena.push(Move {
|
||||||
i: 0,
|
i: 0,
|
||||||
j: 0,
|
j: 0,
|
||||||
@ -510,7 +522,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expand_layer_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(
|
futm.arena.push(Move::new(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -542,7 +556,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn depth_of_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 {
|
futm.arena.push(Move {
|
||||||
i: 0,
|
i: 0,
|
||||||
@ -606,7 +620,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn by_depth_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 {
|
futm.arena.push(Move {
|
||||||
i: 0,
|
i: 0,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
mod board_value;
|
mod board_value;
|
||||||
mod future_moves;
|
mod future_moves;
|
||||||
mod r#move;
|
mod r#move;
|
||||||
pub use future_moves::FutureMoves;
|
pub use future_moves::{FutureMoveConfig, FutureMoves};
|
||||||
|
|||||||
@ -10,8 +10,8 @@ pub mod repr;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let player1 = complexagent::ComplexAgent::new(Piece::Black);
|
let player1 = complexagent::ComplexAgent::new(Piece::Black);
|
||||||
// let player2 = complexagent::ComplexAgent::new(Piece::White);
|
// let player2 = complexagent::ComplexAgent::new(Piece::White);
|
||||||
let player2 = agent::ManualAgent::new(Piece::White);
|
// let player2 = agent::ManualAgent::new(Piece::White);
|
||||||
// let player2 = agent::RandomAgent::new(Piece::White);
|
let player2 = agent::RandomAgent::new(Piece::White);
|
||||||
let mut game = Game::new(Box::new(player1), Box::new(player2));
|
let mut game = Game::new(Box::new(player1), Box::new(player2));
|
||||||
game.game_loop();
|
game.game_loop();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user