Types and helper functions to work with the Permutate Last Layer (PLL) algorithm set, the last step of the CFOP method. See https://www.speedsolving.com/wiki/index.php/PLL for further information
All the cases are represented here. Use the value constructors here or @all to specify a given case in your code, and pass these to any of the helper functions
all : List.Nonempty.Nonempty PLL
A non-empty list of all the PLLs. Can for example be used for randomly selecting a pll
import List.Nonempty
-- All the PLLs are there!
List.Nonempty.length all --> 21
-- We could for example select a random PLL case
-- via this
List.Nonempty.sample all
getLetters : PLL -> String
Generates a string of the identifying letters of the case.
This could be used either for serialization purposes, or for building a string to display the user in some instances.
-- Format is always first letter capitalized and
-- the second one lower case if applicable
getLetters Ua --> "Ua"
getLetters H --> "H"
solvedBy : Algorithm -> PLL -> Basics.Bool
Check whether an algorithm solves a PLL case.
Note that actually solving the cube depends on it being in the correct execution angle as well and doing the last AUF. This function just checks if with those correctly aligned the algorithm can solve it. So different algorithms can pass this as seen in these examples:
import Algorithm
Algorithm.fromString "(x) R' U R' D2 R U' R' D2 R2 (x')"
|> Result.map (\alg -> solvedBy alg Aa)
--> Ok True
Algorithm.fromString "U (x) R' U R' D2 R U' R' D2 R2 (x')"
|> Result.map (\alg -> solvedBy alg Aa)
--> Ok True
Algorithm.fromString "(x) R' U R' D2 R U' R' D2 R2 (x') U"
|> Result.map (\alg -> solvedBy alg Aa)
--> Ok True
Algorithm.fromString "U"
|> Result.map (\alg -> solvedBy alg Aa)
--> Ok False
getAllEquivalentAUFs : ( AUF, PLL, AUF ) -> List.Nonempty.Nonempty ( AUF, AUF )
Calculates and returns all pairs of AUFs that are equivalent to the given pair of AUFs for the given PLL
import AUF
import Expect
import Expect.Extra exposing (equalNonEmptyListMembers)
import List.Nonempty
getAllEquivalentAUFs ( AUF.None, H, AUF.None )
|> equalNonEmptyListMembers
(List.Nonempty.Nonempty
( AUF.None, AUF.None )
[ ( AUF.Clockwise, AUF.CounterClockwise )
, ( AUF.Halfway, AUF.Halfway )
, ( AUF.CounterClockwise, AUF.Clockwise )
]
)
--> Expect.pass
getAllAUFEquivalencyClasses : PLL -> List.Nonempty.Nonempty (List.Nonempty.Nonempty ( AUF, AUF ))
Returns a list of lists, where each sublist represents an equivalency class of AUF pairs for the given The equivalency classes are also exhaustive, so every possible AUF pair is represented in this list of lists
{ caseRecognition : CaseRecognitionSpecification
, postAUFRecognition : PostAUFRecognitionSpecification
}
Describes a unique way to recognize the pll case from just the two sides given by the RecognitionAngle. It also describes one or more possibilities for how to recognize which way to do the final AUF.
{ patterns : Maybe (List.Nonempty.Nonempty RecognitionPattern)
, absentPatterns : Maybe (List.Nonempty.Nonempty RecognitionPattern)
, oppositelyColored : List ( List.Nonempty.Nonempty RecognitionElement
, List.Nonempty.Nonempty RecognitionElement )
, adjacentlyColored : List ( List.Nonempty.Nonempty RecognitionElement
, List.Nonempty.Nonempty RecognitionElement )
, identicallyColored : List ( RecognitionElement
, RecognitionElement
, List RecognitionElement )
, differentlyColored : List ( RecognitionElement
, RecognitionElement
, List RecognitionElement )
, noOtherStickersMatchThanThese : Maybe (List.Nonempty.Nonempty RecognitionElement)
, noOtherBlocksPresent : Basics.Bool
}
Describes a unique way to recognize the pll case from just the two sides given by the RecognitionAngle
List.Nonempty.Nonempty { elementsWithOriginalFace : List.Nonempty.Nonempty ( RecognitionElement
, Cube.Advanced.Face )
, finalFace : Cube.Advanced.Face
}
Describes one or more possibilities for how to recognize which way to do the final AUF
Either a type of pattern on the two sides or just a single sticker on the two sides.
All the possible patterns that we use to recognize the pll case.
The six visible stickers during two sided recognition.
getUniqueTwoSidedRecognitionSpecification : { pllAlgorithmUsed : Algorithm, recognitionAngle : RecognitionAngle, preAUF : AUF, pll : PLL } -> Result RecognitionError RecognitionSpecification
Gets a two sided recognition specification that uniquely identifies the pll case and preAUF
The angle the cube is being looked at while doing two sided recognition
uflRecognitionAngle : RecognitionAngle
Describes looking at the cube so that the U F and L sides are visible
ufrRecognitionAngle : RecognitionAngle
Describes looking at the cube so that the U F and R sides are visible
Occurs if the pll algorithm provided to getUniqueTwoSidedRecognitionSpecification for the case does not solve the case
getSymmetry : PLL -> PLLWithSymmetryInfo
Get the type of symmetry this PLL case displays
A PLL with the classification of it by the symmetry patterns of the case. The descriptions of the different classes of symmetries can be found below
A fully symmetric PLL where you can use the same algorithm to solve it from any angle and doing a preAUF and a postAUF are equivalent. For example (U, pll-alg, U) is equivalent to (no-auf, pll-alg, U2)
A half symmetric PLL which has the same AUF properties as a fully symmetric PLL but only opposing faces can be solved with the same PLL algorithm, so AUF transformations can also only happen by adding or subtracting U2s to the AUFs
An N-Perm symmetric PLL (which only includes the N-Perms) can like fully symmetric PLLs be solved with the same algorithm from any angle, but here a transformation through pre-AUF causes the inverse transformation for the post-AUF. It is best explained with an example: With the same example of (U, pll-alg, U) from the fully symmetric case, with an N-perm it would now be equivalent to (no-auf, pll-alg, no-auf)
A non-symmetric PLL. Any given PLL algorithm can only solve this case from a single angle and therefore no AUF transformations make sense in this case either
pllWithSymmetryInfoToPLL : PLLWithSymmetryInfo -> PLL
Convert a PLL with symmetry info to a normal PLL type
fullySymmetricPLLToPLL : FullySymmetricPLL -> PLL
Convert a fully symmetrical PLL with symmetry info to a normal PLL type
halfSymmetricPLLToPLL : HalfSymmetricPLL -> PLL
Convert a half symmetrical PLL with symmetry info to a normal PLL type
nPermSymmetricPLLToPLL : NPermSymmetricPLL -> PLL
Convert an N-perm symmetrical PLL with symmetry info to a normal PLL type
nonSymmetricPLLToPLL : NonSymmetricPLL -> PLL
Convert a non-symmetrical PLL with symmetry info to a normal PLL type
{ h : Algorithm
, ua : Algorithm
, ub : Algorithm
, z : Algorithm
, aa : Algorithm
, ab : Algorithm
, e : Algorithm
, f : Algorithm
, ga : Algorithm
, gb : Algorithm
, gc : Algorithm
, gd : Algorithm
, ja : Algorithm
, jb : Algorithm
, na : Algorithm
, nb : Algorithm
, ra : Algorithm
, rb : Algorithm
, t : Algorithm
, v : Algorithm
, y : Algorithm
}
A collection of algorithms that solves the respective case
getAlgorithm : Algorithms -> PLL -> Algorithm
Get the algorithm for the PLL case from an algorithm collection. This helps avoid any typos or need to write your own case statements in order to get the algorithm for a case passed to a function
getAlgorithm referenceAlgorithms Y
--> referenceAlgorithms.y
referenceAlgorithms : Algorithms
Plls verified to be correct so they can be used to verify user selected plls or for displaying a pll case somewhere on the site.
They have been chosen to be the optimally lowest move count in HTM just for a small performance boost.
The example tests below are just meant for an easier to read version of all the algorithms that are verified to be correct. They are also tested via elm-verify-examples so the string versions are correct equivalents to the code below.
import Algorithm
-- Edges Only
Algorithm.fromString "R2 U2 R U2 R2 U2 R2 U2 R U2 R2"
--> Ok referenceAlgorithms.h
Algorithm.fromString "F2 U' (L R') F2 (L' R) U' F2"
--> Ok referenceAlgorithms.ua
Algorithm.fromString "F2 U (R' L) F2 (R L') U F2"
--> Ok referenceAlgorithms.ub
Algorithm.fromString "R B' R' B F R' F B' R' B R F2"
--> Ok referenceAlgorithms.z
-- Corners Only
Algorithm.fromString "R' F R' B2 R F' R' B2 R2"
--> Ok referenceAlgorithms.aa
Algorithm.fromString "R B' R F2 R' B R F2 R2"
--> Ok referenceAlgorithms.ab
Algorithm.fromString "D R' D2 F' D L D' F D2 R D' F' L' F"
--> Ok referenceAlgorithms.e
-- Corners And Edges
Algorithm.fromString "L F R' F' L' F' D2 B' L' B D2 F' R F2"
--> Ok referenceAlgorithms.f
Algorithm.fromString "F2' D (R' U R' U' R) D' F2 L' U L"
--> Ok referenceAlgorithms.ga
Algorithm.fromString "R' U' R B2 D (L' U L U' L) D' B2"
--> Ok referenceAlgorithms.gb
Algorithm.fromString "R2' D' F U' F U F' D R2 B U' B'"
--> Ok referenceAlgorithms.gc
Algorithm.fromString "R U R' F2 D' (L U' L' U L') D F2"
--> Ok referenceAlgorithms.gd
Algorithm.fromString "B2 R' U' R B2 L' D L' D' L2"
--> Ok referenceAlgorithms.ja
Algorithm.fromString "B2 (L U L') B2 (R D' R D) R2"
--> Ok referenceAlgorithms.jb
Algorithm.fromString "L U' R U2 L' U R' L U' R U2 L' U R'"
--> Ok referenceAlgorithms.na
Algorithm.fromString "R' U L' U2 R U' L R' U L' U2 R U' L"
--> Ok referenceAlgorithms.nb
Algorithm.fromString "F2 R' F' U' F' U F R F' U2 F U2 F'"
--> Ok referenceAlgorithms.ra
Algorithm.fromString "R2 F R U R U' R' F' R U2 R' U2 R"
--> Ok referenceAlgorithms.rb
Algorithm.fromString "F2 D R2 U' R2 F2 D' L2 U L2"
--> Ok referenceAlgorithms.t
Algorithm.fromString "R' U R' U' B' R' B2 U' B' U B' R B R"
--> Ok referenceAlgorithms.v
Algorithm.fromString "F2 D R2 U R2 D' R' U' R F2 R' U R"
--> Ok referenceAlgorithms.y