Q Language
The Q language is Qter’s representation of an executable program. The file format was designed in such a way that, with only basic Rubik’s Cube knowledge, a human can physically manipulate a twisty puzzle to execute a program and perform a meaningful computation.
Q files are expected to be read from top to bottom. Each line indicates an instruction, the simplest of which is just an algorithm to perform on the cube. For example:
PuzzlesA: 3x31 | U' R22 | L D'...
PuzzlesA: 3x31 | U' R22 | L D'...
The PuzzlesPuzzles declaration specifies the types of twisty puzzles used. In this example, it is declaring that you must start with a 3x3x3 cube, and that it has the name “A”. The name is unimportant in this example, but becomes important when operating on multiple cubes. The instructions indicate that you must perform the algorithm U' R2 L D'U' R2 L D' on the Rubik’s Cube. You must begin with the cube solved before following the instructions.
The Q file format also includes special instructions that involve the twisty puzzle but require additional logic. These logical instructions are designed to be simple enough for humans to understand and perform.
goto <number>goto <number>
Jump to the specified line number instead of reading on to the next line. For example:
PuzzlesA: 3x31 | U' R22 | L D'3 | goto 1...
PuzzlesA: 3x31 | U' R22 | L D'3 | goto 1...
Indicates an infinite loop of performing (U’ R2 L D’) on the Rubik’s Cube. After performing the algorithm, the gotogoto instruction requires you to jump back to line 1 where you started.
solved-goto <number> <positions...>solved-goto <number> <positions...>
If the specified positions on the puzzle each contain their solved piece, then jump to the line number specified as if it was a gotogoto instruction. Otherwise, do nothing and go to the next instruction. Refer to What is Qter for more details. For example:
PuzzlesA: 3x31 | U' R22 | solved-goto 4 UFR UF3 | goto 14 | L D'...
PuzzlesA: 3x31 | U' R22 | solved-goto 4 UFR UF3 | goto 14 | L D'...
indicates performing (U’ R2) and then repeatedly performing (U’ R2) until the UFR corner position and UF edge position contain their solved pieces. Then, perform (L D’) on the Rubik’s Cube.
solvesolve
Solve the puzzle using your favorite method. Logically, this instruction zeroes out all registers on the puzzle.
repeat until <positions...> solved <algorithm>repeat until <positions...> solved <algorithm>
Repeat the given algorithm until the given positions contain their solved pieces. Logically, this is equivalent to
N | solved-goto N+3 <positions...>N+1 | <algorithm>N+2 | goto NN+3 | ...
N | solved-goto N+3 <positions...>N+1 | <algorithm>N+2 | goto NN+3 | ...
but is easier to read and understand. This pattern occurs enough in Q programs that it is worth defining an instruction for it.
input <message> <algorithm> max-input <number>input <message> <algorithm> max-input <number>
This instruction allows taking in arbitrary input from a user which will be stored and processed on the puzzle. To give an input, repeat the given algorithm “your input” number of times. For example:
PuzzlesA: 3x31 | input "Pick a number" R U R' U' max-input 5...
PuzzlesA: 3x31 | input "Pick a number" R U R' U' max-input 5...
To input the number two, execute the algorithm ((R U R’ U’) (R U R’ U’)) on the Rubik’s Cube. Notice that if you try to execute (R U R’ U’) six times, the cube will return to its solved state as if you had inputted the number zero. Thus, your input number must not be greater than five, and this is shown with the max-input 5max-input 5 syntax.
If a negative input is meaningful to the program you are executing, you can input negative one by performing the inverse of the algorithm. For example, negative two would be inputted as ((U R U’ R’) (U R U’ R’)).
halt <message> [<algorithm> counting-until <positions...>]halt <message> [<algorithm> counting-until <positions...>]
This instruction terminates the program and gives an output, and it is similar to the inputinput instruction but in reverse. To decode the output of the program, repeat the given algorithm until the given positions given are solved. The number of repetitions it took to solve the pieces, along with the specified message, is considered the output of the program. For example:
PuzzlesA: 3x31 | input "Choose a number" R U R' U' max-input 52 | halt "You chose" U R U' R' counting-until UFR
PuzzlesA: 3x31 | input "Choose a number" R U R' U' max-input 52 | halt "You chose" U R U' R' counting-until UFR
In this example, after performing the input and reaching the halt instruction, you would have to repeat U R U' R'U R U' R' until the UFR corner is solved. For example, if you inputted the number two by performing (R U R' U') (R U R' U')(R U R' U') (R U R' U'), the expected output will be two, since you have to perform U R U' R'U R U' R' twice to solve the UFR corner. Therefore, the expected output of the program is “You chose 2”.
If the program does not require giving a numeric output, then the algorithm may be left out. For example:
PuzzlesA: 3x31 | halt "I halt immediately"
PuzzlesA: 3x31 | halt "I halt immediately"
print <message> [<algorithm> counting-until <positions...>]print <message> [<algorithm> counting-until <positions...>]
This is an optional instruction that you may choose to ignore. The printprint instruction serves as a secondary mechanism to produce output without exiting the program. The motivation stems from the fact that, without this instruction, the only form of meaningful output is the single number produced by the halthalt instruction.
To execute this instruction, repeat the given algorithm until the positions are solved, analogous to the halt instruction. The number of repetitions this took is then the output of the print statement. Then, you must perform the inverse of the algorithm the same number of times, undoing what you just did and returning the puzzle to the state it was in before executing the print instruction. For example:
PuzzlesA: 3x31 | R U R2 B2 U L U' L' D' R' D R B2 U22 | print "This should output ten:" R U counting-until UFR UF3 | halt "This should also output ten:" R U counting-until UFR UF
PuzzlesA: 3x31 | R U R2 B2 U L U' L' D' R' D R B2 U22 | print "This should output ten:" R U counting-until UFR UF3 | halt "This should also output ten:" R U counting-until UFR UF
Like the halthalt instruction, including only a message is allowed. In this case, you can skip this instruction as there is nothing to do. For example:
PuzzlesA: 3x31 | print "Just a friendly debugging message :-)"...
PuzzlesA: 3x31 | print "Just a friendly debugging message :-)"...
switch <letter>switch <letter>
This instruction allows Qter to support using multiple puzzles in a single program. It tells you to put down your current puzzle and pick up a different one, labeled by letter in the PuzzlesPuzzles declaration. It is important that you do not rotate the puzzle when setting it aside or picking it back up. For example:
PuzzlesA: 3x3B: 3x31 | U2 | switch B3 | R...
PuzzlesA: 3x3B: 3x31 | U2 | switch B3 | R...
This program requires two Rubik’s Cubes to execute. The instructions indicate performing UU on the first Rubik’s Cube and then RR on the second. When the program starts, you are expected to be holding the first cube in the list. Having multiple Rubik’s Cubes is helpful for when a single one doesn’t provide enough storage space for what you wish to do.