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:
parent
71efd222eb
commit
7637f892ae
|
@ -12,8 +12,7 @@ use alloc::vec::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
||||||
use crate::eval::evaluate;
|
use crate::eval::evaluate;
|
||||||
use crate::find::cap::All;
|
use crate::find::{cap::All, find_locations};
|
||||||
use crate::find::{FindLocations, FindLocationsBuffers};
|
|
||||||
|
|
||||||
use self::search::ModifiedAStar;
|
use self::search::ModifiedAStar;
|
||||||
|
|
||||||
|
@ -57,7 +56,6 @@ impl Ai {
|
||||||
struct Graph {
|
struct Graph {
|
||||||
arena: *const Bump,
|
arena: *const Bump,
|
||||||
root: Node,
|
root: Node,
|
||||||
find_buf: Option<FindLocationsBuffers>,
|
|
||||||
children_buf: Vec<Node>,
|
children_buf: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +65,6 @@ impl Graph {
|
||||||
Self {
|
Self {
|
||||||
arena,
|
arena,
|
||||||
root,
|
root,
|
||||||
find_buf: None,
|
|
||||||
children_buf: Vec::new(),
|
children_buf: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,14 +81,11 @@ impl search::Graph for Graph {
|
||||||
self.children_buf.clear();
|
self.children_buf.clear();
|
||||||
|
|
||||||
for ty in node.queue.current() {
|
for ty in node.queue.current() {
|
||||||
let find_buf = self.find_buf.take().unwrap_or_default();
|
for loc in find_locations(&node.mat, ty, All) {
|
||||||
let mut locs = FindLocations::with_buffers(&node.mat, ty, All, find_buf);
|
|
||||||
for loc in &mut locs {
|
|
||||||
let piece = Piece { ty, loc };
|
let piece = Piece { ty, loc };
|
||||||
let node = node.succ(self.arena, piece);
|
let node = node.succ(self.arena, piece);
|
||||||
self.children_buf.push(node);
|
self.children_buf.push(node);
|
||||||
}
|
}
|
||||||
self.find_buf = Some(locs.into_buffers());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("expanded to create {} children", self.children_buf.len());
|
tracing::trace!("expanded to create {} children", self.children_buf.len());
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Find locations.
|
//! Find locations.
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::hash::BuildHasherDefault;
|
|
||||||
use hashbrown::hash_set::HashSet;
|
use hashbrown::hash_set::HashSet;
|
||||||
use mino::input::Kicks;
|
use mino::input::Kicks;
|
||||||
use mino::piece::{Shape, Spawn};
|
use mino::piece::{Shape, Spawn};
|
||||||
|
@ -22,7 +21,7 @@ pub fn find_locations<'a, 'c, 'k, T, C>(
|
||||||
matrix: &'a Mat,
|
matrix: &'a Mat,
|
||||||
piece_ty: T,
|
piece_ty: T,
|
||||||
capabilities: C,
|
capabilities: C,
|
||||||
) -> impl Iterator<Item = Loc> + 'a
|
) -> FindLocations<T, C>
|
||||||
where
|
where
|
||||||
T: Shape<'c> + Kicks<'k> + Spawn + Clone + 'a,
|
T: Shape<'c> + Kicks<'k> + Spawn + Clone + 'a,
|
||||||
C: Capabilities + 'a,
|
C: Capabilities + 'a,
|
||||||
|
@ -69,31 +68,9 @@ pub struct FindLocations<'m, T, C> {
|
||||||
matrix: &'m Mat,
|
matrix: &'m Mat,
|
||||||
piece_ty: T,
|
piece_ty: T,
|
||||||
capabilities: C,
|
capabilities: C,
|
||||||
buffers: FindLocationsBuffers,
|
// TODO: allow these two collections to be extracted and reused
|
||||||
}
|
stack: Vec<Loc>,
|
||||||
|
visited: HashSet<Loc, core::hash::BuildHasherDefault<ahash::AHasher>>,
|
||||||
/// 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m, 'c, 'k, T, C> FindLocations<'m, T, C>
|
impl<'m, 'c, 'k, T, C> FindLocations<'m, T, C>
|
||||||
|
@ -103,40 +80,22 @@ where
|
||||||
{
|
{
|
||||||
/// Constructs a new instance of the location finding algorithm.
|
/// Constructs a new instance of the location finding algorithm.
|
||||||
pub fn new(matrix: &'m Mat, piece_ty: T, capabilities: C) -> Self {
|
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 {
|
let mut this = Self {
|
||||||
matrix,
|
matrix,
|
||||||
piece_ty,
|
piece_ty,
|
||||||
capabilities,
|
capabilities,
|
||||||
buffers,
|
// TODO: set initial capacity
|
||||||
|
stack: Vec::default(),
|
||||||
|
visited: HashSet::default(),
|
||||||
};
|
};
|
||||||
this.init();
|
this.init();
|
||||||
this
|
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) {
|
fn init(&mut self) {
|
||||||
self.buffers.stack.clear();
|
self.stack.clear();
|
||||||
self.buffers.visited.clear();
|
self.visited.clear();
|
||||||
// self.buffers.max_height = 0;
|
// self.stats.max_height = 0;
|
||||||
|
|
||||||
let init_pc = Piece::spawn(self.piece_ty.clone());
|
let init_pc = Piece::spawn(self.piece_ty.clone());
|
||||||
if init_pc.cells().intersects(self.matrix) {
|
if init_pc.cells().intersects(self.matrix) {
|
||||||
|
@ -148,16 +107,15 @@ where
|
||||||
|
|
||||||
fn push(&mut self, loc: Loc) {
|
fn push(&mut self, loc: Loc) {
|
||||||
// 'visited' set prevents cycles
|
// 'visited' set prevents cycles
|
||||||
if self.buffers.visited.insert(loc) {
|
if self.visited.insert(loc) {
|
||||||
self.buffers.stack.push(loc);
|
self.stack.push(loc);
|
||||||
// self.buffers.max_height =
|
// self.stats.max_height = max(self.stats.max_height, self.stack.len());
|
||||||
// core::cmp::max(self.buffers.max_height, self.buffers.stack.len());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self) -> Option<Piece<T>> {
|
fn pop(&mut self) -> Option<Piece<T>> {
|
||||||
let ty = self.piece_ty.clone();
|
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,
|
C: Capabilities,
|
||||||
{
|
{
|
||||||
type Item = Loc;
|
type Item = Loc;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(pc0) = self.pop() {
|
while let Some(pc0) = self.pop() {
|
||||||
// push all locations reachable by performing an input
|
// push all locations reachable by performing an input
|
||||||
|
@ -176,11 +135,12 @@ where
|
||||||
self.push(pc.loc);
|
self.push(pc.loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pc = pc0;
|
let mut pc = pc0;
|
||||||
if input::drop(&mut pc, self.matrix) {
|
if input::drop(&mut pc, self.matrix) {
|
||||||
// piece was floating, so drop it and analyze that later
|
// piece was floating, so drop it and analyze that later
|
||||||
|
// TODO: configure capability to do soft drop
|
||||||
self.push(pc.loc);
|
self.push(pc.loc);
|
||||||
// TODO: don't push if soft drops are denied by self.capabilities
|
|
||||||
} else {
|
} else {
|
||||||
// piece was not floating so it's a valid final piece location.
|
// piece was not floating so it's a valid final piece location.
|
||||||
return Some(pc.loc);
|
return Some(pc.loc);
|
||||||
|
@ -193,7 +153,7 @@ where
|
||||||
impl<'m, 'c, 'k, T: Shape<'c> + Kicks<'k> + Spawn + Clone, C: Capabilities>
|
impl<'m, 'c, 'k, T: Shape<'c> + Kicks<'k> + Spawn + Clone, C: Capabilities>
|
||||||
core::iter::FusedIterator for FindLocations<'m, T, C>
|
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)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue