logical improvements and cleanup
This commit is contained in:
parent
2011ae001b
commit
3b07a67d2e
@ -12,10 +12,10 @@ 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 = 12;
|
const MAX_DEPTH: usize = 10;
|
||||||
Self {
|
Self {
|
||||||
color,
|
color,
|
||||||
future_moves: FutureMoves::new(color, MAX_DEPTH, 6),
|
future_moves: FutureMoves::new(color, MAX_DEPTH, 8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ impl Agent for ComplexAgent {
|
|||||||
fn next_move(&mut self, board: &Board) -> Option<(usize, usize)> {
|
fn next_move(&mut self, board: &Board) -> Option<(usize, usize)> {
|
||||||
self.future_moves.update(board);
|
self.future_moves.update(board);
|
||||||
|
|
||||||
println!("# of moves stored: {}", self.future_moves.len());
|
println!("# of moves stored: {}", self.future_moves.arena_len());
|
||||||
|
|
||||||
self.future_moves.best_move().inspect(|&(i, j)| {
|
self.future_moves.best_move().inspect(|&(i, j)| {
|
||||||
if !self.future_moves.update_root_coord(i, j) {
|
if !self.future_moves.update_root_coord(i, j) {
|
||||||
|
|||||||
@ -37,14 +37,10 @@ impl FutureMoves {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn arena_len(&self) -> usize {
|
||||||
self.arena.len()
|
self.arena.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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) {
|
||||||
@ -118,26 +114,17 @@ impl FutureMoves {
|
|||||||
// because we use [`Board::what_if`] later and we want to reduce calls to [`Board::propegate_from_dry`]
|
// because we use [`Board::what_if`] later and we want to reduce calls to [`Board::propegate_from_dry`]
|
||||||
Board::all_positions()
|
Board::all_positions()
|
||||||
.flat_map(|(i, j)| parent.board.what_if(i, j, new_color).map(move |x| (i, j, x)))
|
.flat_map(|(i, j)| parent.board.what_if(i, j, new_color).map(move |x| (i, j, x)))
|
||||||
.map(|(i, j, new_board)| Move {
|
.map(|(i, j, new_board)| Move::new(i, j, new_board, new_color, lazy_children, self.agent_color, Some(parent_idx))).collect();
|
||||||
i,
|
|
||||||
j,
|
|
||||||
board: new_board,
|
|
||||||
winner: new_board.game_winner(),
|
|
||||||
parent: Some(parent_idx),
|
|
||||||
children: Vec::new(),
|
|
||||||
value: 0,
|
|
||||||
color: new_color,
|
|
||||||
lazy_children,
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
// negative, because we want the max value to be at the first index
|
// negative, because we want the max value to be at the first index
|
||||||
new.sort_by_key(|x| -x.compute_self_value(self.agent_color));
|
// abs because we want the most EXTREME possible outcome (win or lose for example)
|
||||||
|
new.sort_by_key(|x| -x.self_value.abs());
|
||||||
|
|
||||||
// keep the TOP_K children `self.agent_color`-color moves
|
// keep the TOP_K children `self.agent_color`-color moves
|
||||||
const TOP_K_CHILDREN: usize = 1;
|
const TOP_K_CHILDREN: usize = 2;
|
||||||
|
|
||||||
// we want to keep only the best move of the agent
|
// we want to keep only the best move of the agent
|
||||||
if lazy_children && new_color == self.agent_color && new.len() > TOP_K_CHILDREN {
|
if lazy_children && new.len() > TOP_K_CHILDREN {
|
||||||
new.drain(TOP_K_CHILDREN..);
|
new.drain(TOP_K_CHILDREN..);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +143,7 @@ impl FutureMoves {
|
|||||||
} else {
|
} else {
|
||||||
self.arena.extend(new);
|
self.arena.extend(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_indices = start_idx..self.arena.len();
|
let new_indices = start_idx..self.arena.len();
|
||||||
|
|
||||||
self.arena[parent_idx].children.extend(new_indices.clone());
|
self.arena[parent_idx].children.extend(new_indices.clone());
|
||||||
@ -191,15 +179,14 @@ impl FutureMoves {
|
|||||||
// TODO! impl dynamic sorting based on children's states, maybe it propegates
|
// TODO! impl dynamic sorting based on children's states, maybe it propegates
|
||||||
// upwards using the `parent` field
|
// upwards using the `parent` field
|
||||||
// SAFETY! the sort_by_key function should not modify anything
|
// SAFETY! the sort_by_key function should not modify anything
|
||||||
unsafe { (*(self as *mut Self)).arena.get_unchecked_mut(idx) }
|
unsafe { &mut (*(self as *mut Self)) }.arena[idx]
|
||||||
.children
|
.children
|
||||||
// negative because we want the largest value in the first index
|
// negative because we want the largest value in the first index
|
||||||
.sort_by_key(|&x| -self.arena[x].value);
|
// abs so we get the most extreme solutions
|
||||||
|
// but base on `.value` for recursive behavior
|
||||||
|
.sort_by_key(|&x| -self.arena[x].value.abs());
|
||||||
|
|
||||||
let node = &self.arena[idx];
|
let children_value = self.arena[idx]
|
||||||
let self_value = node.compute_self_value(self.agent_color) / (depth + 1) as i64;
|
|
||||||
|
|
||||||
let children_value = node
|
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
.rev() // rev then reverse so we get an index starting from the back
|
.rev() // rev then reverse so we get an index starting from the back
|
||||||
@ -207,10 +194,11 @@ impl FutureMoves {
|
|||||||
// since children are sorted by value, we should weight the first one more
|
// since children are sorted by value, we should weight the first one more
|
||||||
.map(|(i, &child)| self.arena[child].value * (i as i64 + 1))
|
.map(|(i, &child)| self.arena[child].value * (i as i64 + 1))
|
||||||
.sum::<i64>()
|
.sum::<i64>()
|
||||||
.checked_div(node.children.len() as i64)
|
.checked_div((&self.arena[idx]).children.len() as i64)
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
self.arena[idx].value = self_value + children_value;
|
self.arena[idx].value =
|
||||||
|
self.arena[idx].self_value / (depth as i64 + 1) + children_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,6 +252,7 @@ impl FutureMoves {
|
|||||||
value: 0,
|
value: 0,
|
||||||
color: !self.agent_color,
|
color: !self.agent_color,
|
||||||
lazy_children: false,
|
lazy_children: false,
|
||||||
|
self_value: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,9 +24,11 @@ pub struct Move {
|
|||||||
/// Indices of this Move's Children
|
/// Indices of this Move's Children
|
||||||
pub children: Vec<usize>,
|
pub children: Vec<usize>,
|
||||||
|
|
||||||
/// Value of this move
|
/// Value of this move (including children)
|
||||||
pub value: i64,
|
pub value: i64,
|
||||||
|
|
||||||
|
pub self_value: i64,
|
||||||
|
|
||||||
pub color: Piece,
|
pub color: Piece,
|
||||||
|
|
||||||
pub lazy_children: bool,
|
pub lazy_children: bool,
|
||||||
@ -37,6 +39,32 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Move {
|
impl Move {
|
||||||
|
pub fn new(
|
||||||
|
i: usize,
|
||||||
|
j: usize,
|
||||||
|
board: Board,
|
||||||
|
color: Piece,
|
||||||
|
lazy_children: bool,
|
||||||
|
agent_color: Piece,
|
||||||
|
parent: Option<usize>,
|
||||||
|
) -> Self {
|
||||||
|
let mut m = Move {
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
board,
|
||||||
|
winner: board.game_winner(),
|
||||||
|
parent,
|
||||||
|
children: Vec::new(),
|
||||||
|
value: 0,
|
||||||
|
color,
|
||||||
|
lazy_children,
|
||||||
|
self_value: 0,
|
||||||
|
};
|
||||||
|
m.self_value = m.compute_self_value(agent_color);
|
||||||
|
m.value = m.self_value;
|
||||||
|
m
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn coords(&self) -> (usize, usize) {
|
pub const fn coords(&self) -> (usize, usize) {
|
||||||
(self.i, self.j)
|
(self.i, self.j)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user