shrimplify: remove "capabilities" interface
this is also going to be reassessed later
This commit is contained in:
parent
7637f892ae
commit
002c0ba37c
|
@ -12,7 +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, find_locations};
|
use crate::find::find_locations;
|
||||||
|
|
||||||
use self::search::ModifiedAStar;
|
use self::search::ModifiedAStar;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ 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() {
|
||||||
for loc in find_locations(&node.mat, ty, All) {
|
for loc in find_locations(&node.mat, ty) {
|
||||||
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);
|
||||||
|
|
|
@ -94,7 +94,7 @@ fn list_moves() -> anyhow::Result<()> {
|
||||||
let front = input.queue.previews.get(0).copied();
|
let front = input.queue.previews.get(0).copied();
|
||||||
let hold = input.queue.hold;
|
let hold = input.queue.hold;
|
||||||
for ty in [front, hold].into_iter().flatten() {
|
for ty in [front, hold].into_iter().flatten() {
|
||||||
for loc in fish::find_locations(&mat, ty, fish::find::cap::All) {
|
for loc in fish::find_locations(&mat, ty) {
|
||||||
output.moves.push(fish::io::OutputMove {
|
output.moves.push(fish::io::OutputMove {
|
||||||
location: mino::Piece { ty, loc }.into(),
|
location: mino::Piece { ty, loc }.into(),
|
||||||
spin: fish::io::Spin::None,
|
spin: fish::io::Spin::None,
|
||||||
|
|
105
fish/src/find.rs
105
fish/src/find.rs
|
@ -9,53 +9,25 @@ use mino::{input, Loc, Mat, Movement, Piece};
|
||||||
// Generic arguments legend
|
// Generic arguments legend
|
||||||
// ========================
|
// ========================
|
||||||
// - T: piece type (e.g. srs::PieceType)
|
// - T: piece type (e.g. srs::PieceType)
|
||||||
// - C: capabilities (e.g. cap::All)
|
|
||||||
// - 'm: matrix lifetime
|
// - 'm: matrix lifetime
|
||||||
// - 'c: T::cells() lifetime
|
// - 'c: T::cells() lifetime
|
||||||
// - 'k: T::kicks() lifetime
|
// - 'k: T::kicks() lifetime
|
||||||
// - 'a: general purpose lifetime
|
// - 'a: general purpose lifetime
|
||||||
|
|
||||||
/// Helper function to just yield all of the locations reachable on `matrix` for the shape
|
static ALL_INPUTS: &[Movement] = &[
|
||||||
/// `shape`, given input capabilities `capabilities`.
|
Movement::LEFT,
|
||||||
pub fn find_locations<'a, 'c, 'k, T, C>(
|
Movement::RIGHT,
|
||||||
matrix: &'a Mat,
|
Movement::CW,
|
||||||
piece_ty: T,
|
Movement::CCW,
|
||||||
capabilities: C,
|
Movement::FLIP,
|
||||||
) -> FindLocations<T, C>
|
];
|
||||||
|
|
||||||
|
/// Yields all of the locations reachable by the given peice on the given matrix.
|
||||||
|
pub fn find_locations<'a, 'c, 'k, T>(matrix: &'a Mat, piece_ty: T) -> FindLocations<T>
|
||||||
where
|
where
|
||||||
T: Shape<'c> + Kicks<'k> + Spawn + Clone + 'a,
|
T: Shape<'c> + Kicks<'k> + Spawn + Clone + 'a,
|
||||||
C: Capabilities + 'a,
|
|
||||||
{
|
{
|
||||||
FindLocations::new(matrix, piece_ty, capabilities)
|
FindLocations::new(matrix, piece_ty)
|
||||||
}
|
|
||||||
|
|
||||||
/// Interface to describe what inputs the location finder is capable of performing in
|
|
||||||
/// order to reach target locations. This can be used, for instance, to prevent soft-drops
|
|
||||||
/// or 180 spins.
|
|
||||||
pub trait Capabilities {
|
|
||||||
/// Iterator type returned by `all_inputs`.
|
|
||||||
type InputsIter: IntoIterator<Item = Movement>;
|
|
||||||
|
|
||||||
/// Returns a list of all of the inputs that can be performed.
|
|
||||||
fn all_inputs(&self) -> Self::InputsIter;
|
|
||||||
|
|
||||||
// TODO: flags for soft drop or kicks
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Different implementations of the `Capabilities` trait.
|
|
||||||
pub mod cap {
|
|
||||||
use super::Capabilities;
|
|
||||||
use mino::Movement;
|
|
||||||
|
|
||||||
/// Find all possible reachable locations; no restrictions.
|
|
||||||
pub struct All;
|
|
||||||
|
|
||||||
impl Capabilities for All {
|
|
||||||
type InputsIter = [Movement; 4];
|
|
||||||
fn all_inputs(&self) -> Self::InputsIter {
|
|
||||||
[Movement::LEFT, Movement::RIGHT, Movement::CW, Movement::CCW]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Algorithm used to search for reachable locations on a given board state. The current
|
/// Algorithm used to search for reachable locations on a given board state. The current
|
||||||
|
@ -64,45 +36,37 @@ pub mod cap {
|
||||||
///
|
///
|
||||||
/// [`FindLocations`] is an [`Iterator`], so you can use that interface to obtain the next
|
/// [`FindLocations`] is an [`Iterator`], so you can use that interface to obtain the next
|
||||||
/// available location or loop over all of them.
|
/// available location or loop over all of them.
|
||||||
pub struct FindLocations<'m, T, C> {
|
pub struct FindLocations<'m, T> {
|
||||||
matrix: &'m Mat,
|
matrix: &'m Mat,
|
||||||
piece_ty: T,
|
piece_ty: T,
|
||||||
capabilities: C,
|
|
||||||
// TODO: allow these two collections to be extracted and reused
|
// TODO: allow these two collections to be extracted and reused
|
||||||
stack: Vec<Loc>,
|
stack: Vec<Loc>,
|
||||||
visited: HashSet<Loc, core::hash::BuildHasherDefault<ahash::AHasher>>,
|
visited: HashSet<Loc, core::hash::BuildHasherDefault<ahash::AHasher>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m, 'c, 'k, T, C> FindLocations<'m, T, C>
|
impl<'m, 'c, 'k, T> FindLocations<'m, T>
|
||||||
where
|
where
|
||||||
T: Shape<'c> + Kicks<'k> + Spawn + Clone,
|
T: Shape<'c> + Kicks<'k> + Spawn + Clone,
|
||||||
C: Capabilities,
|
|
||||||
{
|
{
|
||||||
/// 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 {
|
fn new(matrix: &'m Mat, piece_ty: T) -> Self {
|
||||||
let mut this = Self {
|
// TODO: use with_capacity
|
||||||
|
let mut stack = Vec::default();
|
||||||
|
let mut visited = HashSet::default();
|
||||||
|
|
||||||
|
let init_pc = Piece::spawn(piece_ty.clone());
|
||||||
|
let game_over = init_pc.cells().intersects(matrix);
|
||||||
|
if !game_over {
|
||||||
|
stack.push(init_pc.loc);
|
||||||
|
visited.insert(init_pc.loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
matrix,
|
matrix,
|
||||||
piece_ty,
|
piece_ty,
|
||||||
capabilities,
|
stack,
|
||||||
// TODO: set initial capacity
|
visited,
|
||||||
stack: Vec::default(),
|
|
||||||
visited: HashSet::default(),
|
|
||||||
};
|
|
||||||
this.init();
|
|
||||||
this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&mut self) {
|
|
||||||
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) {
|
|
||||||
// game over
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.push(init_pc.loc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, loc: Loc) {
|
fn push(&mut self, loc: Loc) {
|
||||||
|
@ -119,17 +83,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m, 'c, 'k, T, C> Iterator for FindLocations<'m, T, C>
|
impl<'m, 'c, 'k, T> Iterator for FindLocations<'m, T>
|
||||||
where
|
where
|
||||||
T: Shape<'c> + Kicks<'k> + Spawn + Clone,
|
T: Shape<'c> + Kicks<'k> + Spawn + Clone,
|
||||||
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() {
|
||||||
|
// TODO: configure capabilities, e.g. is 180 enabled, are kicks enabled
|
||||||
|
|
||||||
// push all locations reachable by performing an input
|
// push all locations reachable by performing an input
|
||||||
for inp in self.capabilities.all_inputs() {
|
for &inp in ALL_INPUTS.iter() {
|
||||||
let mut pc = pc0.clone();
|
let mut pc = pc0.clone();
|
||||||
if inp.perform(&mut pc, self.matrix) {
|
if inp.perform(&mut pc, self.matrix) {
|
||||||
self.push(pc.loc);
|
self.push(pc.loc);
|
||||||
|
@ -150,8 +115,8 @@ 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> core::iter::FusedIterator
|
||||||
core::iter::FusedIterator for FindLocations<'m, T, C>
|
for FindLocations<'m, T>
|
||||||
{
|
{
|
||||||
// CORRECTNESS: once `self.stack` is empty, `next()` will always return `None`.
|
// CORRECTNESS: once `self.stack` is empty, `next()` will always return `None`.
|
||||||
}
|
}
|
||||||
|
@ -185,7 +150,7 @@ mod test {
|
||||||
Loc: From<E::Item>,
|
Loc: From<E::Item>,
|
||||||
{
|
{
|
||||||
let expected = expected.into_iter().map(Loc::from).collect::<Vec<_>>();
|
let expected = expected.into_iter().map(Loc::from).collect::<Vec<_>>();
|
||||||
let found = find_locations(matrix, ty, cap::All).collect::<Vec<_>>();
|
let found = find_locations(matrix, ty).collect::<Vec<_>>();
|
||||||
if let Some(exp) = find_missing(ty, &expected, &found) {
|
if let Some(exp) = find_missing(ty, &expected, &found) {
|
||||||
panic!("{exp:?} expected but not found");
|
panic!("{exp:?} expected but not found");
|
||||||
} else if let Some(fnd) = find_missing(ty, &found, &expected) {
|
} else if let Some(fnd) = find_missing(ty, &found, &expected) {
|
||||||
|
|
Loading…
Reference in New Issue