shrimplify: remove FindLocationsBuffers

we will add some sort of similar functionality back later, after we have performance data
to justify it
This commit is contained in:
tali 2023-04-09 18:00:30 -04:00
parent 71efd222eb
commit 7637f892ae
2 changed files with 20 additions and 66 deletions

View File

@ -12,8 +12,7 @@ use alloc::vec::Vec;
use bumpalo::Bump;
use crate::eval::evaluate;
use crate::find::cap::All;
use crate::find::{FindLocations, FindLocationsBuffers};
use crate::find::{cap::All, find_locations};
use self::search::ModifiedAStar;
@ -57,7 +56,6 @@ impl Ai {
struct Graph {
arena: *const Bump,
root: Node,
find_buf: Option<FindLocationsBuffers>,
children_buf: Vec<Node>,
}
@ -67,7 +65,6 @@ impl Graph {
Self {
arena,
root,
find_buf: None,
children_buf: Vec::new(),
}
}
@ -84,14 +81,11 @@ impl search::Graph for Graph {
self.children_buf.clear();
for ty in node.queue.current() {
let find_buf = self.find_buf.take().unwrap_or_default();
let mut locs = FindLocations::with_buffers(&node.mat, ty, All, find_buf);
for loc in &mut locs {
for loc in find_locations(&node.mat, ty, All) {
let piece = Piece { ty, loc };
let node = node.succ(self.arena, piece);
self.children_buf.push(node);
}
self.find_buf = Some(locs.into_buffers());
}
tracing::trace!("expanded to create {} children", self.children_buf.len());

View File

@ -1,7 +1,6 @@
//! Find locations.
use alloc::vec::Vec;
use core::hash::BuildHasherDefault;
use hashbrown::hash_set::HashSet;
use mino::input::Kicks;
use mino::piece::{Shape, Spawn};
@ -22,7 +21,7 @@ pub fn find_locations<'a, 'c, 'k, T, C>(
matrix: &'a Mat,
piece_ty: T,
capabilities: C,
) -> impl Iterator<Item = Loc> + 'a
) -> FindLocations<T, C>
where
T: Shape<'c> + Kicks<'k> + Spawn + Clone + 'a,
C: Capabilities + 'a,
@ -69,31 +68,9 @@ pub struct FindLocations<'m, T, C> {
matrix: &'m Mat,
piece_ty: T,
capabilities: C,
buffers: FindLocationsBuffers,
}
/// Contains the underlying buffers used by `FindLocations`. This structure may be used to
/// preallocate space or reuse buffers for multiple runs of the search algorithm.
///
/// See [`FindLocations::with_buffers`] and [`FindLocations::into_buffers`].
#[derive(Clone, Debug)]
pub struct FindLocationsBuffers {
pub stack: Vec<Loc>,
pub visited: HashSet<Loc, BuildHasher>,
// TODO: useful for profiling?
// pub max_height: usize,
}
type BuildHasher = BuildHasherDefault<ahash::AHasher>;
impl Default for FindLocationsBuffers {
fn default() -> Self {
Self {
stack: Vec::with_capacity(64),
visited: HashSet::with_capacity(400),
// max_height: 0,
}
}
// TODO: allow these two collections to be extracted and reused
stack: Vec<Loc>,
visited: HashSet<Loc, core::hash::BuildHasherDefault<ahash::AHasher>>,
}
impl<'m, 'c, 'k, T, C> FindLocations<'m, T, C>
@ -103,40 +80,22 @@ where
{
/// Constructs a new instance of the location finding algorithm.
pub fn new(matrix: &'m Mat, piece_ty: T, capabilities: C) -> Self {
let bufs = FindLocationsBuffers::default();
Self::with_buffers(matrix, piece_ty, capabilities, bufs)
}
/// Constructs a new instance of the location finding algorithm. Uses `buffers` for
/// storage needed by the algorithm. The buffers will be cleared on initialization so
/// it does not matter if they previously contained data.
pub fn with_buffers(
matrix: &'m Mat,
piece_ty: T,
capabilities: C,
buffers: FindLocationsBuffers,
) -> Self {
let mut this = Self {
matrix,
piece_ty,
capabilities,
buffers,
// TODO: set initial capacity
stack: Vec::default(),
visited: HashSet::default(),
};
this.init();
this
}
/// Aborts the search algorithm and relinquishes ownership of the underlying
/// buffers. This is useful for reusing the buffers by passing them to
/// [`Self::with_buffers`] the next time the algorithm is run.
pub fn into_buffers(self) -> FindLocationsBuffers {
self.buffers
}
fn init(&mut self) {
self.buffers.stack.clear();
self.buffers.visited.clear();
// self.buffers.max_height = 0;
self.stack.clear();
self.visited.clear();
// self.stats.max_height = 0;
let init_pc = Piece::spawn(self.piece_ty.clone());
if init_pc.cells().intersects(self.matrix) {
@ -148,16 +107,15 @@ where
fn push(&mut self, loc: Loc) {
// 'visited' set prevents cycles
if self.buffers.visited.insert(loc) {
self.buffers.stack.push(loc);
// self.buffers.max_height =
// core::cmp::max(self.buffers.max_height, self.buffers.stack.len());
if self.visited.insert(loc) {
self.stack.push(loc);
// self.stats.max_height = max(self.stats.max_height, self.stack.len());
}
}
fn pop(&mut self) -> Option<Piece<T>> {
let ty = self.piece_ty.clone();
self.buffers.stack.pop().map(|loc| Piece { ty, loc })
self.stack.pop().map(|loc| Piece { ty, loc })
}
}
@ -167,6 +125,7 @@ where
C: Capabilities,
{
type Item = Loc;
fn next(&mut self) -> Option<Self::Item> {
while let Some(pc0) = self.pop() {
// push all locations reachable by performing an input
@ -176,11 +135,12 @@ where
self.push(pc.loc);
}
}
let mut pc = pc0;
if input::drop(&mut pc, self.matrix) {
// piece was floating, so drop it and analyze that later
// TODO: configure capability to do soft drop
self.push(pc.loc);
// TODO: don't push if soft drops are denied by self.capabilities
} else {
// piece was not floating so it's a valid final piece location.
return Some(pc.loc);
@ -193,7 +153,7 @@ where
impl<'m, 'c, 'k, T: Shape<'c> + Kicks<'k> + Spawn + Clone, C: Capabilities>
core::iter::FusedIterator for FindLocations<'m, T, C>
{
// When `buffers.stack` is empty, the iterator will constanty return `None`.
// CORRECTNESS: once `self.stack` is empty, `next()` will always return `None`.
}
#[cfg(test)]