Skip to content

Commit

Permalink
Implement Debug and PartialEq for PackedKState and `PackedKTran…
Browse files Browse the repository at this point in the history
…sformation`.
  • Loading branch information
lgarron committed Aug 25, 2023
1 parent aa96bbe commit fc40a2a
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 12 deletions.
6 changes: 3 additions & 3 deletions src/rs/cli/commands/canonical_algs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn read_to_json<T: for<'a> Deserialize<'a>>(input_file: &Path) -> Result<T, Stri
}

fn do_transformations_commute(t1: &PackedKTransformation, t2: &PackedKTransformation) -> bool {
t1.unpack().apply_transformation(&t2.unpack()) == t2.unpack().apply_transformation(&t1.unpack())
t1.apply_transformation(t2) == t2.apply_transformation(t1)
}

pub fn canonical_algs(args: &CanonicalAlgsArgs) -> Result<(), String> {
Expand All @@ -22,8 +22,8 @@ pub fn canonical_algs(args: &CanonicalAlgsArgs) -> Result<(), String> {
let kpuzzle = KPuzzle::try_new(def).unwrap();
let packed_kpuzzle = PackedKPuzzle::try_from(kpuzzle).unwrap();

println!("{:?}", packed_kpuzzle.start_state().byte_slice());
println!("{:?}", packed_kpuzzle.start_state().unpack().state_data);
println!("{:?}", packed_kpuzzle.start_state());
// println!("{:?}", packed_kpuzzle.start_state().unpack().state_data);

let t1 = packed_kpuzzle
.transformation_from_move(&"R".try_into().unwrap())
Expand Down
1 change: 1 addition & 0 deletions src/rs/packed/orientation_packer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ mod tests {

use crate::PackedKPuzzle;

// TODO: Return a `Result`.
#[test]
fn test_orientation_mod() {
let def = KPuzzleDefinition {
Expand Down
17 changes: 15 additions & 2 deletions src/rs/packed/packed_kpuzzle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::{alloc::Layout, sync::Arc};

use cubing::{
alg::Move,
kpuzzle::{InvalidAlgError, InvalidDefinitionError, KPuzzle, KPuzzleOrbitName},
kpuzzle::{
InvalidAlgError, InvalidDefinitionError, KPuzzle, KPuzzleOrbitName, KTransformation,
},
};

use super::{byte_conversions::usize_to_u8, PackedKState, PackedKTransformation};
Expand Down Expand Up @@ -207,13 +209,24 @@ impl PackedKPuzzle {
new_state
}

pub fn identity_transformation(&self) -> Result<PackedKTransformation, ConversionError> {
let unpacked_ktransformation = self.data.kpuzzle.identity_transformation();
self.pack_transformation(&unpacked_ktransformation)
}

// TODO: implement this as a `TryFrom`?
pub fn transformation_from_move(
&self, // TODO: Any issues with not using `&self`?
&self,
key_move: &Move,
) -> Result<PackedKTransformation, ConversionError> {
let unpacked_ktransformation = self.data.kpuzzle.transformation_from_move(key_move)?;
self.pack_transformation(&unpacked_ktransformation)
}

fn pack_transformation(
&self,
unpacked_ktransformation: &KTransformation,
) -> Result<PackedKTransformation, ConversionError> {
let new_transformation = PackedKTransformation::new(self.clone());
for orbit_info in &self.data.orbit_iteration_info {
let unpacked_orbit_data = unpacked_ktransformation
Expand Down
34 changes: 31 additions & 3 deletions src/rs/packed/packed_kstate.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use std::alloc::{alloc, dealloc};
use std::{
alloc::{alloc, dealloc},
fmt::Debug,
};

use super::{
byte_conversions::{u8_to_usize, PackedOrientationWithMod},
packed_kpuzzle::PackedKPuzzleOrbitInfo,
PackedKPuzzle, PackedKTransformation,
};

use cubing::kpuzzle::KPuzzle;
#[cfg(not(feature = "no_orientation_mod"))]
use cubing::kpuzzle::{KState, KStateData};
#[cfg(not(feature = "no_orientation_mod"))]
Expand Down Expand Up @@ -98,9 +102,9 @@ impl PackedKState {
for i in 0..orbit_info.num_pieces {
let transformation_idx = transformation.get_piece_or_permutation(orbit_info, i);

let new_piece_permutation =
let new_piece_value =
self.get_piece_or_permutation(orbit_info, u8_to_usize(transformation_idx));
into_state.set_piece_or_permutation(orbit_info, i, new_piece_permutation);
into_state.set_piece_or_permutation(orbit_info, i, new_piece_value);

let previous_packed_orientation =
self.get_packed_orientation(orbit_info, u8_to_usize(transformation_idx));
Expand Down Expand Up @@ -205,3 +209,27 @@ impl PackedKState {
}
}
}

struct KPuzzleDebug {
kpuzzle: KPuzzle,
}

impl Debug for KPuzzleDebug {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{ … name: \"{}\" … }}", &self.kpuzzle.definition().name)
}
}

impl Debug for PackedKState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PackedKState")
.field(
"packed_kpuzzle",
&KPuzzleDebug {
kpuzzle: self.packed_kpuzzle.data.kpuzzle.clone(),
},
)
.field("bytes", &self.byte_slice())
.finish()
}
}
138 changes: 134 additions & 4 deletions src/rs/packed/packed_ktransformation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
use std::alloc::{alloc, dealloc};
use std::{
alloc::{alloc, dealloc},
fmt::Debug,
};

use super::{packed_kpuzzle::PackedKPuzzleOrbitInfo, PackedKPuzzle};
use super::{byte_conversions::u8_to_usize, packed_kpuzzle::PackedKPuzzleOrbitInfo, PackedKPuzzle};
pub struct PackedKTransformation {
pub packed_kpuzzle: PackedKPuzzle,
pub bytes: *mut u8,
}
use cubing::kpuzzle::KPuzzle;

#[cfg(not(feature = "no_orientation_mod"))]
use cubing::kpuzzle::{KTransformation, KTransformationOrbitData};

impl Drop for PackedKTransformation {
Expand Down Expand Up @@ -58,14 +64,62 @@ impl PackedKTransformation {
}
}

// Adapted from https://github.com/cubing/cubing.rs/blob/b737c6a36528e9984b45b29f9449a9a330c272fb/src/kpuzzle/transformation.rs#L32-L61
// TODO: dedup the implementation (but avoid runtime overhead for the shared abstraction).
pub fn apply_transformation(
&self,
transformation: &PackedKTransformation,
) -> PackedKTransformation {
let mut new_state = PackedKTransformation::new(self.packed_kpuzzle.clone());
self.apply_transformation_into(transformation, &mut new_state);
new_state
}

// Adapted from https://github.com/cubing/cubing.rs/blob/b737c6a36528e9984b45b29f9449a9a330c272fb/src/kpuzzle/transformation.rs#L32-L61
// TODO: dedup the implementation (but avoid runtime overhead for the shared abstraction).
// TODO: assign to self from another value, not into another
pub fn apply_transformation_into(
&self,
transformation: &PackedKTransformation,
into_state: &mut PackedKTransformation,
) {
for orbit_info in &self.packed_kpuzzle.data.orbit_iteration_info {
// TODO: optimization when either value is the identity.
for i in 0..orbit_info.num_pieces {
let transformation_idx = transformation.get_piece_or_permutation(orbit_info, i);

let new_piece_permutation =
self.get_piece_or_permutation(orbit_info, u8_to_usize(transformation_idx));
into_state.set_piece_or_permutation(orbit_info, i, new_piece_permutation);

let previous_packed_orientation =
self.get_orientation(orbit_info, u8_to_usize(transformation_idx));

// TODO: lookup table?
let new_orientation = (previous_packed_orientation
+ transformation.get_orientation(orbit_info, i))
% orbit_info.num_orientations;
into_state.set_orientation(orbit_info, i, new_orientation);
}
}
}

pub fn byte_slice(&self) -> &[u8] {
// yiss ☺️
// https://stackoverflow.com/a/27150865
unsafe { std::slice::from_raw_parts(self.bytes, self.packed_kpuzzle.data.num_bytes) }
}

pub fn hash(&self) -> u64 {
cityhash::city_hash_64(self.byte_slice())
}

#[cfg(not(feature = "no_orientation_mod"))]
pub fn unpack(&self) -> KTransformation {
use std::sync::Arc;

use cubing::kpuzzle::KTransformationData;

use crate::packed::byte_conversions::u8_to_usize;

let mut state_data = KTransformationData::new();
for orbit_info in &self.packed_kpuzzle.data.orbit_iteration_info {
let mut permutation = Vec::<usize>::new();
Expand All @@ -86,3 +140,79 @@ impl PackedKTransformation {
}
}
}

struct KPuzzleDebug {
kpuzzle: KPuzzle,
}

impl Debug for KPuzzleDebug {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{ … name: \"{}\" … }}", &self.kpuzzle.definition().name)
}
}

impl Debug for PackedKTransformation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PackedKTransformation")
.field(
"packed_kpuzzle",
&KPuzzleDebug {
kpuzzle: self.packed_kpuzzle.data.kpuzzle.clone(),
},
)
.field("bytes", &self.byte_slice())
.finish()
}
}

impl PartialEq<PackedKTransformation> for PackedKTransformation {
fn eq(&self, other: &Self) -> bool {
self.byte_slice() == other.byte_slice()
}
}

#[cfg(test)]
mod tests {
use cubing::alg::AlgParseError;
use cubing::parse_move;
use cubing::puzzles::cube3x3x3_kpuzzle;

use crate::packed::packed_kpuzzle::ConversionError;
use crate::{PackedKPuzzle, PackedKTransformation};

#[test]
fn test_orientation_mod() -> Result<(), String> {
let kpuzzle = cube3x3x3_kpuzzle();
let packed_kpuzzle = PackedKPuzzle::try_from(kpuzzle).map_err(|e| e.description)?;

let from_move = |move_str: &str| -> Result<PackedKTransformation, String> {
let r#move = parse_move!(move_str).map_err(|e: AlgParseError| e.description)?;
packed_kpuzzle
.transformation_from_move(&r#move)
.map_err(|e: ConversionError| e.to_string())
};

let id = packed_kpuzzle
.identity_transformation()
.map_err(|e| e.to_string())?;
let t1 = from_move("R")?;
let t2 = from_move("R2")?;
let t2prime = from_move("R2'")?;
let t4 = from_move("R4")?;
let t5 = from_move("R5")?;

assert_eq!(id, t4);
assert_eq!(t1, t5);
assert_eq!(t2, t2prime);

assert_ne!(id, t1);
assert_ne!(id, t2);
assert_ne!(t1, t2);

assert_eq!(id.apply_transformation(&t1), t1);
assert_eq!(t1.apply_transformation(&t1), t2);
assert_eq!(t2.apply_transformation(&t1).apply_transformation(&t2), t1);

Ok(())
}
}

0 comments on commit fc40a2a

Please sign in to comment.