From 774b15a8affb46ec6584d0a2775698e3020db10a Mon Sep 17 00:00:00 2001 From: Odilf Date: Fri, 11 Aug 2023 14:25:11 +0200 Subject: [PATCH] added a `PieceSetDescriptor` and removed the const generic of `Piece` --- .../src/cube_n/cube3/heuristics/manhattan.rs | 4 +-- .../cube_n/cube3/mus/index/implementations.rs | 2 +- barbarosa/src/cube_n/invariants.rs | 2 +- barbarosa/src/cube_n/moves/wide.rs | 25 +++++++++----- barbarosa/src/cube_n/pieces/center/corner.rs | 24 +++++++------- barbarosa/src/cube_n/pieces/center/edge.rs | 24 +++++++------- barbarosa/src/cube_n/pieces/center/wing.rs | 24 +++++++------- barbarosa/src/cube_n/pieces/corner.rs | 25 ++++++++------ barbarosa/src/cube_n/pieces/edge.rs | 29 +++++++++------- barbarosa/src/cube_n/pieces/wing.rs | 25 +++++++------- barbarosa/src/generic/mod.rs | 2 +- barbarosa/src/generic/piece/mod.rs | 27 ++++++++------- barbarosa/src/generic/piece/set.rs | 33 +++++++++++++++---- 13 files changed, 145 insertions(+), 101 deletions(-) diff --git a/barbarosa/src/cube_n/cube3/heuristics/manhattan.rs b/barbarosa/src/cube_n/cube3/heuristics/manhattan.rs index 2632d66..193b826 100644 --- a/barbarosa/src/cube_n/cube3/heuristics/manhattan.rs +++ b/barbarosa/src/cube_n/cube3/heuristics/manhattan.rs @@ -3,14 +3,14 @@ use nalgebra::Vector3; use crate::{ cube3::Cube3, cube_n::{Corner, Edge}, - generic::{Piece, PieceSet}, + generic::{piece::PieceSetDescriptor, PieceSet}, }; fn vec_manhattan(a: &Vector3, b: &Vector3) -> f32 { a.iter().zip(b.iter()).map(|(a, b)| (a - b).abs()).sum() } -fn piece_set_manhattan, const N: usize>( +fn piece_set_manhattan, const N: usize>( set: &PieceSet, coords: impl Fn(&P::Position) -> Vector3, ) -> f32 { diff --git a/barbarosa/src/cube_n/cube3/mus/index/implementations.rs b/barbarosa/src/cube_n/cube3/mus/index/implementations.rs index 494aa7e..c12217e 100644 --- a/barbarosa/src/cube_n/cube3/mus/index/implementations.rs +++ b/barbarosa/src/cube_n/cube3/mus/index/implementations.rs @@ -3,7 +3,7 @@ use crate::{ mus::{CornersMUS, HalfEdgesMUS}, Corner, Edge, }, - generic::Piece, + generic::{piece::PieceSetDescriptor, Piece}, }; use super::{ diff --git a/barbarosa/src/cube_n/invariants.rs b/barbarosa/src/cube_n/invariants.rs index 23367e1..5c86cb1 100644 --- a/barbarosa/src/cube_n/invariants.rs +++ b/barbarosa/src/cube_n/invariants.rs @@ -32,7 +32,7 @@ use std::fmt::Debug; use crate::{ cube_n::{cube3::mus::index::PositionIndexable, Cube3, Edge}, - generic::Piece, + generic::piece::PieceSetDescriptor, }; use super::pieces::{corner::CornerSet, edge::EdgeSet}; diff --git a/barbarosa/src/cube_n/moves/wide.rs b/barbarosa/src/cube_n/moves/wide.rs index 927a817..391c8da 100644 --- a/barbarosa/src/cube_n/moves/wide.rs +++ b/barbarosa/src/cube_n/moves/wide.rs @@ -11,7 +11,7 @@ pub use crate::generic::{ parse::{self, Parsable}, }; -use self::generic::{Alg, Cube, Movable, Piece, PieceSet}; +use self::generic::{piece::PieceSetDescriptor, Alg, Cube, Movable, Piece, PieceSet}; use super::{ rotation::{AxisRotation, Rotatable}, @@ -183,13 +183,13 @@ impl Alg { } /// A piece that can be moved by a wide move -pub trait DepthPiece: Piece { +pub trait DepthPiece: Piece { /// Whether the piece is in the wide move if it has the given normal and tangent depth. - fn is_in_wide_move( + fn is_in_wide_move( &self, normal_depth: u32, tangent_depth: u32, - m: &WideAxisMove, + m: &WideAxisMove, ) -> bool; } @@ -199,7 +199,7 @@ pub trait DepthPiece: Piece { /// implements [`Movable`] for [`WideAxisMove`]s. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct DepthPieceSet< - P: DepthPiece, + P: DepthPiece + PieceSetDescriptor, const N: usize, const NORMAL_DEPTH: u32, const TANGENT_DEPTH: u32 = 0, @@ -208,15 +208,22 @@ pub struct DepthPieceSet< pub set: PieceSet, } -impl, const N: usize, const ND: u32, const TD: u32> DepthPieceSet { +impl, const N: usize, const ND: u32, const TD: u32> + DepthPieceSet +{ /// Alias to [`Piece::SOLVED`] pub const SOLVED: Self = Self { set: PieceSet::SOLVED, }; } -impl + Rotatable, const M: u32, const N: usize, const ND: u32, const TD: u32> - Movable> for DepthPieceSet +impl< + P: DepthPiece + Rotatable + PieceSetDescriptor, + const M: u32, + const N: usize, + const ND: u32, + const TD: u32, + > Movable> for DepthPieceSet { fn apply(&mut self, m: &WideAxisMove) { self.set @@ -226,7 +233,7 @@ impl + Rotatable, const M: u32, const N: usize, const ND: u32, } } -impl, const N: usize, const ND: u32, const TD: u32> Deref +impl, const N: usize, const ND: u32, const TD: u32> Deref for DepthPieceSet { type Target = PieceSet; diff --git a/barbarosa/src/cube_n/pieces/center/corner.rs b/barbarosa/src/cube_n/pieces/center/corner.rs index 667ace6..eeb446a 100644 --- a/barbarosa/src/cube_n/pieces/center/corner.rs +++ b/barbarosa/src/cube_n/pieces/center/corner.rs @@ -12,7 +12,7 @@ use crate::{ space::{Axis, Direction}, Vec3, WideAxisMove, }, - generic, + generic::{self, piece::PieceSetDescriptor}, }; /// A center corner piece of the cube. There are 4 of these in each face of a cube. @@ -22,9 +22,19 @@ pub struct CenterCorner { axis: Axis, } -impl generic::Piece<24> for CenterCorner { +impl generic::Piece for CenterCorner { type Position = Self; + fn position(&self) -> Self::Position { + self.clone() + } + + fn is_solved(&self, original_pos: &Self::Position) -> bool { + self.position[self.axis] == original_pos.position[original_pos.axis] + } +} + +impl PieceSetDescriptor<24> for CenterCorner { const SOLVED: [Self; 24] = { use Direction::*; @@ -47,14 +57,6 @@ impl generic::Piece<24> for CenterCorner { }; const REFERENCE_POSITIONS: [Self::Position; 24] = Self::SOLVED; - - fn position(&self) -> Self::Position { - self.clone() - } - - fn is_solved(&self, original_pos: &Self::Position) -> bool { - self.position[self.axis] == original_pos.position[original_pos.axis] - } } impl Rotatable for CenterCorner { @@ -64,7 +66,7 @@ impl Rotatable for CenterCorner { } } -impl DepthPiece<24> for CenterCorner { +impl DepthPiece for CenterCorner { fn is_in_wide_move( &self, normal_depth: u32, diff --git a/barbarosa/src/cube_n/pieces/center/edge.rs b/barbarosa/src/cube_n/pieces/center/edge.rs index 01c41ba..ea2e315 100644 --- a/barbarosa/src/cube_n/pieces/center/edge.rs +++ b/barbarosa/src/cube_n/pieces/center/edge.rs @@ -14,7 +14,7 @@ use crate::{ space::{faces, Axis, Direction, Face}, WideAxisMove, }, - generic, + generic::{self, piece::PieceSetDescriptor}, }; /// A center edge piece of the cube. There are 4 of these in each face of a cube. @@ -34,9 +34,19 @@ pub struct CenterEdge { pub side_direction: Direction, } -impl generic::Piece<24> for CenterEdge { +impl generic::Piece for CenterEdge { type Position = Self; + fn position(&self) -> Self::Position { + self.clone() + } + + fn is_solved(&self, original_pos: &Self::Position) -> bool { + self.main_face == original_pos.main_face + } +} + +impl PieceSetDescriptor<24> for CenterEdge { const REFERENCE_POSITIONS: [Self::Position; 24] = { use faces::*; use Direction::*; @@ -50,14 +60,6 @@ impl generic::Piece<24> for CenterEdge { }; const SOLVED: [Self; 24] = Self::REFERENCE_POSITIONS; - - fn position(&self) -> Self::Position { - self.clone() - } - - fn is_solved(&self, original_pos: &Self::Position) -> bool { - self.main_face == original_pos.main_face - } } impl Rotatable for CenterEdge { @@ -120,7 +122,7 @@ impl CenterEdge { } } -impl DepthPiece<24> for CenterEdge { +impl DepthPiece for CenterEdge { fn is_in_wide_move( &self, normal_depth: u32, diff --git a/barbarosa/src/cube_n/pieces/center/wing.rs b/barbarosa/src/cube_n/pieces/center/wing.rs index 475c6e0..136bd2b 100644 --- a/barbarosa/src/cube_n/pieces/center/wing.rs +++ b/barbarosa/src/cube_n/pieces/center/wing.rs @@ -13,7 +13,7 @@ use crate::{ space::{faces, Axis, Direction, Face}, WideAxisMove, }, - generic, + generic::{self, piece::PieceSetDescriptor}, }; use super::edge::CenterEdge; @@ -28,9 +28,19 @@ pub struct CenterWing { pseudo_oriented: bool, } -impl generic::Piece<48> for CenterWing { +impl generic::Piece for CenterWing { type Position = Self; + fn position(&self) -> Self::Position { + self.clone() + } + + fn is_solved(&self, original_pos: &Self::Position) -> bool { + self.main_face() == original_pos.main_face() + } +} + +impl PieceSetDescriptor<48> for CenterWing { const REFERENCE_POSITIONS: [Self::Position; 48] = { use faces::*; use Direction::*; @@ -45,14 +55,6 @@ impl generic::Piece<48> for CenterWing { }; const SOLVED: [Self; 48] = Self::REFERENCE_POSITIONS; - - fn position(&self) -> Self::Position { - self.clone() - } - - fn is_solved(&self, original_pos: &Self::Position) -> bool { - self.main_face() == original_pos.main_face() - } } impl Rotatable for CenterWing { @@ -139,7 +141,7 @@ impl std::fmt::Debug for CenterWing { } } -impl DepthPiece<48> for CenterWing { +impl DepthPiece for CenterWing { fn is_in_wide_move( &self, normal_depth: u32, diff --git a/barbarosa/src/cube_n/pieces/corner.rs b/barbarosa/src/cube_n/pieces/corner.rs index a1adb76..e4afe48 100644 --- a/barbarosa/src/cube_n/pieces/corner.rs +++ b/barbarosa/src/cube_n/pieces/corner.rs @@ -11,7 +11,10 @@ use crate::{ space::{Axis, Direction, Face}, AxisMove, Vec3, }, - generic::{self, moves::impl_movable_array, utils::map_array_const, PieceSet}, + generic::{ + self, moves::impl_movable_array, piece::PieceSetDescriptor, utils::map_array_const, + PieceSet, + }, }; /// A corner piece of the cube. @@ -25,9 +28,19 @@ pub struct Corner { pub orientation_axis: Axis, } -impl generic::Piece<8> for Corner { +impl generic::Piece for Corner { type Position = Vec3; + fn position(&self) -> Self::Position { + self.position + } + + fn is_solved(&self, original_pos: &Self::Position) -> bool { + self.position() == *original_pos && self.is_oriented() + } +} + +impl PieceSetDescriptor<8> for Corner { const REFERENCE_POSITIONS: [Self::Position; 8] = { use Direction::*; @@ -38,14 +51,6 @@ impl generic::Piece<8> for Corner { }; const SOLVED: [Self; 8] = map_array_const!(Corner::REFERENCE_POSITIONS, 8, Corner::oriented); - - fn position(&self) -> Self::Position { - self.position - } - - fn is_solved(&self, original_pos: &Self::Position) -> bool { - self.position() == *original_pos && self.is_oriented() - } } impl Rotatable for Corner { diff --git a/barbarosa/src/cube_n/pieces/edge.rs b/barbarosa/src/cube_n/pieces/edge.rs index 719b151..3dd94a3 100644 --- a/barbarosa/src/cube_n/pieces/edge.rs +++ b/barbarosa/src/cube_n/pieces/edge.rs @@ -11,7 +11,10 @@ use crate::{ space::{Axis, Direction, Face}, AxisMove, Vec2, }, - generic::{self, moves::impl_movable_array, utils::map_array_const, Piece, PieceSet}, + generic::{ + self, moves::impl_movable_array, piece::PieceSetDescriptor, utils::map_array_const, Piece, + PieceSet, + }, }; // use super::{ContainedInMove, Corner}; @@ -44,9 +47,19 @@ pub struct Edge { pub oriented: bool, } -impl generic::Piece<12> for Edge { +impl generic::Piece for Edge { type Position = (Axis, Vec2); + fn position(&self) -> Self::Position { + (self.normal_axis, self.slice_position) + } + + fn is_solved(&self, original_pos: &Self::Position) -> bool { + self.position() == *original_pos && self.oriented + } +} + +impl PieceSetDescriptor<12> for Edge { // TODO: Try to use cartesian product to make this nicer const REFERENCE_POSITIONS: [(Axis, Vec2); 12] = { use Axis::*; @@ -77,20 +90,12 @@ impl generic::Piece<12> for Edge { /// /// See [crate::cube_n::cube3::mus] for more information. const SOLVED: [Edge; 12] = { - const fn from_tuple((axis, pos): (Axis, Vec2)) -> Edge { + const fn from_tuple((axis, pos): ::Position) -> Edge { Edge::oriented(axis, pos) } map_array_const!(Edge::REFERENCE_POSITIONS, 12, from_tuple) }; - - fn position(&self) -> Self::Position { - (self.normal_axis, self.slice_position) - } - - fn is_solved(&self, original_pos: &Self::Position) -> bool { - self.position() == *original_pos && self.oriented - } } impl Rotatable for Edge { @@ -191,7 +196,7 @@ impl Edge { /// Returns the standard coordinates of the edge pub fn coordinates( - (normal_axis, slice_position): &>::Position, + (normal_axis, slice_position): &::Position, ) -> nalgebra::Vector3 { normal_axis.map_on_slice(Vector3::zeros(), |_| { slice_position.map(|dir| dir.scalar() as f32) diff --git a/barbarosa/src/cube_n/pieces/wing.rs b/barbarosa/src/cube_n/pieces/wing.rs index 9a18729..ea86125 100644 --- a/barbarosa/src/cube_n/pieces/wing.rs +++ b/barbarosa/src/cube_n/pieces/wing.rs @@ -14,7 +14,7 @@ use crate::{ space::{Axis, Direction, Face}, Vec2, WideAxisMove, }, - generic, + generic::{self, piece::PieceSetDescriptor}, }; use super::{edge::ParallelAxesError, Edge}; @@ -29,10 +29,19 @@ pub struct Wing { corresponding_edge: Edge, } -impl generic::Piece<24> for Wing { +impl generic::Piece for Wing { type Position = Self; - /// The solved set of [`Wing`]s. + fn position(&self) -> Self::Position { + self.clone() + } + + fn is_solved(&self, original_pos: &Self::Position) -> bool { + self == original_pos + } +} + +impl PieceSetDescriptor<24> for Wing { const SOLVED: [Wing; 24] = { use Axis::*; use Direction::*; @@ -56,14 +65,6 @@ impl generic::Piece<24> for Wing { }; const REFERENCE_POSITIONS: [Self::Position; 24] = Self::SOLVED; - - fn position(&self) -> Self::Position { - self.clone() - } - - fn is_solved(&self, original_pos: &Self::Position) -> bool { - self == original_pos - } } impl Rotatable for Wing { @@ -147,7 +148,7 @@ impl Wing { } } -impl DepthPiece<24> for Wing { +impl DepthPiece for Wing { fn is_in_wide_move( &self, normal_depth: u32, diff --git a/barbarosa/src/generic/mod.rs b/barbarosa/src/generic/mod.rs index 38215b9..df259f0 100644 --- a/barbarosa/src/generic/mod.rs +++ b/barbarosa/src/generic/mod.rs @@ -12,10 +12,10 @@ pub use self::{ pub mod alg; pub mod moves; pub mod parse; +pub mod piece; pub mod search; pub mod utils; -mod piece; mod scramble; /// A generic cube (or twisty puzzle) diff --git a/barbarosa/src/generic/piece/mod.rs b/barbarosa/src/generic/piece/mod.rs index b5d4656..9038b13 100644 --- a/barbarosa/src/generic/piece/mod.rs +++ b/barbarosa/src/generic/piece/mod.rs @@ -1,28 +1,27 @@ +//! Traits and structs for pieces on the cube. + mod set; use std::fmt::Debug; -pub use set::PieceSet; +pub use set::{PieceSet, PieceSetDescriptor}; -/// A piece on the cube. It is generic over a const `SET_SIZE` which is the number of -/// distinct positions that the piece can be in. You also need to define a position, such -/// that it is impossible to have two pieces in the same position. +/// A piece on the cube. /// -/// The original position of a piece is the way that it gets identified, you can think of it +/// A piece is identified by its original position, you can think of it /// as the color information of a piece. For example, the RUF corner is the one that has the /// original position of `[1, 1, 1]`. Each piece has a reference of these positions, which makes /// it so that we only need to store the current position instead of the original and the current. -pub trait Piece: Sized + PartialEq + Clone + Debug { - /// The solved set of pieces. - const SOLVED: [Self; SET_SIZE]; - - /// The position type of the piece. It should be a type with exactly `SET_SIZE` different possible values. +pub trait Piece: Sized + PartialEq + Clone + Debug { + /// The position type of the piece. + /// + /// Positions are unique in [`PieceSet`]s. That is, there can only + /// be one piece at each position. + /// + /// It should have finite different possible values, such that you + /// can implement [`PieceSetDescriptor`] for it with a specific `N`. type Position: PartialEq + Debug; - /// The reference positions of the piece. This is used to define that, in an array of pieces, the piece at - /// index `i` was originally at position `REFERENCE_POSITIONS[i]`. - const REFERENCE_POSITIONS: [Self::Position; SET_SIZE]; - /// Returns the current position of the piece fn position(&self) -> Self::Position; diff --git a/barbarosa/src/generic/piece/set.rs b/barbarosa/src/generic/piece/set.rs index c0be41f..4b3b110 100644 --- a/barbarosa/src/generic/piece/set.rs +++ b/barbarosa/src/generic/piece/set.rs @@ -8,6 +8,27 @@ use crate::generic::{Movable, Move}; use super::Piece; +/// A trait to be able to use [`PieceSet`] with different types of pieces. +/// +/// This trait is generic over a const `SET_SIZE` which is the number of +/// distinct positions that the piece can be in. +/// +/// This trait is not part of the [`Piece`] trait since that would entail adding +/// a generic const on every use of the [`Piece`] trait, which is very cumebrsome. +/// The ideal situation would be to have an associated const, but you can not use +/// them in any meaningful way in current stable rust :(. +pub trait PieceSetDescriptor: Piece { + /// The solved set of pieces. + const SOLVED: [Self; SET_SIZE]; + + /// The reference positions of the piece. This is used to define that, in an array of pieces, the piece at + /// index `i` was originally at position `REFERENCE_POSITIONS[i]`. + /// + /// Ideally, it should enumarate every possible distinct value of [`Piece::Position`] (but you could technically + /// not do that). + const REFERENCE_POSITIONS: [Self::Position; SET_SIZE]; +} + /// A set of `N` pieces. /// /// This struct provides methods in order to ensure that each piece is unique and that each position @@ -16,17 +37,17 @@ use super::Piece; /// [`PieceSet`] is not responsible for enforcing the specific invariants of the different piece types. /// For example, [`EdgeSet`](crate::cube_n::pieces::edge::EdgeSet) does not check that the parity of the edges is correct. #[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub struct PieceSet, const N: usize> { +pub struct PieceSet, const N: usize> { pieces: [P; N], } -impl, const N: usize> PieceSet { +impl, const N: usize> PieceSet { /// Alias to [`Piece::SOLVED`] pub const SOLVED: Self = Self { pieces: P::SOLVED }; /// Creates a new [`PieceSet`] from an array of pieces. Fails if one of the invariants is /// not upheld. - pub fn new(pieces: [P; N]) -> Result> { + pub fn new(pieces: [P; N]) -> Result> { let output = Self { pieces }; match output.validate() { @@ -36,7 +57,7 @@ impl, const N: usize> PieceSet { } /// Checks whether there is a duplicate piece or position in the set. - pub fn validate(&self) -> Option> { + pub fn validate(&self) -> Option> { if let Some(dup) = find_duplicates(self.pieces.iter().map(P::position)) { return Some(ValidationError::DuplicatePosition(dup)); } @@ -144,7 +165,7 @@ fn find_duplicates(iter: impl IntoIterator) -> Option } #[derive(Debug, Error)] -pub enum ValidationError, const N: usize> { +pub enum ValidationError { #[error("Duplicate position ({0:?})")] DuplicatePosition(P::Position), @@ -155,7 +176,7 @@ pub enum ValidationError, const N: usize> { impl Movable for PieceSet where M: Move, - P: Piece + Movable, + P: PieceSetDescriptor + Movable, { fn apply(&mut self, m: &M) { for piece in &mut self.pieces {