RubicCube

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

This program implements a Rubik’s Cube simulator, rendering all six faces of a 3×3×3 cube on screen using user-defined graphics characters (UDGs) stored in arrays. The cube’s state is encoded in a 6×14 string array `a$`, where the first nine columns hold cubie colors per face and columns 10–14 store adjacency data for rotation logic. Clockwise and counter-clockwise face rotations are handled by subroutines at lines 1020 and 1150, which manipulate the state array and optionally animate the affected cubies via the display routine at line 800. The program supports saving and loading named cube states to tape as a string array, and includes a move-history string `m$` that records each rotation to allow an “unscramble” playback feature. A companion machine code block is loaded at `USR “a”` (the UDG base address) via a separate `CODE` file, providing the custom cubie graphics used throughout the display.


Program Analysis

Program Structure

The program is organized into well-separated subroutines with a clear initialization and main-loop flow. Execution starts at line 10 which jumps to line 30 (past the tape LOAD at line 20, which is only reached when re-run via SAVE "RubicCube" LINE 20). The high-level flow is:

  1. Lines 30–110: Screen setup and data initialization (border/paper/ink, cube state array, coordinate table, shape arrays)
  2. Lines 120–160: Display instructions and enter main loop
  3. Lines 170–340: Option menu (fresh cube, unscramble, save to tape)
  4. Lines 350–700: Initialization subroutine — builds a$(), u(), b$(), d() arrays from DATA
  5. Lines 710–790: Full cube redraw subroutine
  6. Lines 800–910: Partial redraw subroutine (affected faces only)
  7. Lines 920–1010: Main keypress dispatch loop
  8. Lines 1020–1140: Counter-clockwise rotation (key “r”)
  9. Lines 1150–1270: Clockwise rotation (key “t”)
  10. Lines 1280–1320: Keypress wait routine (flush then wait)
  11. Lines 1330–1390: Copy current edge cubies into c$() buffer
  12. Lines 1400–1490: Face selection display
  13. Lines 1500–1560: Highlight selected face center (XOR overlay)
  14. Lines 1570–1630: Start menu (play/scramble/load)
  15. Lines 1640–1730: Scramble routine
  16. Lines 1740–1800: Load cube from tape
  17. Lines 1810–1850: Move history recorder
  18. Lines 1860–1990: Unscramble playback engine
  19. Lines 2000–2010: SAVE commands for program and machine code

Data Representation

The cube state is stored in a$(6,14), a 6×14 string array. Each row represents one face; columns 1–9 hold single-character strings encoding the color (as a digit 2–7, matching INK values) of each cubie on that face. Columns 10–14 hold adjacency face indices used during rotation to identify which neighboring faces are affected.

The screen coordinates for all 54 visible cubie positions are stored in u(54,2), a numeric array populated from DATA at lines 510–560. Each entry gives the PRINT AT row and column for that cubie’s top-left corner. Cubies are displayed as 2×2 character blocks using UDGs defined in the machine code file.

The d(4,3) array (lines 660–680) maps, for each of the four edge groups around a face, the three cubie positions within the adjacent face that are affected by a rotation.

Machine Code Usage

Line 20 loads a machine code block named "rubiccubeC" to address USR "a", which is the base address of the UDG table (character 144). This installs custom 2×2 cubie graphics (UDGs \a through \p at minimum) used in b$(). Line 2010 saves this block back to tape. The BASIC program itself never calls USR as a function; the machine code is purely graphical data, not executable subroutines.

UDG and Display Technique

Each cubie face is rendered as a 2×2 block of UDG characters. The four UDGs per shape variant are stored in b$(6,4) at lines 580–640. Faces 1 and 3 share b$(1) (UDGs \a\b\c\d), faces 2 and 4 share b$(2) (UDGs \i\j\k\l), and faces 5 and 6 share b$(5) (UDGs \e\f\g\h), reflecting the three visible orientations of the isometric cube projection.

The selected face is highlighted using OVER 1 (XOR mode) at lines 1520–1540 and 1460–1470, printing UDGs \m\n\o\p over the center cubie to create a highlight effect without permanently altering the cell colors. The same technique clears the highlight by reprinting in the same mode.

Rotation Algorithm

Both rotation subroutines (lines 1020 and 1150) follow the same pattern:

  1. Call line 1810 to record the move in m$
  2. Call line 1330 to snapshot the eight edge cubies of the four adjacent faces into c$(4,3)
  3. Rotate the face’s own nine cubies in a$(k, TO 8) by string-slicing and reassignment (lines 1040–1050 for CCW, 1170–1180 for CW)
  4. Cycle the edge cubie colors around the four adjacent faces using the offset index x (±1 mod 4)
  5. Redraw only the affected cubies via line 800 (skipped when hide=1 during scrambling)

The face ring rotation for CW (line 1090) uses x=s+1 cycling 1→2→3→4→1, and CCW (line 1200) uses x=s-1 cycling 4→3→2→1→4.

Move History and Unscramble

The move history is recorded in the string variable m$. Each move is prepended (not appended) as a two-character sequence: face number (as a digit) and move type (“r” or “t”). Line 1820 implements compression: if the same face is turned again in the same direction, the previous record is consumed rather than duplicated — this is a partial move-cancellation optimization. The unscramble routine at line 1860 reads moves from the front of m$ and plays back the opposite rotation, stepping through the history in reverse order. During playback, pressing “h” halts and “r” returns control immediately.

Key BASIC Idioms

  • SGN PI is used throughout as a constant value of 1 (since SGN(3.14159…) = 1), avoiding the storage of a numeric literal in FOR loop initializers — a common Sinclair BASIC memory-saving idiom.
  • PI TO 4 used as a slice index evaluates to 3 TO 4 since PI truncates to 3 in integer slice contexts.
  • VAL a$(f,e) converts a single stored digit character back to a number for use as an INK color or array index.
  • STR$ (c+1) is used to store numeric values as single characters in string arrays.
  • The keypress routine at lines 1280–1320 uses the standard flush-then-wait pattern: spin while INKEY$ is non-empty, then spin while empty, ensuring a clean single keypress.

Notable Anomaly: Variable Name Collision

Lines 740, 840, and 880 use u(Z,2) with capital Z in the second coordinate lookup, while the loop variable is lowercase z. In Sinclair BASIC, variable names are case-sensitive for string variables but numeric variable names are single letters and case is normalized — both z and Z refer to the same variable. This is not a bug but may appear confusing.

Line 1190/1210 Redundancy

In the clockwise rotation subroutine, line 1190 declares FOR t=SGN PI TO 3 but this loop variable t is immediately re-declared at line 1210 with FOR t=SGN PI TO 3 again inside the FOR s loop. The first FOR t at line 1190 is effectively dead code — it sets up a loop that is never iterated because line 1200’s IF x=0 assignment and line 1210’s re-declaration supersede it. This appears to be a copy-paste artifact from the CCW routine structure at lines 1190–1210 and does not affect correctness.

Scramble and Tape Storage

The scramble routine (lines 1640–1730) performs 7 random face rotations with hide=1 to suppress screen updates during computation, then redraws the full cube at the end. Tape save (lines 280–320) stores the move history in a temporary g$() array and the cube state in a$() as two separate named SAVE operations. Loading (lines 1740–1800) reverses this, restoring both arrays.

Content

Appears On

Library tape of the Indiana Sinclair Timex User’s Group.

Related Products

Related Articles

Related Content

Image Gallery

RubicCube

Source Code

   10 GO TO 30
   20 LOAD "rubiccubeC"CODE USR "a"
   30 BORDER 6: PAPER 0: INK 9: BRIGHT 1
   40 CLS 
   50 PRINT AT 16,2; INK 6;"  *** ACME GLASS CUBE ***"
   60 PRINT INK 5;"** GENUINE SIMULATED PLASTIC **"
   70 PRINT INK 4;"     *** DO NOT DROP! ***"
   80 GO SUB 350
   90 GO SUB 710
  100 GO SUB 1570
  110 INK 9: PAPER 1
  120 PRINT AT 16,0;"   Press Colour Key To Select   "
  130 PRINT "  Face- Then Press Key T Or R   "
  140 PRINT " To Turn Clockwise Or Otherwise "
  150 FLASH 0: PAPER 0
  160 GO TO 920
  170 GO TO 350
  180 PRINT AT 16,0; PAPER 6;" Press f For A Fresh Cube"," Press u To Unscramble This One  Press t To Store It On Tape",
  190 PRINT ,,
  200 GO SUB 1280
  210 IF k$="f" THEN RUN 
  220 IF k$="u" THEN GO SUB 250: GO SUB 1860: GO TO 100
  230 IF k$="t" THEN GO TO 280
  240 BEEP .5,-40: GO TO 200
  250 PRINT AT 16,0,,"    Hold Down H To Halt Action   "
  260 PRINT "   Or Hold R To Regain Control  ",,
  270 RETURN 
  280 INPUT "Name Of Cube?";n$
  290 IF n$="" THEN LET n$="no name"
  300 DIM g$(LEN m$): LET g$()=m$
  310 SAVE n$ DATA g$(): SAVE "array" DATA a$()
  320 DIM g$(1)
  330 IF k<>0 THEN LET k$=STR$ (VAL m$(1)+1): GO SUB 1400: GO TO 920
  340 GO TO 100
  350 DIM a$(6,14)
  360 FOR e=SGN PI TO 9
  370 FOR c=SGN PI TO 6
  380 LET a$(c,e)=STR$ (c+1)
  390 NEXT c
  400 NEXT e
  410 FOR f=SGN PI TO 6: FOR e=10 TO 14
  420 READ aa: LET a$(f,e)=STR$ aa
  430 NEXT e: NEXT f
  440 DATA 2,3,4,5,6,3,1,5,6,4,1,2,6,4,5,6,5,1,3,2,4,6,2,1,6,5,4,3,2,1
  450 DIM u(54,2)
  460 FOR e=SGN PI TO 54
  470 FOR f=SGN PI TO 2
  480 READ u(e,f)
  490 BEEP .008,e
  500 NEXT f: NEXT e
  510 DATA 7,8,6,10,5,12,7,12,9,12,10,10,11,8,9,8,8,10
  520 DATA 1,7,2,9,3,11,4,9,5,7,4,5,3,3,2,5,3,7
  530 DATA 7,18,5,18,3,18,2,20,1,22,3,22,5,22,6,20,4,20
  540 DATA 7,23,8,25,9,27,10,25,11,23,10,21,9,19,8,21,9,23
  550 DATA 11,6,10,4,9,2,7,2,5,2,6,4,7,6,9,6,8,4
  560 DATA 3,28,5,28,7,28,6,26,5,24,3,24,1,24,2,26,4,26
  570 REM *** cubie shape arrays ***
  580 DIM b$(6,4)
  590 LET b$(1)="\a\b\c\d"
  600 LET b$(2)="\i\j\k\l"
  610 LET b$(PI)=b$(1)
  620 LET b$(4)=b$(2)
  630 LET b$(5)="\e\f\g\h"
  640 LET b$(6)=b$(5)
  650 DIM d$(8): DIM c$(4,PI): DIM d(4,PI)
  660 FOR s=SGN PI TO 4: FOR t=SGN PI TO PI: READ d(s,t)
  670 NEXT t: NEXT s
  680 DATA 5,4,3,3,2,1,7,6,5,1,8,7
  690 LET k=0: LET m$="": LET hide=k
  700 RETURN 
  710 FOR f=SGN PI TO 6
  720 FOR e=SGN PI TO 9
  730 LET z=e+9*f-9: INK VAL a$(f,e)
  740 PRINT AT u(z,1),u(Z,2);b$(f, TO 2): PRINT AT u(z,1)+1,u(z,2);b$(f,PI TO 4)
  750 BEEP .006,f*e
  760 NEXT e
  770 NEXT f
  780 INK 9
  790 RETURN 
  800 FOR e=o TO p STEP y
  810 LET f=VAL a$(k,e+9)
  820 FOR c=m TO n STEP y
  830 LET z=f*9-9+d(e,c): INK VAL a$(f,d(e,c))
  840 PRINT AT u(z,1),u(Z,2);b$(f, TO 2): PRINT AT u(z,1)+1,u(z,2);b$(f,PI TO 4): BEEP .004,z
  850 NEXT c: NEXT e
  860 FOR p=v TO w STEP y
  870 LET z=k*9-9+p: LET f=k: INK VAL a$(k,p)
  880 PRINT AT u(z,1),u(Z,2);b$(f, TO 2): PRINT AT u(z,1)+1,u(z,2);b$(f,PI TO 4): BEEP .004,z
  890 NEXT p
  900 INK 9
  910 RETURN 
  920 GO SUB 1280
  930 IF k$="q" THEN GO TO 180
  940 IF k$="t" AND k<>0 THEN GO SUB 1150: GO TO 920
  950 IF k$="r" AND k<>0 THEN GO SUB 1020: GO TO 920
  960 IF k$<"2" OR k$>"7" THEN BEEP .5,-40: GO TO 920
  970 GO SUB 1400
  980 IF k<>0 THEN GO SUB 1500
  990 LET k=VAL k$-1
 1000 GO SUB 1500
 1010 GO TO 920
 1020 GO SUB 1810
 1030 GO SUB 1330
 1040 LET a$(k, TO 6)=d$(PI TO 8)
 1050 LET a$(k,7 TO 8)=d$( TO 2)
 1060 FOR s=SGN PI TO 4
 1070 LET g=VAL a$(k,s+9): LET x=s+1: IF x=5 THEN LET x=1
 1080 FOR t=SGN PI TO PI
 1090 LET a$(g,d(s,t))=c$(x,t)
 1100 NEXT t: NEXT s
 1110 IF hide=1 THEN RETURN 
 1120 LET v=8: LET w=1: LET o=4: LET p=w: LET m=3: LET n=w: LET y=-w
 1130 GO SUB 800
 1140 RETURN 
 1150 GO SUB 1810
 1160 GO SUB 1330
 1170 LET a$(k,1 TO 2)=d$(7 TO 8)
 1180 LET a$(k,PI TO 8)=d$(1 TO 6)
 1190 FOR s=SGN PI TO 4: FOR t=SGN PI TO 3
 1200 LET g=VAL a$(k,s+9): LET x=s-1: IF x=0 THEN LET x=4
 1210 FOR t=SGN PI TO 3
 1220 LET a$(g,d(s,t))=c$(x,t)
 1230 NEXT t: NEXT s
 1240 IF hide=1 THEN RETURN 
 1250 LET v=1: LET w=8: LET o=v: LET p=4: LET m=v: LET n=3: LET y=v
 1260 GO SUB 800
 1270 RETURN 
 1280 IF INKEY$<>"" THEN GO TO 1280
 1290 IF INKEY$="" THEN GO TO 1290
 1300 LET k$=INKEY$
 1310 BEEP .05,40
 1320 RETURN 
 1330 LET d$=a$(k, TO 8)
 1340 FOR s=SGN PI TO 4
 1350 LET g=VAL a$(k,s+9)
 1360 FOR t=SGN PI TO 3
 1370 LET c$(s,t)=a$(g,d(s,t))
 1380 NEXT t: NEXT s
 1390 RETURN 
 1400 PRINT AT 14,0,,,,,,,,
 1410 PAPER VAL k$
 1420 PRINT "Colour Of Central Cubie Selects "
 1430 PRINT "Face For Rotation, R Or T Rotate"
 1440 PRINT "     Press Q For New Cube       "
 1450 PRINT AT 12,14;"FACE": PRINT AT 14,15; PAPER 0; INK VAL k$;b$(VAL k$-1,1 TO 2);TAB 15;b$(VAL k$-1,3 TO 4)
 1460 INK 8: PAPER 8: OVER 1
 1470 PRINT AT 14,15;"\m\n";TAB 15;"\o\p"
 1480 OVER 0: INK 9: PAPER 0
 1490 RETURN 
 1500 IF k=0 THEN RETURN 
 1510 LET qb=u(k*9,1): LET qb1=u(k*9,2)
 1520 INK 8: PAPER 8: OVER 1
 1530 PRINT AT qb,qb1;"\m\n"
 1540 PRINT AT qb+1,qb1;"\o\p"
 1550 INK 9: OVER 0: PAPER 0
 1560 RETURN 
 1570 PRINT AT 16,0; PAPER 2;" Press c To Play With This Cube  Press s To Scramble It First    Press t To Load One From Tape  "
 1580 GO SUB 1980: GO SUB 1500: LET k=0
 1590 GO SUB 1280
 1600 IF k$="c" THEN RETURN 
 1610 IF k$="s" THEN GO TO 1640
 1620 IF k$="t" THEN GO TO 1740
 1630 BEEP .5,-40: GO TO 1590
 1640 LET hide=1
 1650 FOR e=SGN PI TO 7
 1660 LET k=INT (RND*6)+1
 1670 LET k$="r"
 1680 IF RND>.5 THEN LET k$="t"
 1690 IF k$="r" THEN GO SUB 1020
 1700 IF k$="t" THEN GO SUB 1150
 1710 BEEP .05,e*5
 1720 NEXT e
 1730 GO SUB 710: LET k=0: LET hide=k: RETURN 
 1740 INPUT "Name Of Cube?";n$
 1750 PRINT AT 20,0;"        Start The Tape          "
 1760 LOAD n$ DATA g$(): LOAD "array" DATA a$()
 1770 LET m$=g$()
 1780 DIM g$(1)
 1790 CLS : GO SUB 710
 1800 RETURN 
 1810 IF m$="" THEN GO TO 1830
 1820 IF k=VAL m$(1) AND k$<>m$(2) THEN LET m$=m$(3 TO ): RETURN 
 1830 LET m$=k$+m$
 1840 LET m$=STR$ k+m$
 1850 RETURN 
 1860 IF m$="" THEN RUN 
 1870 GO SUB 1500
 1880 LET k=VAL m$(1)
 1890 LET k$=STR$ (k+1): LET t$=m$(2)
 1900 LET m$=m$(PI TO )
 1910 GO SUB 1450: GO SUB 1500
 1920 IF t$="t" THEN GO SUB 1030
 1930 IF t$="r" THEN GO SUB 1160
 1940 IF INKEY$="h" THEN GO TO 1940
 1950 IF INKEY$="r" THEN RETURN 
 1960 IF m$<>"" THEN GO TO 1870
 1970 GO SUB 1500: LET k=0
 1980 PRINT AT 12,14; PAPER 0;"    ": PRINT AT 14,15;"  ";TAB 15;"  "
 1990 RETURN 
 2000 SAVE "RubicCube" LINE 20
 2010 SAVE "rubiccubeC"CODE USR "a",168

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top