rewrite basically done
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
use std::num::NonZero;
|
||||
|
||||
use crate::{agent::Agent, board::Board, piece::Piece};
|
||||
use either::Either;
|
||||
use crate::{
|
||||
agent::Agent,
|
||||
board::{Board, Winner},
|
||||
piece::Piece,
|
||||
};
|
||||
use indicatif::{ProgressBar, ProgressIterator, ProgressStyle};
|
||||
use num::Integer;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Move {
|
||||
@@ -17,7 +17,7 @@ struct Move {
|
||||
board: Board,
|
||||
|
||||
/// Current winner of the match
|
||||
winner: Option<Piece>,
|
||||
winner: Winner,
|
||||
|
||||
/// Index of this move's parent
|
||||
parent: Option<usize>,
|
||||
@@ -35,15 +35,16 @@ impl Move {
|
||||
fn compute_self_value(&self, agent_color: Piece, depth: i64) -> i64 {
|
||||
let mut self_value = self.value;
|
||||
|
||||
if self.winner == Some(!agent_color) {
|
||||
if self.winner == Winner::Player(!agent_color) {
|
||||
// if this board results in the opponent winning, MAJORLY negatively weigh this move
|
||||
// NOTE! this branch isn't completely deleted because if so, the bot wouldn't make a move.
|
||||
// We shouldn't prune branches because we still need to always react to the opponent's moves
|
||||
self_value = i64::MIN;
|
||||
} else if self.winner == Some(agent_color) {
|
||||
} else if self.winner == Winner::Player(agent_color) {
|
||||
// results in a win for the agent
|
||||
self_value = i64::MAX;
|
||||
}
|
||||
// TODO! handle ties... what should they be valued as? maybe `i64::MAX / 2`?
|
||||
|
||||
self_value / depth
|
||||
}
|
||||
@@ -78,11 +79,11 @@ impl FutureMoves {
|
||||
.collect();
|
||||
|
||||
for _ in self.current_depth..=(self.max_depth as isize) {
|
||||
let arena_len = self.arena.len();
|
||||
let prog_len = next_nodes.len();
|
||||
next_nodes = next_nodes
|
||||
.into_iter()
|
||||
.progress_with(
|
||||
ProgressBar::new(arena_len as u64).with_style(
|
||||
ProgressBar::new(prog_len as u64).with_style(
|
||||
ProgressStyle::with_template(
|
||||
"Generating children: ({pos}/{len}) {per_sec}",
|
||||
)
|
||||
@@ -128,7 +129,8 @@ impl FutureMoves {
|
||||
// we want to keep only the best move of the agent
|
||||
if color == self.agent_color {
|
||||
if new.len() > 1 {
|
||||
new.sort_by_key(|x| x.compute_self_value(self.agent_color, 1));
|
||||
// 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, 1));
|
||||
new.drain(1..);
|
||||
}
|
||||
}
|
||||
@@ -145,7 +147,7 @@ impl FutureMoves {
|
||||
}
|
||||
|
||||
/// Given an index from `self.arena`, what depth is it at? 1-indexed (ROOT IS AT INDEX 1)
|
||||
fn depth_of(&self, node_idx: usize) -> NonZero<usize> {
|
||||
fn depth_of(&self, node_idx: usize) -> usize {
|
||||
let mut depth = 0;
|
||||
let mut current = Some(node_idx);
|
||||
while let Some(parent_idx) = current {
|
||||
@@ -153,8 +155,7 @@ impl FutureMoves {
|
||||
current = self.arena[parent_idx].parent;
|
||||
}
|
||||
|
||||
// SAFETY! because `node_idx` is of type `usize`, depth will never be 0
|
||||
unsafe { NonZero::new_unchecked(depth) }
|
||||
depth
|
||||
}
|
||||
|
||||
fn compute_values(&mut self) {
|
||||
@@ -163,19 +164,16 @@ impl FutureMoves {
|
||||
let mut visited = vec![false; self.arena.len()];
|
||||
|
||||
for depth in (0..=self.current_depth).rev() {
|
||||
let nodes_at_depth: Vec<usize> = (0..self.arena.len())
|
||||
.filter(|&idx| {
|
||||
if visited[idx] {
|
||||
false
|
||||
} else {
|
||||
visited[idx] = true;
|
||||
true
|
||||
}
|
||||
})
|
||||
.filter(|&idx| self.depth_of(idx).get() == depth as usize)
|
||||
.collect();
|
||||
for idx in 0..self.arena.len() {
|
||||
if visited[idx] {
|
||||
continue;
|
||||
} else {
|
||||
visited[idx] = true;
|
||||
}
|
||||
if self.depth_of(idx) != depth as usize {
|
||||
continue;
|
||||
}
|
||||
|
||||
for idx in nodes_at_depth {
|
||||
let self_value = self.arena[idx]
|
||||
.compute_self_value(self.agent_color, (self.current_depth - depth + 1) as i64);
|
||||
|
||||
@@ -230,7 +228,7 @@ impl FutureMoves {
|
||||
i: 0,
|
||||
j: 0,
|
||||
board: *board,
|
||||
winner: None,
|
||||
winner: Winner::None,
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
value: 0,
|
||||
@@ -253,7 +251,7 @@ impl FutureMoves {
|
||||
|
||||
fn update_root_idx(&mut self, idx: usize) {
|
||||
self.current_root = Some(idx);
|
||||
self.current_depth -= self.depth_of(idx).get() as isize;
|
||||
self.current_depth -= self.depth_of(idx) as isize - 1;
|
||||
self.prune_unrelated();
|
||||
self.extend_layers();
|
||||
self.compute_values();
|
||||
@@ -264,6 +262,9 @@ impl FutureMoves {
|
||||
return;
|
||||
};
|
||||
|
||||
// make sure `root` doesn't reference another node
|
||||
self.arena[root].parent = None;
|
||||
|
||||
let mut retain = vec![false; self.arena.len()];
|
||||
|
||||
// stack is going to be AT MAXIMUM, the size of the array,
|
||||
@@ -314,7 +315,7 @@ pub struct ComplexAgent {
|
||||
|
||||
impl ComplexAgent {
|
||||
pub const fn new(color: Piece) -> Self {
|
||||
const MAX_DEPTH: usize = 10;
|
||||
const MAX_DEPTH: usize = 17;
|
||||
Self {
|
||||
color,
|
||||
future_moves: FutureMoves::new(color, MAX_DEPTH),
|
||||
|
||||
Reference in New Issue
Block a user