Tetris, without levels and next piece hint. Controls are as follows: O - move left P - move right Q - rotate counter-clockwise S - rotate clockwise SPACE - hard drop Scoring table: Soft drop: 1 point per row Hard drop: 2 points per row single row elimination: 100 points double row elimination: 300 points triple row elimination: 600 points tetris: 1000 points I recommend running it in fuse emulator. http://fuse-emulator.sourceforge.net/ From the command line, you can type fuse tetris.tap to run, but if you start fuse from GUI, you click Media > Tape > Open, select tetris.tap. Then you press J in the emulator (types LOAD) and Alt+P (types quotation mark) twice and hit ENTER. Note, that the program starts at line 30, that is the command to start it is RUN 30 (press R, type 30 and hit ENTER), if you type it in. The code: 10 LET k=y-3+(y=3): LET l=y+2-(y>19): FOR n=k TO l: LET s$(n)=u$(n): NEXT n: LET s$(y,3*x-1)=CHR$ c: FOR n=s TO s+2: LET u=CODE y$(n)-98: LET v=CODE x$(n)-98: LET s$(y+i*u+j*v,3*(x+j*u-i*v)-1)=CHR$ c: NEXT n: PRINT AT k,0;: FOR n=k TO l: PRINT s$(n): NEXT n: RETURN 20 LET h=t$(y,x)="L": FOR n=s TO s+2: LET u=CODE y$(n)-98: LET v=CODE x$(n)-98: LET h=h OR t$(y+i*u+j*v,x+j*u-i*v)="L": NEXT n: RETURN 30 LET x$="acdaacaacabcabcabcccb": LET y$="bbbcbbabbbcbbccbaabcc": DIM t$(21,16): DIM u$(21,48): FOR n=20 TO 21: FOR m=1 TO 16: LET u=m=1 OR m=16 OR n-20: LET t$(n,m)=" L"(u+1): LET u$(n,m*3-2 TO m*3)=CHR$ 17+CHR$ (7-6*u)+t$(n,m): NEXT m: NEXT n: FOR n=1 TO 19: LET t$(n)=t$(20): LET u$(n)=u$(20): NEXT n: DIM s$(21,48): LET t=0 40 BRIGHT 0: PRINT AT 0,0;"Score: ";t: BRIGHT 1: FOR n=1 TO 21: PRINT u$(n): NEXT n: LET x=8: LET y=3: LET i=INT (3*RND)-1: LET j=(NOT ABS i)*(2*INT (2*RND)-1): LET s=1+3*INT (RND*7): LET c=1+INT (RND*6): GO SUB 20: IF h THEN BRIGHT 0: RUN 30 50 GO SUB 10: LET k$=INKEY$: LET k=(k$="s")-(k$="q"): IF k AND (s<>1 OR (x>2 AND x<14)) THEN LET l=k*i: LET i=k*j: LET j=-l: GO SUB 20: IF h THEN LET l=k*j: LET j=k*i: LET i=-l 60 LET x=x+(k$="p")-(k$="o"): GO SUB 20: IF h THEN LET x=x-(k$="p")+(k$="o") 70 LET y=y+1: GO SUB 20: IF h THEN LET y=y-1: LET t$(y,x)="L": LET z=3*x: LET u$(y,z-1 TO z)=CHR$ c+"L": FOR n=s TO s+2: LET u=CODE y$(n)-98: LET v=CODE x$(n)-98: LET r=y+i*u+j*v: LET z=x+j*u-i*v: LET t$(r,z)="L": LET u$(r,3*z-1 TO 3*z)=CHR$ c+"L": NEXT n: GO TO 90 80 LET t=t+1+(k$=" "): GO TO 50+20*(k$=" ") 90 LET u=100: LET m=20: FOR n=20 TO 1 STEP -1: LET t$(m)=t$(n): LET u$(m)=u$(n): LET v=t$(n)=t$(21): LET t=t+u*v: LET u=u+100*v: IF NOT v THEN LET m=m-1 100 NEXT n: FOR n=m TO 2 STEP -1: LET t$(n)=t$(1): LET u$(n)=u$(1): NEXT n: GO TO 40 Explanation: In order to understand the code, it is worth looking at an earlier version, with no scoring and no colors. It has the same structure, but reads easier. Differences will be explained below. 10 LET k=y-3+(y=3): LET l=y+2-(y>19): FOR n=k TO l: LET s$(n)=t$(n): NEXT n: LET s$(y,x)="#": FOR n=s TO s+2: LET u=CODE y$(n)-98: LET v=CODE x$(n)-98: LET s$(y+i*u+j*v,x+j*u-i*v)="#": NEXT n: PRINT AT k,0;: FOR n=k TO l: PRINT s$(n): NEXT n: RETURN 20 LET h=t$(y,x)="#": FOR n=s TO s+2: LET u=CODE y$(n)-98: LET v=CODE x$(n)-98: LET h=h OR t$(y+i*u+j*v,x+j*u-i*v)="#": NEXT n: RETURN 30 LET x$="acdaacaacabcabcabcccb": LET y$="bbbcbbabbbcbbccbaabcc": DIM t$(21,16): FOR n=1 TO 20: LET t$(n)="# #": NEXT n: LET t$(n)="################": DIM s$(21,16) 40 PRINT AT 1,0;: FOR n=1 TO 21: PRINT t$(n): NEXT n: LET x=8: LET y=3: LET i=INT (3*RND)-1: LET j=(NOT ABS i)*(2*INT (2*RND)-1): LET s=1+3*INT (RND*7): GO SUB 20: IF h THEN RUN 30 50 GO SUB 10: LET k$=INKEY$: LET k=(k$="s")-(k$="q"): IF k AND (s<>1 OR (x>2 AND x<14)) THEN LET l=k*i: LET i=k*j: LET j=-l: GO SUB 20: IF h THEN LET l=k*j: LET j=k*i: LET i=-l 60 LET x=x+(k$="p")-(k$="o"): GO SUB 20: IF h THEN LET x=x-(k$="p")+(k$="o") 70 LET y=y+1: GO SUB 20: IF h THEN LET y=y-1: LET t$(y,x)="#": FOR n=s TO s+2: LET u=CODE y$(n)-98: LET v=CODE x$(n)-98: LET t$(y+i*u+j*v,x+j*u-i*v)="#": NEXT n: GO TO 90 80 GO TO 50+20*(k$=" ") 90 LET m=20: FOR n=20 TO 1 STEP -1: LET t$(m)=t$(n): IF t$(n)<>t$(21) THEN LET m=m-1 100 NEXT n: FOR n=m TO 2 STEP -1: LET t$(n)=t$(1): NEXT n: GO TO 40 Lines 10 and 20 are subroutines. They are placed at the beginning of the program for speed, as GO SUB searches the program code in a linear fashion. Line 10 draws a domino centered on (x,y) with the unit vector (i,j) pointing the direction of rotation. The dominos' shape is encoded in strings x$ and y$, containing the offets from the center, with letters a..d encoding integers between -1 and +2, respectively. The current domino is pointed by variable s. Only 3 positions are encoded per domino, omitting the 0,0 offset. First, the relevant part of the playing field in t$() is copied into s$(), then the domino is drawn in s$ and then it is printed. This is to omit ugly flickering while drawing. Line 20 checks whether the domino would hit anything, returning the result in boolean variable h. Line 30 is the actual starting point of the program and it initializes all variables: x$ and y$ describe the shapes, t$() is the playing area, s$ is its copy with the falling domino added. Line 40 initializes the drop of a domino. It first draws the playing area, then places the domino at the top, in a random orientation. Note, that the orientations are not uniformly distributed, but all 4 orientations are possible. The actual probabilities are 1/3 for vertical orientations and 1/6 for horizontal ones. Then it picks a shape from a uniform distribution. If it would hit something in the initial position, the game is restarted. Line 50 draws the falling domino and reads the keyboard. If the keys pressed are for the rotations, it does the rotation, checks whether it'd hit anything, and undoes the rotation if it would. Line 60 does horizontal movement and undoes it, if it would hit anything. Line 70 does the vertical movement. If it would hit anything, the domino is fixed in array t$. The reason it does not simply call 10 for drawing the domino is that displaying it at this point would be ugly, as the falling piece is still visible from a hard drop. Line 80 checks, if SPACE was pressed and either executes a hard drop by looping to line 70 or continues with the soft drop at line 50, where the keyboard is read again. Line 90 eliminates rows that are full, whereas line 100 fills the top of the playing area with empty rows and loops to line 40 dropping a new shape. This is the basic play mechanics. The submitted version has added color and scoring. Score is kept in variable t and updated after each vertical movement in line 80 by 1 or 2 depending on whether we are in a soft or a hard drop. Line 90 updates the score for row eliminations, adding 100 to the increment for each row eliminated. The score is displayed in line 40. Colors are quite Spectrum-specific. A new array u$ was added for the colored version of the playing field, where each position consists of 3 bytes: 17 is the background color terminal control, followed by the color code and then either by a whitespace or a capital L. The array s$ copies the color version. The # sign was changed into capital L for aesthetic reasons. The color of the piece is stored in variable c, ranging between 1 and 6, so that it is never white (which is the background color) and never black (which does not look good).