Twister is a library for modeling the state of twisty puzzles. To get started, check out the interactive playground.
The recommended way to install is through NPM.
npm install @bedard/twister
Alternatively, you can use the CDN. When using the CDN, the library will be exposed globally as Twister
.
<script src="https://unpkg.com/@bedard/twister"></script>
Below is the recommended way to instantiate Twister models. Using destructured imports allows for unused puzzles to be tree-shaken from your application.
import { Cube } from '@bedard/twister'
const puzzle = new Cube({ size: 3 })
Once a puzzle has been instantiated, the following methods are available...
Set the puzzle to a given state. State objects can be created using the output
method.
puzzle.apply(state)
Create a new puzzle instance with the same state
and options
.
const puzzle = new Puzzle()
const clone = puzzle.clone()
Updates puzzle state using a parsed turn object. In most situations, it's simpler to use the turn
method and make use of turn notation.
const turn = puzzle.parse('R')
puzzle.execute(turn)
Generates a scramble of a default or specified number of moves, but does not execute it.
const scramble = puzzle.generateScramble()
Generate the string representation of a parsed turn object. This can be thought of as the opposite of parse
.
const turn = puzzle.parse('R')
puzzle.notation(turn) // 'R'
Returns a minified version of the puzzle's state. This method is useful for saving state as JSON, then restoring that state via the apply
method.
const state = puzzle.output()
Convert a single piece of puzzle notation to a turn object. This method is generally used to interact with the execute
method, but is also useful for testing if notation is valid. To parse a turn in reverse, provide true
as the second argument.
const turn = puzzle.parse('R')
Convert a space-delimited string of turns into an array of turn objects. To parse an algorithm in reverse, provide true
as the second argument.
const turns = puzzle.parseAlgorithm('R U R-')
Return a puzzle to its solved state.
puzzle.reset()
Scrambles a puzzle to a default or specified number of moves. This is similar to generateScramble
, the only difference being that this method executes the resulting scramble. This method is also available via the CLI, more info here.
puzzle.scramble()
Get stickers affected by a turn. If no turn notation is provided, all stickers will be returned.
const stickers = puzzle.stickers('R')
Test if the puzzle is solved, or matches a specific state.
// test if the puzzle is solved
const solved = puzzle.test()
// test for a specific state
const isSame = puzzle.test(otherPuzzle.output())
Executes an algorithm. This method is also available via the CLI, more info here.
puzzle.turn('R U R-')
Execute the reverse of an algorithm. Note that unturns are executed from right to left.
const scramble = puzzle.turn('R U R-')
puzzle.unturn('R U R-') // 'R U- R-'
All stickers are stored as { value }
objects. This allows for additional information, such as rendering data, to be attached to the stickers. To do this, simply instantiate the puzzle, and modify the objects that are part of puzzle.state
.
import { Cube } from '@bedard/twister'
const puzzle = new Cube({ size: 3 })
puzzle.state.u[0].foo = 'bar'
For applications with advanced scrambling needs, a custom random function can be provided on instantiation. Below is an example using Rando.js to generate cryptographically strong scrambles. The random
option must be a function that returns a floating point number between 0
and 1
. By default, Math.random
is used.
import { Cube } from '@bedard/twister'
import { rando } from '@nastyox/rando.js';
const puzzle = new Cube({
random: rando,
size: 3,
});
While this library does it's best to generate strong scrambles, it should never be used in WCA events. Always use the official TNoodle library for WCA purposes.
The following utilities are available from the command line. Constructor options can be provided via --options
. Note that when providing JSON arguments, we use JSON5 syntax for a smoother user experience.
Parse a single piece of turn notation.
$ twister parse cube R
Parse multiple pieces of turn notation.
$ twister parseAlgorithm cube "R U R-"
Scramble a puzzle.
# scramble a puzzle
$ twister scramble cube
# scramble a puzzle to a specific number of moves
$ twister scramble cube --turns=10
Execute an algorithm. This will be performed on a solved puzzle unless an initial state is provided.
# apply turns to a solved puzzle
$ twister turn cube "R U R-"
# apply turns from an initial state
$ twister turn cube "R U R-" --state="{...}"
# apply turns and test for a particular state
$ twister turn cube "R U R-" --test="{...}"
This puzzle represents an N-layered face turning cube.
import { Cube } from '@bedard/twister';
const puzzle = new Cube({ size: 3 });
Cube state is represented as an array of sticker objects. Each face array starts from the top left sticker and read sequentially to the bottom right. To picture how these values map onto an actual cube, imagine unfolding a cube while looking at the F
face. Notice that the B
face has the same orientation as the L
, F
, and R
faces.
Our notation is a superset of WCA notation. Any algorithm produced by a WCA scrambler is compatible with this library. There are however, a couple of extensions we've made to the WCA notation. The first of which is the optional use of a -
to indicate counter-clockwise turns. The second is the ability to annotate "slice turns" with a single move. To do this, simply omit the wide
segment of a turn. For example, a 3F
in our notation system would be equal to 3Fw 2Fw'
in WCA notation.
This puzzle represents an N-layered face turning dodecahedron.
import { Dodecaminx } from '@bedard/twister';
const puzzle = new Dodecaminx({ size: 3 });
State for a dodecaminx is stored as an array of corner matrices, middle arrays, and a center value. These arrays start from the primary corner of a face, and continue clockwise around that face. The corner matrices are similar to that of a cube face, starting with the corner furthest from the center and reading sequentially towards the center. Middle arrays start with the sticker furthest from the center. Note that for even-layered puzzles, the middle and center values are omitted.
Notation for this puzzle is similar to that of cubes. The main difference is that whole-puzzle rotations are denoted by lowercase letters. Here are a few examples to demonstrate various turns around the U
face.
U
= outer layer turned once clockwiseU2
= outer layer turned twice clockwiseU2-
= outer layer turned twice counter-clockwise2U
= second layer turned once clockwiseUw
= second and outer layer turned once clockwiseu
= entire puzzle rotated once clockwiseu2
= entire puzzle rotated twice clockwiseu2-
= entire puzzle rotated twice counter-clockwise
Copyright (c) 2020-present, Scott Bedard