Skip to content

Commit

Permalink
Decompose Square-1 scrambling code.
Browse files Browse the repository at this point in the history
  • Loading branch information
lgarron committed Nov 1, 2024
1 parent f9d8596 commit 0f80ef7
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 126 deletions.
5 changes: 5 additions & 0 deletions src/rs/scramble/puzzles/square1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod parity;
pub mod phase1;
pub mod phase2;
pub mod scramble;
pub mod wedges;
24 changes: 24 additions & 0 deletions src/rs/scramble/puzzles/square1/parity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use cubing::kpuzzle::KPattern;

use crate::scramble::{
puzzles::square1::wedges::{WedgeType, NUM_WEDGES, WEDGE_TYPE_LOOKUP},
randomize::{basic_parity, BasicParity},
};

pub(crate) fn bandaged_wedge_parity(pattern: &KPattern) -> BasicParity {
let wedge_orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(wedge_orbit_info.name.0, "WEDGES");

let mut bandaged_wedges = Vec::<u8>::default();
for slot in 0..NUM_WEDGES {
let value = unsafe {
pattern
.packed_orbit_data()
.get_raw_piece_or_permutation_value(wedge_orbit_info, slot)
};
if WEDGE_TYPE_LOOKUP[value as usize] != WedgeType::CornerUpper {
bandaged_wedges.push(value);
}
}
basic_parity(&bandaged_wedges)
}
86 changes: 86 additions & 0 deletions src/rs/scramble/puzzles/square1/phase1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use std::fmt::Debug;

use cubing::kpuzzle::{KPattern, KPuzzle};

use crate::{
_internal::search::{
check_pattern::PatternValidityChecker,
coordinates::phase_coordinate_puzzle::{PhaseCoordinatePuzzle, SemanticCoordinate},
},
scramble::{
puzzles::{
mask_pattern::mask,
square1::wedges::{WedgeType, WEDGE_TYPE_LOOKUP},
},
randomize::BasicParity,
},
};

use super::{
super::definitions::square1_square_square_shape_kpattern, parity::bandaged_wedge_parity,
};

pub(crate) struct Phase1Checker;

const SLOTS_THAT_ARE_AFTER_SLICES: [u8; 4] = [0, 6, 12, 18];

impl PatternValidityChecker<KPuzzle> for Phase1Checker {
fn is_valid(pattern: &cubing::kpuzzle::KPattern) -> bool {
let orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(orbit_info.name.0, "WEDGES");

for slot in SLOTS_THAT_ARE_AFTER_SLICES {
let value = unsafe {
pattern
.packed_orbit_data()
.get_raw_piece_or_permutation_value(orbit_info, slot)
};

// TODO: consider removing this lookup. We know that the wedge values are only 0, 1, or
// 2 during this phase.
if WEDGE_TYPE_LOOKUP[value as usize] == WedgeType::CornerUpper {
return false;
}
}

true
}
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub(crate) struct Square1Phase1CompoundSemanticCoordinate {
masked_pattern: KPattern,
parity: BasicParity,
}

impl Debug for Square1Phase1CompoundSemanticCoordinate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Phase1Coordinates")
.field("masked_pattern", &self.masked_pattern.to_data())
.field("parity", &self.parity)
.finish()
}
}

impl SemanticCoordinate<KPuzzle> for Square1Phase1CompoundSemanticCoordinate {
fn try_new(_kpuzzle: &KPuzzle, full_pattern: &KPattern) -> Option<Self> {
let phase_mask = &square1_square_square_shape_kpattern(); // TODO: Store this with the coordinate lookup?
let Ok(masked_pattern) = mask(full_pattern, phase_mask) else {
panic!("Mask application failed");
};

// TODO: this isn't a full validity check for scramble positions.
if !Phase1Checker::is_valid(&masked_pattern) {
return None;
}

let parity = bandaged_wedge_parity(full_pattern);
Some(Self {
masked_pattern,
parity,
})
}
}

pub(crate) type Square1Phase1Puzzle =
PhaseCoordinatePuzzle<KPuzzle, Square1Phase1CompoundSemanticCoordinate>;
55 changes: 55 additions & 0 deletions src/rs/scramble/puzzles/square1/phase2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use cubing::kpuzzle::KPuzzle;

use crate::{
_internal::search::{
check_pattern::PatternValidityChecker, hash_prune_table::HashPruneTable,
idf_search::SearchOptimizations,
},
scramble::puzzles::square1::wedges::{WedgeType, WEDGE_TYPE_LOOKUP},
};

struct Phase2Checker;

impl PatternValidityChecker<KPuzzle> for Phase2Checker {
fn is_valid(pattern: &cubing::kpuzzle::KPattern) -> bool {
let orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(orbit_info.name.0, "WEDGES");

for slot in [0, 1, 2, 12, 13, 14] {
let value = unsafe {
pattern
.packed_orbit_data()
.get_raw_piece_or_permutation_value(orbit_info, slot)
};
let wedge_type = &WEDGE_TYPE_LOOKUP[value as usize];

if *wedge_type == WedgeType::CornerUpper && (slot == 0 || slot == 12) {
// We can't slice.
return false;
}

for slot_offset in [3, 6, 9] {
let offset_value = unsafe {
pattern
.packed_orbit_data()
.get_raw_piece_or_permutation_value(orbit_info, slot + slot_offset)
};
let offset_wedge_type = &WEDGE_TYPE_LOOKUP[offset_value as usize];

if wedge_type != offset_wedge_type {
return false;
}
}
}

true
}
}

struct Square1Phase2Optimizations {}

impl SearchOptimizations<KPuzzle> for Square1Phase2Optimizations {
type PatternValidityChecker = Phase2Checker;

type PruneTable = HashPruneTable<KPuzzle, Phase2Checker>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::{
fmt::Debug,
str::FromStr,
time::{Duration, Instant},
};
Expand All @@ -15,87 +14,29 @@ use crate::{
cli::options_impl::{MetricEnum, VerbosityLevel},
search::{
check_pattern::PatternValidityChecker,
coordinates::phase_coordinate_puzzle::{PhaseCoordinatePuzzle, SemanticCoordinate},
hash_prune_table::HashPruneTable,
idf_search::{IDFSearch, IndividualSearchOptions, SearchOptimizations},
prune_table_trait::Depth,
search_logger::SearchLogger,
},
},
scramble::{
puzzles::mask_pattern::mask,
puzzles::{
mask_pattern::mask,
square1::{
phase1::{Phase1Checker, Square1Phase1Puzzle},
wedges::{WedgeType, WEDGE_TYPE_LOOKUP},
},
},
randomize::{
basic_parity, randomize_orbit_naïve, BasicParity, OrbitOrientationConstraint,
OrbitPermutationConstraint, PieceZeroConstraint,
randomize_orbit_naïve, OrbitOrientationConstraint, OrbitPermutationConstraint,
PieceZeroConstraint,
},
scramble_search::{move_list_from_vec, FilteredSearch},
},
};

use super::definitions::{square1_square_square_shape_kpattern, square1_unbandaged_kpuzzle};

#[derive(PartialEq, Eq)]
enum WedgeType {
CornerLower,
CornerUpper,
Edge,
}

const NUM_WEDGES: u8 = 24;

const WEDGE_TYPE_LOOKUP: [WedgeType; NUM_WEDGES as usize] = [
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
];

pub struct Phase1Checker;

const SLOTS_THAT_ARE_AFTER_SLICES: [u8; 4] = [0, 6, 12, 18];

impl PatternValidityChecker<KPuzzle> for Phase1Checker {
fn is_valid(pattern: &cubing::kpuzzle::KPattern) -> bool {
let orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(orbit_info.name.0, "WEDGES");

for slot in SLOTS_THAT_ARE_AFTER_SLICES {
let value = unsafe {
pattern
.packed_orbit_data()
.get_raw_piece_or_permutation_value(orbit_info, slot)
};

// TODO: consider removing this lookup. We know that the wedge values are only 0, 1, or
// 2 during this phase.
if WEDGE_TYPE_LOOKUP[value as usize] == WedgeType::CornerUpper {
return false;
}
}

true
}
}
use super::super::definitions::{square1_square_square_shape_kpattern, square1_unbandaged_kpuzzle};

struct Phase2Checker;

Expand Down Expand Up @@ -135,43 +76,6 @@ impl PatternValidityChecker<KPuzzle> for Phase2Checker {
}
}

#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Square1Phase1CompoundSemanticCoordinate {
masked_pattern: KPattern,
parity: BasicParity,
}

impl Debug for Square1Phase1CompoundSemanticCoordinate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Phase1Coordinates")
.field("masked_pattern", &self.masked_pattern.to_data())
.field("parity", &self.parity)
.finish()
}
}

impl SemanticCoordinate<KPuzzle> for Square1Phase1CompoundSemanticCoordinate {
fn try_new(_kpuzzle: &KPuzzle, full_pattern: &KPattern) -> Option<Self> {
let phase_mask = &square1_square_square_shape_kpattern(); // TODO: Store this with the coordinate lookup?
let Ok(masked_pattern) = mask(full_pattern, phase_mask) else {
panic!("Mask application failed");
};

// TODO: this isn't a full validity check for scramble positions.
if !Phase1Checker::is_valid(&masked_pattern) {
return None;
}

let parity = wedge_parity(full_pattern);
Some(Self {
masked_pattern,
parity,
})
}
}

type Square1Phase1Puzzle = PhaseCoordinatePuzzle<KPuzzle, Square1Phase1CompoundSemanticCoordinate>;

struct Square1Phase2Optimizations {}

impl SearchOptimizations<KPuzzle> for Square1Phase2Optimizations {
Expand All @@ -180,7 +84,7 @@ impl SearchOptimizations<KPuzzle> for Square1Phase2Optimizations {
type PruneTable = HashPruneTable<KPuzzle, Phase2Checker>;
}

pub fn scramble_square1() -> Alg {
pub(crate) fn scramble_square1() -> Alg {
let kpuzzle = square1_unbandaged_kpuzzle();
let generator_moves = move_list_from_vec(vec!["U_SQ_", "D_SQ_", "/"]);

Expand Down Expand Up @@ -317,24 +221,6 @@ pub fn scramble_square1() -> Alg {
panic!("at the (lack of) disco(very)")
}

pub fn wedge_parity(pattern: &KPattern) -> BasicParity {
let wedge_orbit_info = &pattern.kpuzzle().data.ordered_orbit_info[0];
assert_eq!(wedge_orbit_info.name.0, "WEDGES");

let mut bandaged_wedges = Vec::<u8>::default();
for slot in 0..NUM_WEDGES {
let value = unsafe {
pattern
.packed_orbit_data()
.get_raw_piece_or_permutation_value(wedge_orbit_info, slot)
};
if WEDGE_TYPE_LOOKUP[value as usize] != WedgeType::CornerUpper {
bandaged_wedges.push(value);
}
}
basic_parity(&bandaged_wedges)
}

const DEBUG_STATIC_SQUARE_1_SCRAMBLE_SETUP_ALG: Option<&str> = None;
// const DEBUG_STATIC_SQUARE_1_SCRAMBLE_SETUP_ALG: Option<&str> = Some("(0, -1) / (4, -2) / (5, -1) / (4, -5) / (0, -3) / (-1, -3) / (3, 0) / (-3, 0) / (4, 0) / (4, 0) /");

Expand Down
35 changes: 35 additions & 0 deletions src/rs/scramble/puzzles/square1/wedges.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#[derive(PartialEq, Eq)]
pub(crate) enum WedgeType {
CornerLower,
CornerUpper,
Edge,
}

pub(crate) const NUM_WEDGES: u8 = 24;

pub(crate) const WEDGE_TYPE_LOOKUP: [WedgeType; NUM_WEDGES as usize] = [
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
WedgeType::Edge,
WedgeType::CornerLower,
WedgeType::CornerUpper,
];
Loading

0 comments on commit 0f80ef7

Please sign in to comment.