ZX-81 CUBEMASTER
by Simon Lane
Your Computer, February 1982, page 16

The hours of tortuous twiddling are now behind you Cubemaster goes to the heart
of Rubik's riddle to produce an answer every time. Simon Lane's program dis-
plays on screen the current state of play and instructs you how to solve the 
cubic conundrum.

THE FORMULA for solving the cube which I have used in this program is relative-
ly simple compared with certain techniques, and solves the Rubik's problem in 
three steps. First, it completes the top side, then the next layer down, and 
finally the bottom side.

  For convenience, the computer always chooses the red side as the top side, 
which means the orange side is on the bottom. It would be possible to complete
any side first. The first task is to put the top-side edges in their correct 
positions and when the top-side corners are also correct, the side is complete.
For the middle layer all that needs to be done is to put the middle edges in 
their correct positions. Although this seems simple, it can be very time-
consuming as the position on the top side must not be destroyed.

  The  bottom  side  is  the  most  difficult to complete, since now the posi-
tions on the top side and the middle layer must be preserved. For that reason,
this part of the formula takes the most time to execute, and has to be reduced
to a number of simpler steps:

-Placing the bottom-side corners in their correct positions.
-Turning them so that they are facing the correct way.
-Adjusting the bottom-side edges so that they are all orange side down.
-Placing them in their correct positions.

 In the program itself, the formula appears as a large number of conditional
statements in the form: "If a certain position Then make this move."

FIGURE 1. Goes here.

  For this reason the program requires very simple methods both for storing the
position and making the moves. The position is stored in two six-by-six numeri-
cal arrays - E for the edge squares and C for the corner squares.

  Because they are numerical arrays, each of the colours has to be represented
by a  number, so 1 stands for red, 2 for blue, 3 for white, 4 for green, 5 for
yellow and 6 for orange. Each face is identified by the colour of the square in
its centre. So, for example, the side with a red square in its centre is side
number 1.

  Each edge square is identified by two coordinates. The first coordinate re-
presents the face it is on, and the second the face it is next to. For example,
if E(1,2) 6, then that would mean that the edge square on the red - which was 
next to the blue face - was coloured orange - see figure l.

  The corner squares  are identified using the same system, except that the
co-ordinates represent the position of the edge square to the left of - one
position anticlockwise - the corner square.  For example, if C(2,6)=6, then
that would mean that the corner square on the blue face - which was to the
right of the edge square next to the orange face - was coloured orange - see
figure 2.

  Since moves must be made in many different parts of the program, it is
obvious that you need a subroutine to tell the human what move to make, and to
change the internal representation of the cube every times a move has been
made. I have incorporated this in the program as subroutine 2000, and the move
is transferred to it in the string variable X$.

 I have used a string variable to save space, since it allows the  whole move 
to be defined in one line; if two numerical variables had been used, one for 
the side and one to indicate clockwise or anticlockwise, two lines would be
needed. Another subroutine is also required to execute a series of moves at the
same time. This appears in the program as subroutine 3120, and the moves are 
also transferred to it in a string variable, Z$, for the same reasons as 
before. The subroutine divides this string into the individual moves, and 
executes them by placing them one by one into X$ and calling subroutine 2000.

  To ensure that each move is as simple as possible for the person trying to
solve the  cube, only 12 different moves are used. They turn each of  the sides
either clockwise or anticlockwise through 90.

 Lines 10 to 410 are instructions, and lines 520 to 950 cover the initialisa-
tion of variables, and entry of the position. This is where the E and C arrays
are set up. Also the variables R,B,W,G,Y and O are given the values 1 to 6
respectively. This was designed to make the program clearer and to save the
user remembering which colour was represented by which number - whenever the
number of a colour occurred, it could be replaced by one of these variables.

  In the position-entering part of the program, line 620 onwards, subroutine
1000 is called to display a picture of four sides of the cube and then the 
colours of the eight squares around the centre square are entered. Lines 1000
to 1140 contain the subroutine to draw the cube. Lines 1005 and 1045 are con-
tained as a subroutine because they are used later by subroutine 2000.

FIGURE 2. Goes Here

 Here, the variables Top, Lef, Bot and Bac are set up for each side. I could
have used nested loops to replace lines 1050 onwards, which would have saved a
considerable amount of space, but I avoided them as they would have slowed down
the subroutine considerably. Lines 1150 to 1160 hold the subroutine to print a
colour.

 The colour stored in the variable Colour is printed. Note the peculiar use of
And in the Print statements. This is one of the useful idiosyncrasies of the
ZX-81. Another example is the use of Val in the previous subroutine. These fea-
tures increase the speed of the program and save space, but they make conver-
sion for any other dialects of Basic very difficult. Lines 1300 to 1600 contain
the subroutine to check the position. Lines 1310 to 1440 are the instructions
for using this part of the program.

  Inkey$ and Val are used in conjunction with subroutine 1000 to display dia-
grams of the sides chosen by the user. Lines 2000 to 2290 contain the sub-
routine at the heart of the program - it is called for the execution of every
move made. Lines 2002 to 2006 are necessary because of the fact that calls are
frequently made to the subroutine when it is not necessary for a move to be
made. The variable X$ is set to the null string in the line 2004 to avoid a
move being executed twice by mistake.

  Lines 2020 and 2075 transfer the information stored in X$ into two variables,
Sid, which has a value of 1 to 6 and represents the side to be turned, and X$
is changed to A or C to represent whether the move should be anticlockwise or
clockwise.

  Lines 2090 to 2114 are required while the program is trying to complete the
top side. If a move to the top side is made, the values of the front, right,
back and left sides will change. This is best understood if you consider turn-
ing the top side as turning the rest of the cube in the opposite direction. The
colours of the front, right, back and left sides will then change accordingly.

  Lines 2120 to 2215 control the printing of the move. Print Tab 31; statements
are used after Scroll statements to fill the display with spaces. If they were
omitted, CLS would be slowed down considerably, since it would have to lengthen
the display file again, moving up the part of the memory where the variables
are stored.

  Lines 2218 to 2290 execute the move in memory - that is, they change the int-
ernal representation of the cube. Subroutine 1005 is used to set the variables
Top, Bot, Lef, Bac and Rig. Then the painstaking process of moving each square
begins.

  Initialisation of variables is catered for in lines 2400 to 2500. This is the
start of the formula. The variable Move, which counts the number of moves made,
is set to Zero. X$ is set to the null string in case it is not set to anything
else before subroutine 2000 is called for the first lime. TS and TC, the top
side and the top colour, are set to 1 since they remain red throughout the pro-
gram, and US and UC are set to 6, orange, in the same way. Finally the front
side and the front colour - FS and FC - are set to 2, blue, as the computer
will start on the top edge next to the blue edge.

  Lines 2505 to 2900 deal with the top-side edges. Lines 2510 to 2570 test to
see if any of the top-side edges are already in their correct positions, and
ED, which counts the number of edge squares done, is set up. Subroutine 2589

FIGURE 3 Goes here.

is used several times during the program, as it works out the left, back and
right sides and colours from the front side and the front colour.  Lines 2640
to 2850 deal with the actual moves involved, and the rest of this section
controls looping back to the beginning of the section until all the top-side
edges have been done.

  Middle-layer edges are calculated in lines 3370 to 3680. At the beginning of
this section two variables are set up, R$ and L$. They are strings of moves
which are used extensively in this section in conjunction with subroutines
3120. Ml, the number of middle-layer edges in the correct position, is set up,
and if all the edges are correctly placed, a jump is made to line 3690. Other-
wise, the edges are put in their correct places by lines 3140 to 3680.

 By lines 8000 to 8090, the cube should be finish. If it is not, it is not 
because of computer error, but human error. This program can solve the cube
from any position which can be reached without dismantling the cube. First you
are asked to type Newline so that the screen will not be cleared before you
have done the last move. It then gives you the chance of trying the program
again by typing Newline. Otherwise the program has finished.

  The shortage of memory on the ZX81  has forced me to omit the full range of
error checking routines which could be provided. If you accidentally enter the
wrong colour when setting up the cube, the  program  will  crash and you will
have to start again. The only other problem you might face is that a number of
the pirate cubes on the market have their colours on different sides.

 To use this program on the 8K RAM ZX-80 requires a few minor alterations:

  240 PAUSE 4E4
  241 POKE 16437,255
  242 IF INKEY$<>"C" THEN GOTO 240
  410 PAUSE 4E4
  411 POKE 16437,255
  412 IF INKEY$<>"S" THEN GOTO 410
  795 PAUSE 4E4
  797 POKE 16437,255
   DELETE 800
  805 IF X$="" THEN GOTO 795
 1450 PAUSE 4E4
 1451 POKE 16437,255
 1452 LET K$=INKEY$
 2125 PAUSE 4E4
 2126 POKE 16437,255
 2140 IF K$<>"H" AND K$<>CHR$ 118 THEN GOTO 2125
 8010 PAUSE 4E4
 8011 POKE 16437,255
 8O12 IF INKEY$<>CHR$ 118 THEN GOTO 8010
 8075 PAUSE 4E4
 8076 POKE 16437,255
 8090 GOTO 8075

 Conversion for any other machine would be very difficult, because of the 
extensive use of Val throughout the program since on the ZX-81, Val may be used
to evaluate variables as well as numbers.

Table 1.  The program variables.

  Variables used in the first half of the program - up to line 1600.

  E (6,6)   An array holding the edge squares.                       
  C (6,6)   An array holdiog the corner squares.                       
  I,J       Loop control variables.       
  C$        String containing the initials of the colours used in cube-
            drawing subroutine 1000.                
  R         Red, set to l.                  
  B         Blue, set to 2.                 
  W         White, set to 3.                
  G         Green, set to 4.                
  Y         Yellow, set to 5.               
  O         Orange, set to 6.               
  S         The side being entered.         
  COLOUR    The colour to be printed by subroutine 1150.                
  D         Line number for Print At expression.                     
  A         Column number for Print At expression.                     
  SID       The side next to the square being entered.                         
  X$        The key being typed, used during the position entering section    
  C         The number of the square being entered.                         
  TOP       Top side                         
  LEF       Left side                        
  RIG       Right side                       
  BOT       Bottom side                     
  BAC       Back side                      
  K$        The key being typed in subroutine 1300, the position checking subroutine.

  Variables used in the second half of the program - line 2000 onwards

  X$        The move to be made by subroutine 2000. Used in subroutine 2000 to
            show whether the move is clockwise or anticlockwise.
  SID       The side to be returned in subroutine 2000.
  XX        Dummy variable used to hold the temporary value of colours during
            the execution of a move.
  FS        Front side.
  LS        Left side.
  BS        Back side,
  RS        Right side.
  TS        Top side.
  US        Under side.
  FC        Front colour.
  LC        Left colour.
  BC        Back colour.
  RC        Right colour.
  TC        Top colour.
  UC        Under colour.
  MOVE      The number of moves executed so far.
  K$        The key being typed in subroutine 2000.
  I.J K.L   Loop control variables.
  ED        The  number of top-side edges done so far.
  Z$        The string of moves to be executed by subroutine 3120.
  CO        The number of top-side corners done so far.
  R$,L$     Strings of moves used to position the middle edges.
  M1        Number of middle edges done so.
  A$,B$     Strings of moves used to position the bottom-side corners.
  S$        Representation of two sides in the form of a string.
  S1,S2     The numerical equivalents of the sides stored in S$,
  X         Flag to indicate whether or not to loop back to line 3982 at line
            3963.
  R$,L$     Stings of moves used to position the bottom-side corners.
  FL        The number of corner squares or edge squares on the bottom-side
            which are orange.
  A$,B$     Strings of moves used to position the bottom-side edges. 
  R$,L$     
===============================================================================
CUBE CORRECTION
Your Computer, March 1982, page 15 Letters

  The Cubemaster program from February Your Computer is the longest software
listing I have yet seen for the ZX-81.  Unfortunately, a couple bugs crept in.

   Line 550 should read  LET C$="RBWGYO"

and in Iines 4280, 4290, 4300 and 4310 the space should be taken out five 
characters back from the edge of the listings, that is the LS,LS,US and US
should be closed up in the four lines.
                                                                Graham Mitchell
                                                                   Bromborough,
                                                                         Wirral
===============================================================================
Comments
                                                                             
As you can see this is a very long, complex program, I think I've found all  
the typo errors but given the nature of the program it is hard to test. I    
have used it to solve some simple cube configurations succesfully.           
                           
Unless I've missed something Line 550 still has a bug in it which is not the 
same as the correction noted above.  The only way I could get the program to 
run was by adding a space to C$ in the line 550 LET C$="RBWGYO ".  The space is
required because lines 545 and 546 initializes all the E(6,6) and C(6,6) array
elements to 7 and these array elements are then used to reference a character
position in C$, without the 7th "space" character the program quicky crashes
with error 3/1050, "Subscript out of range".

From a programming point of view this program shows how useful and powerful
Sinclair BASIC's VAL function and string slicing capabilities are.

                                                               Greg Harder 2017
===============================================================================