Any sequence of turns on a 3x3 Rubik's Cube. Usually used to describe an algorithm used to solve a specific case for speedcubing.
The notation used is based on: https://www.speedsolving.com/wiki/index.php/Notation
It is meant to be used for speedcubing so it includes options such as cube rotations, wide moves and three-quarter turns even if those aren't necessary to be able to solve the cube, but can be important in describing the fastest way to solve a given case for a human
Describes a single turn, which is rotating any turnable in a given direction for a given amount of degrees
Describes anything that can be turned on a Rubik's Cube such as a face, a slice, a rotation of the whole cube or several slices together also known as a wide move
Describes how much to turn a turnable in a turn
Describes which direction to turn a turnable in a turn
fromTurnList : List Turn -> Algorithm
Create an Algorithm from a list of turns
fromTurnList
[ Turn U OneQuarter CounterClockwise
, Turn B Halfway Clockwise
]
empty : Algorithm
An empty algorithm
toString : Algorithm -> String
Display an algorithm in a standard format readable by humans
fromTurnList
[ Turn U Halfway CounterClockwise
, Turn F OneQuarter Clockwise
]
|> toString
--> "U2' F"
fromString : String -> Result FromStringError Algorithm
Parses user input and either returns the algorithm described by the string or a detailed error description of why it failed
fromString "" --> Err EmptyAlgorithm
fromString "U" --> Ok (fromTurnList [Turn U OneQuarter Clockwise])
The different descriptions of in which way a string is not a valid algorithm string. Note that all these errors assume that the string is user input, and so makes some opinionated decisions about when and how to error based on that.
If you want to programatically create arbitrary algorithms you should use constructors such as fromTurnList
For an example of how to handle and display these errors to a user on user input, make sure to check out this full user input example
EmptyAlgorithm: There were no turns in the string and this does not make sense for user input.
If you need behaviour like this just allow the user to not input any algorithm at all
InvalidTurnable: A turnable such as U or x was expected but not found
InvalidTurnLength: It seems like a turn length such as 2 or 3 was attempted to be specified but wasn't valid
RepeatedTurnable: The same turnable was repeated twice in a row which would never make sense in an algorithm. The correct way to describe this is by combining the two into one such as UU becoming U2, or UU' just not being there at all
TurnWouldWorkWithoutInterruption: It looks like an otherwise correct turn was specified but a parenthesis, some whitespace or something similar came in the way making it invalid
ApostropheWrongSideOfLength: It looks like the apostrophe was put on the wrong side of the length, such as U'2 instead of U2' in an otherwise correct turn, just swapping these would make it valid
UnclosedParenthesis: There is an opening parenthesis that was never closed
UnmatchedClosingParenthesis: There is a closing parenthesis that doesn't have an opening match
EmptyParentheses: There is a set of parentheses that aren't enclosing any turns, which does not make sense as parentheses are used to group turns to help memorization and execution
NestedParentheses: A second set of parentheses were started within a set of parentheses. Nested triggers or other nested grouping hasn't seemed to be a relevant need anywhere in the community so it is not allowed until need has been proven
SpansOverSeveralLines: An algorithm is not allowed to span over several different lines, the string input should just be a single line
InvalidSymbol: A symbol was encountered that does not make any sense in an algorithm anywhere.
UnexpectedError: The parsing code behaved in an unexpected way. This should never happen unless we have a bug in our code. If you get this error in production code just either tell the user that the algorithm wasn't valid without any further explanation or tell them something unexpected happen. The debugInfo key is not helpful to show to users, but only for figuring out how to fix the Elm Package to avoid this happening in the future, and logging a Github Issue with the debugInfo would be very appreciated
debugFromStringError : FromStringError -> String
Describes the error as a string, and is not recommended to be displayed to end-users, but rather to be used in error mesages logged for developer's eyes etc.
case fromString algorithmString of
Ok _ ->
doSomethingOnSuccess
Err error ->
logError (debugFromStringError error)
inverse : Algorithm -> Algorithm
Get the inverse of the algorithm.
By definition this means that if one was to apply the algorithm followed by its inverse one would arrive at the same state one started at.
Result.map inverse <| fromString "UB'"
--> fromString "BU'"
append : Algorithm -> Algorithm -> Algorithm
We append the two arguments, so a ++ b
Result.map2 append (fromString "U") (fromString "B'")
--> fromString "UB'"
reverseAppend : Algorithm -> Algorithm -> Algorithm
We append the two algorithms in reverse, so b ++ a
Result.map2 reverseAppend (fromString "U") (fromString "B'")
--> fromString "B'U"
allCubeAngles : List.Nonempty.Nonempty Algorithm
24 algorithms to rotate a cube to any of the 24 unique angles it can be positioned in
import List.Nonempty
List.Nonempty.length allCubeAngles --> 24
allTurns : List.Nonempty.Nonempty Turn
All possible combinations of turnables, lengths and directions
Can for example be used if you ever need to list all possible turns to a user, or if you need to select a turn at random
import List.Nonempty
List.Nonempty.sample allTurns
List.Nonempty.length allTurns
--> List.Nonempty.length allTurnables
--> * List.Nonempty.length allTurnLengths
--> * List.Nonempty.length allTurnDirections
allTurnables : List.Nonempty.Nonempty Turnable
All possible turnables
Can for example be used if you ever need to list all possible turnables to a user, or if you need to select a turnable at random
import List.Nonempty
List.Nonempty.sample allTurnables
List.Nonempty.length allTurnables --> 18
allTurnLengths : List.Nonempty.Nonempty TurnLength
All possible turn lengths
Can for example be used if you ever need to list all possible turn lengths to a user, or if you need to select a turn length at random
import List.Nonempty
List.Nonempty.sample allTurnLengths
List.Nonempty.length allTurnLengths --> 3
allTurnDirections : List.Nonempty.Nonempty TurnDirection
All possible turn directions
Can for example be used if you ever need to list all possible turn directions to a user, or if you need to select a turn direction at random
import List.Nonempty
List.Nonempty.sample allTurnDirections
List.Nonempty.length allTurnDirections --> 2
toTurnList : Algorithm -> List Turn
You should not need this for by far most use cases.
It will let you introspect the algorithm which can be useful in some advanced usecases, but in general you should avoid this and just pass around the algorithm type