allocator optimizations
This commit is contained in:
parent
598c38efd6
commit
3d3eb01143
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
/target
|
||||
/flamegraph.svg
|
||||
/perf.data*
|
||||
|
33
src/board.rs
33
src/board.rs
@ -136,6 +136,9 @@ impl Board {
|
||||
/// Propegate piece captures originating from (i, j)
|
||||
/// DO NOT USE THIS ALONE, this should be called as a part of
|
||||
/// [`Board::place`] or [`Board::place_and_prop_unchecked`]
|
||||
// TODO! this function is responsible for approx 64% of the time spent computing moves in `ComplexAgent`
|
||||
// IDEAS: early-exit from each chain so we don't have to call `diag` (which allocs a lot and uses a lot of cycles)
|
||||
// NOTE! got it down to 24.86% (61.1% decrease) with allocator optimizations
|
||||
fn propegate_from_dry(&self, i: usize, j: usize, starting_color: Piece) -> Vec<(usize, usize)> {
|
||||
// Create all chains from the piece being propegated from in `i` and `j` coordinates
|
||||
let (i_chain, j_chain) = (
|
||||
@ -143,21 +146,16 @@ impl Board {
|
||||
split_from(0, BOARD_SIZE - 1, j),
|
||||
);
|
||||
|
||||
let mut chains: Vec<Vec<(usize, usize)>> = i_chain
|
||||
.into_iter()
|
||||
.map(|range| range.into_iter().map(|i| (i, j)).collect())
|
||||
.collect();
|
||||
let mut chains: Vec<Vec<(usize, usize)>> = Vec::with_capacity(8);
|
||||
|
||||
chains.extend(
|
||||
j_chain
|
||||
.into_iter()
|
||||
.map(|range| range.into_iter().map(|j| (i, j)).collect()),
|
||||
);
|
||||
chains.extend(i_chain.map(|range| range.into_iter().map(|i| (i, j)).collect()));
|
||||
|
||||
chains.extend(j_chain.map(|range| range.into_iter().map(|j| (i, j)).collect()));
|
||||
|
||||
// handle diagonals
|
||||
chains.extend(diag(i, j, 0, 0, BOARD_SIZE - 1, BOARD_SIZE - 1));
|
||||
|
||||
let mut fill: Vec<(usize, usize)> = Vec::new();
|
||||
let mut fill: Vec<(usize, usize)> = Vec::with_capacity(chains.iter().map(Vec::len).sum());
|
||||
|
||||
for chain in chains {
|
||||
for (chain_length, &(new_i, new_j)) in chain.iter().enumerate() {
|
||||
@ -167,15 +165,14 @@ impl Board {
|
||||
};
|
||||
|
||||
if piece == &starting_color {
|
||||
// fill all opposite colors with this color
|
||||
let Some(history) = chain.get(..chain_length) else {
|
||||
break;
|
||||
};
|
||||
|
||||
// fill all opposite colors with this color
|
||||
for &(i_o, j_o) in history {
|
||||
fill.push((i_o, j_o));
|
||||
// get history of this chain
|
||||
if let Some(history) = chain.get(..chain_length) {
|
||||
// fill all opposite colors with this color
|
||||
for &(i_o, j_o) in history {
|
||||
fill.push((i_o, j_o));
|
||||
}
|
||||
}
|
||||
|
||||
// either the other pieces were replaced, or this was an invalid chain,
|
||||
// in both cases, the loop needs to be breaked
|
||||
break;
|
||||
|
@ -58,7 +58,6 @@ struct FutureMoves {
|
||||
max_depth: usize,
|
||||
/// Color w.r.t
|
||||
agent_color: Piece,
|
||||
gc: usize,
|
||||
}
|
||||
|
||||
impl FutureMoves {
|
||||
@ -69,7 +68,6 @@ impl FutureMoves {
|
||||
current_depth: 0,
|
||||
max_depth,
|
||||
agent_color,
|
||||
gc: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,10 +203,7 @@ impl FutureMoves {
|
||||
if let Some(root) = new_root {
|
||||
self.current_root = Some(root);
|
||||
self.current_depth = self.max_depth - self.depth_of(Some(root));
|
||||
self.gc += 1;
|
||||
if self.gc > 3 {
|
||||
self.prune_unrelated();
|
||||
}
|
||||
self.prune_unrelated();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -11,8 +11,8 @@ mod piece;
|
||||
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();
|
||||
}
|
||||
|
45
src/misc.rs
45
src/misc.rs
@ -1,33 +1,30 @@
|
||||
use std::{iter::Rev, ops::RangeInclusive};
|
||||
|
||||
pub fn split_from<T>(min: T, max: T, x: T) -> Vec<Vec<T>>
|
||||
pub fn split_from<T>(min: T, max: T, x: T) -> [Vec<T>; 2]
|
||||
where
|
||||
T: num::Integer + Copy,
|
||||
RangeInclusive<T>: Iterator<Item = T> + DoubleEndedIterator,
|
||||
Rev<RangeInclusive<T>>: Iterator<Item = T>,
|
||||
{
|
||||
let mut output = [const { Vec::new() }; 2];
|
||||
|
||||
// check that x is in range
|
||||
if min > x || x > max {
|
||||
return Vec::new();
|
||||
return output;
|
||||
}
|
||||
|
||||
let mut output: Vec<Vec<T>> = Vec::with_capacity(2);
|
||||
if x > min + T::one() {
|
||||
let x_lower = x - T::one();
|
||||
output.push((min..=x_lower).rev().collect());
|
||||
} else {
|
||||
output.push(Vec::new());
|
||||
output[0] = (min..=x_lower).rev().collect();
|
||||
}
|
||||
|
||||
if x + T::one() < max {
|
||||
output.push(((x + T::one())..=max).collect());
|
||||
} else {
|
||||
output.push(Vec::new());
|
||||
output[1] = ((x + T::one())..=max).collect();
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn diag<T>(i: T, j: T, min_i: T, min_j: T, max_i: T, max_j: T) -> Vec<Vec<(T, T)>>
|
||||
pub fn diag<T>(i: T, j: T, min_i: T, min_j: T, max_i: T, max_j: T) -> [Vec<(T, T)>; 4]
|
||||
where
|
||||
T: num::Integer + Copy,
|
||||
RangeInclusive<T>: Iterator<Item = T> + DoubleEndedIterator,
|
||||
@ -36,25 +33,25 @@ where
|
||||
let i_chains = split_from(min_i, max_i, i);
|
||||
let j_chains = split_from(min_j, max_j, j);
|
||||
|
||||
vec![
|
||||
[
|
||||
i_chains[0]
|
||||
.clone()
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(j_chains[0].clone())
|
||||
.collect(),
|
||||
i_chains[1]
|
||||
.clone()
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(j_chains[1].clone())
|
||||
.collect(),
|
||||
i_chains[1]
|
||||
.clone()
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(j_chains[0].clone())
|
||||
.collect(),
|
||||
i_chains[0]
|
||||
.clone()
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(j_chains[1].clone())
|
||||
.collect(),
|
||||
]
|
||||
@ -66,16 +63,16 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn split_test() {
|
||||
assert_eq!(split_from(0, 6, 2), vec![vec![1, 0], vec![3, 4, 5, 6]]);
|
||||
assert_eq!(split_from(0, 6, 2), [vec![1, 0], vec![3, 4, 5, 6]]);
|
||||
|
||||
assert_eq!(split_from(0, 6, 0), vec![vec![], vec![1, 2, 3, 4, 5, 6]]);
|
||||
assert_eq!(split_from(0, 6, 0), [vec![], vec![1, 2, 3, 4, 5, 6]]);
|
||||
|
||||
assert_eq!(split_from(0, 6, 6), vec![vec![5, 4, 3, 2, 1, 0], vec![]]);
|
||||
assert_eq!(split_from(0, 6, 6), [vec![5, 4, 3, 2, 1, 0], vec![]]);
|
||||
|
||||
// test out-of-bounds and also generics
|
||||
assert_eq!(
|
||||
split_from::<i16>(-1i16, 4i16, 10i16),
|
||||
Vec::<Vec<i16>>::new()
|
||||
[const { Vec::new() }; 2]
|
||||
);
|
||||
}
|
||||
|
||||
@ -83,7 +80,7 @@ mod test {
|
||||
fn diag_test() {
|
||||
assert_eq!(
|
||||
diag(2, 3, 0, 0, 7, 7),
|
||||
vec![
|
||||
[
|
||||
vec![(1, 2), (0, 1)],
|
||||
vec![(3, 4), (4, 5), (5, 6), (6, 7)],
|
||||
vec![(3, 2), (4, 1), (5, 0)],
|
||||
|
Loading…
x
Reference in New Issue
Block a user