more iterator stuff
This commit is contained in:
parent
3e2ab2fd32
commit
657bb967a0
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
misc::{diag, split_from},
|
misc::{diag_raw, split_from},
|
||||||
piece::Piece,
|
piece::Piece,
|
||||||
};
|
};
|
||||||
use std::{cmp::Ordering, fmt};
|
use std::{cmp::Ordering, fmt};
|
||||||
@ -148,17 +148,19 @@ impl Board {
|
|||||||
|
|
||||||
chains.extend(
|
chains.extend(
|
||||||
i_chain
|
i_chain
|
||||||
|
.clone()
|
||||||
.map(|range| range.map(move |i| (i, j)))
|
.map(|range| range.map(move |i| (i, j)))
|
||||||
.map(Iterator::collect),
|
.map(Iterator::collect),
|
||||||
);
|
);
|
||||||
chains.extend(
|
chains.extend(
|
||||||
j_chain
|
j_chain
|
||||||
|
.clone()
|
||||||
.map(|range| range.map(move |j| (i, j)))
|
.map(|range| range.map(move |j| (i, j)))
|
||||||
.map(Iterator::collect),
|
.map(Iterator::collect),
|
||||||
);
|
);
|
||||||
|
|
||||||
// handle diagonals
|
// handle diagonals
|
||||||
chains.extend(diag(i, j, 0, 0, BOARD_SIZE - 1, BOARD_SIZE - 1).map(Iterator::collect));
|
chains.extend(diag_raw(i_chain, j_chain).map(Iterator::collect));
|
||||||
|
|
||||||
// Longest chain is (BOARD_SIZE - 2) as there needs to be the two pieces containing it
|
// Longest chain is (BOARD_SIZE - 2) as there needs to be the two pieces containing it
|
||||||
let mut fill: Vec<(usize, usize)> = Vec::with_capacity((BOARD_SIZE - 2) * chains.len());
|
let mut fill: Vec<(usize, usize)> = Vec::with_capacity((BOARD_SIZE - 2) * chains.len());
|
||||||
@ -214,6 +216,8 @@ impl Board {
|
|||||||
match white_score.cmp(&black_score) {
|
match white_score.cmp(&black_score) {
|
||||||
Ordering::Greater => Some(Piece::White), // White win
|
Ordering::Greater => Some(Piece::White), // White win
|
||||||
Ordering::Less => Some(Piece::Black), // Black win
|
Ordering::Less => Some(Piece::Black), // Black win
|
||||||
|
|
||||||
|
// TODO! this will end up being parsed the same as a "no winner", it should be a seperate type
|
||||||
Ordering::Equal => None, // Tie
|
Ordering::Equal => None, // Tie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,7 @@ struct FutureMoves {
|
|||||||
current_root: Option<usize>,
|
current_root: Option<usize>,
|
||||||
current_depth: usize,
|
current_depth: usize,
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
|
|
||||||
/// Color w.r.t
|
/// Color w.r.t
|
||||||
agent_color: Piece,
|
agent_color: Piece,
|
||||||
}
|
}
|
||||||
@ -80,22 +81,30 @@ impl FutureMoves {
|
|||||||
self.extend_layers(root_nodes, color, self.max_depth);
|
self.extend_layers(root_nodes, color, self.max_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend_layers(&mut self, nodes: Vec<usize>, color: Piece, remaining_depth: usize) {
|
fn extend_layers(
|
||||||
|
&mut self,
|
||||||
|
nodes: impl Iterator<Item = usize>,
|
||||||
|
color: Piece,
|
||||||
|
remaining_depth: usize,
|
||||||
|
) {
|
||||||
if remaining_depth == 0 {
|
if remaining_depth == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_color = !color;
|
let next_color = !color;
|
||||||
let mut next_nodes = Vec::new();
|
|
||||||
|
|
||||||
for node_idx in nodes {
|
let next_nodes: Vec<usize> = nodes
|
||||||
let board = &self.arena[node_idx].board.clone();
|
.flat_map(|node_idx| {
|
||||||
let children = self.generate_children(Some(node_idx), board, next_color);
|
self.generate_children(
|
||||||
next_nodes.extend(children);
|
Some(node_idx),
|
||||||
}
|
&self.arena[node_idx].board.clone(),
|
||||||
|
next_color,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
self.current_depth += 1;
|
self.current_depth += 1;
|
||||||
self.extend_layers(next_nodes, next_color, remaining_depth - 1);
|
self.extend_layers(next_nodes.into_iter(), next_color, remaining_depth - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_children(
|
fn generate_children(
|
||||||
@ -103,31 +112,28 @@ impl FutureMoves {
|
|||||||
parent: Option<usize>,
|
parent: Option<usize>,
|
||||||
board: &Board,
|
board: &Board,
|
||||||
color: Piece,
|
color: Piece,
|
||||||
) -> Vec<usize> {
|
) -> impl Iterator<Item = usize> {
|
||||||
let parent_idx = parent;
|
|
||||||
let start_idx = self.arena.len();
|
let start_idx = self.arena.len();
|
||||||
self.arena.extend(
|
self.arena.extend(
|
||||||
board
|
board
|
||||||
.possible_moves(color)
|
.possible_moves(color)
|
||||||
.flat_map(|(i, j)| board.what_if(i, j, color).map(|x| (i, j, x)))
|
.flat_map(|(i, j)| board.what_if(i, j, color).map(|x| (i, j, x)))
|
||||||
.map(|(i, j, (new_board, captured))| {
|
.map(|(i, j, (new_board, captured))| Move {
|
||||||
let winner = new_board.game_winner(color);
|
|
||||||
Move {
|
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
captured,
|
captured,
|
||||||
color,
|
color,
|
||||||
board: new_board,
|
board: new_board,
|
||||||
winner,
|
winner: new_board.game_winner(color),
|
||||||
parent,
|
parent,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
value: 0,
|
value: 0,
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
let new_indices: Vec<usize> = (start_idx..self.arena.len()).collect();
|
|
||||||
|
|
||||||
if let Some(parent_idx) = parent_idx {
|
let new_indices = start_idx..self.arena.len();
|
||||||
|
|
||||||
|
if let Some(parent_idx) = parent {
|
||||||
self.arena[parent_idx].children.extend(new_indices.clone());
|
self.arena[parent_idx].children.extend(new_indices.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,10 +150,8 @@ impl FutureMoves {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for idx in nodes_at_depth {
|
for idx in nodes_at_depth {
|
||||||
let self_value = {
|
let self_value = self.arena[idx]
|
||||||
let node = &self.arena[idx];
|
.compute_self_value(self.agent_color, self.current_depth - depth + 1);
|
||||||
node.compute_self_value(self.agent_color, self.current_depth - depth + 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
let children_value = self.arena[idx]
|
let children_value = self.arena[idx]
|
||||||
.children
|
.children
|
||||||
@ -191,18 +195,18 @@ impl FutureMoves {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_root(&mut self, i: usize, j: usize) -> bool {
|
pub fn update_root(&mut self, i: usize, j: usize) -> bool {
|
||||||
let new_root = self.arena.iter().enumerate().find_map(|(idx, node)| {
|
self.arena
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(idx, node)| {
|
||||||
(node.parent == self.current_root && node.i == i && node.j == j).then_some(idx)
|
(node.parent == self.current_root && node.i == i && node.j == j).then_some(idx)
|
||||||
});
|
})
|
||||||
|
.inspect(|&root| {
|
||||||
if let Some(root) = new_root {
|
|
||||||
self.current_root = Some(root);
|
self.current_root = Some(root);
|
||||||
self.current_depth = self.max_depth - self.depth_of(Some(root));
|
self.current_depth = self.max_depth - self.depth_of(Some(root));
|
||||||
self.prune_unrelated();
|
self.prune_unrelated();
|
||||||
true
|
})
|
||||||
} else {
|
.is_some()
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prune_unrelated(&mut self) {
|
fn prune_unrelated(&mut self) {
|
||||||
@ -215,19 +219,26 @@ impl FutureMoves {
|
|||||||
// traverse children of the current root
|
// traverse children of the current root
|
||||||
while let Some(idx) = stack.pop() {
|
while let Some(idx) = stack.pop() {
|
||||||
retain[idx] = true;
|
retain[idx] = true;
|
||||||
stack.extend(self.arena[idx].children.iter().copied());
|
stack.extend(self.arena[idx].children.iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_arena = Vec::with_capacity(self.arena.len());
|
let mut new_arena = Vec::with_capacity(self.arena.len());
|
||||||
let mut index_map = vec![None; self.arena.len()];
|
let mut index_map = vec![None; self.arena.len()];
|
||||||
|
|
||||||
|
// PERF: reverse iterator to avoid unneeded `memcpy`s when deconstructing the Arena
|
||||||
for (old_idx, keep) in retain.iter().enumerate().rev() {
|
for (old_idx, keep) in retain.iter().enumerate().rev() {
|
||||||
let mut node = self.arena.remove(old_idx);
|
let mut node = self.arena.remove(old_idx);
|
||||||
if *keep {
|
if *keep {
|
||||||
index_map[old_idx] = Some(new_arena.len());
|
index_map[old_idx] = Some(new_arena.len());
|
||||||
|
|
||||||
node.parent = node.parent.and_then(|p| index_map[p]);
|
node.parent = node.parent.and_then(|p| index_map[p]);
|
||||||
node.children = node.children.iter().filter_map(|&c| index_map[c]).collect();
|
|
||||||
|
node.children = node
|
||||||
|
.children
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|c| index_map[c])
|
||||||
|
.collect();
|
||||||
|
|
||||||
new_arena.push(node);
|
new_arena.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,7 +255,7 @@ pub struct ComplexAgent {
|
|||||||
|
|
||||||
impl ComplexAgent {
|
impl ComplexAgent {
|
||||||
pub fn new(color: Piece) -> Self {
|
pub fn new(color: Piece) -> Self {
|
||||||
const MAX_DEPTH: usize = 7;
|
const MAX_DEPTH: usize = 6;
|
||||||
Self {
|
Self {
|
||||||
color,
|
color,
|
||||||
future_moves: FutureMoves::new(color, MAX_DEPTH),
|
future_moves: FutureMoves::new(color, MAX_DEPTH),
|
||||||
@ -259,12 +270,9 @@ impl Agent for ComplexAgent {
|
|||||||
|
|
||||||
println!("# of moves stored: {}", self.future_moves.arena.len());
|
println!("# of moves stored: {}", self.future_moves.arena.len());
|
||||||
|
|
||||||
if let Some((i, j)) = self.future_moves.best_move() {
|
self.future_moves.best_move().inspect(|&(i, j)| {
|
||||||
self.future_moves.update_root(i, j);
|
self.future_moves.update_root(i, j);
|
||||||
Some((i, j))
|
})
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
|
|||||||
@ -11,8 +11,8 @@ mod piece;
|
|||||||
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();
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/misc.rs
16
src/misc.rs
@ -25,7 +25,7 @@ where
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diag<T>(
|
pub fn diag_test_helper<T>(
|
||||||
i: T,
|
i: T,
|
||||||
j: T,
|
j: T,
|
||||||
min_i: T,
|
min_i: T,
|
||||||
@ -40,7 +40,19 @@ where
|
|||||||
{
|
{
|
||||||
let i_chains = split_from(min_i, max_i, i);
|
let i_chains = split_from(min_i, max_i, i);
|
||||||
let j_chains = split_from(min_j, max_j, j);
|
let j_chains = split_from(min_j, max_j, j);
|
||||||
|
diag_raw(i_chains, j_chains)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn diag_raw<T>(
|
||||||
|
i_chains: [impl Iterator<Item = T> + Clone; 2],
|
||||||
|
|
||||||
|
j_chains: [impl Iterator<Item = T> + Clone; 2],
|
||||||
|
) -> [impl Iterator<Item = (T, T)> + Clone; 4]
|
||||||
|
where
|
||||||
|
T: num::Integer + Copy,
|
||||||
|
RangeInclusive<T>: Iterator<Item = T> + DoubleEndedIterator,
|
||||||
|
Rev<RangeInclusive<T>>: Iterator<Item = T>,
|
||||||
|
{
|
||||||
[(0, 0), (1, 1), (1, 0), (0, 1)].map(move |(a, b)| i_chains[a].clone().zip(j_chains[b].clone()))
|
[(0, 0), (1, 1), (1, 0), (0, 1)].map(move |(a, b)| i_chains[a].clone().zip(j_chains[b].clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +87,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn diag_test() {
|
fn diag_test() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
diag(2, 3, 0, 0, 7, 7).map(Iterator::collect::<Vec<(usize, usize)>>),
|
diag_test_helper(2, 3, 0, 0, 7, 7).map(Iterator::collect::<Vec<(usize, usize)>>),
|
||||||
[
|
[
|
||||||
vec![(1, 2), (0, 1)],
|
vec![(1, 2), (0, 1)],
|
||||||
vec![(3, 4), (4, 5), (5, 6), (6, 7)],
|
vec![(3, 4), (4, 5), (5, 6), (6, 7)],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user