2048 (Atari 8 Bit) by D. Scott Williamson
A downloadable game
2048
By D. Scott Williamson
For the PUR-80 category of the 2025 BASIC 10 Liner contest
Table of contents:
Included Files Description
Startup & Emulator Instructions
Description
Rules
Winning the game
How to Play
Strategy
Program features
Grid
Movement and accumulation
Use of conditional expressions as integers (booleans)
Proof of 10 lines less than 256 columns
Program overview
Detailed program description
Included Files Description
README 2048.txt This file
2048.atr Floppy disk image containing DOS, B2048.BAS, and B2048.LST
B2048.BAS BASIC file that can be loaded with LOAD
B2048.LST BASIC Listing that can be loaded with ENTER
B2048.LST.TXT BASIC Listing with line endings converted to LF (Unix style) for PC editors
B2048 Listing.png Image of program listing
2048_80 Start.png Screenshot: Start of a game
2048_80 Gameplay 1.png Screenshot: Gameplay 1
2048_80 Gameplay 2.png Screenshot: Gameplay 2
2048_80 Win Theme.png Screenshot: Gameplay 3 Winning theme
Description
Rules
In the game 2048, you move the joystick to slide numbered tiles around on a 4x4 grid.
The goal is to combine tiles with the same number value to build larger numbers.
Winning the game
The goal is to reach the 2048 tile
When the 2048 tile is reached YOU WIN and the game color theme changes
You may continue playing beyond tile 2048 to reach higher scores and tiles with higher .powers!
How to play
Gameplay starts on an empty 4x4 grid with two randomly placed tiles, each with a value of 2 or 4 (2 is more common than 4)
When you move the joystick up, down, left, or right, all the tiles will slide in that direction.
If a tile slides into another tile with the same value they will combine into a single tile with double the value and the new value is added to your score.
After each move where tiles slide and/or combine, a new random 2 or 4 tile appears in an empty cell
The game ends when the board is full and you can't make any more moves
Strategy
Keep the largest number in a corner
Form the next largest number around it
Slide the number tiles to combine them
Program features
Grid
Movement and accumulation
It turns out that moving and combining tiles in 2048 complex task as there are some hidden rules
Tiles don't have to be adjacent to be combined (0's are skipped)
Tiles closer to the target edge are combined first
A tile combined in a turn cannot be combined again in the same turn
The rules apply in all 4 movement directions
Examples:
Consider moving to the right -->
All of these combinations of 4s will result in 0 0 0 8
0 0 4 4 -> 0 0 0 8
0 4 0 4 -> 0 0 0 8
4 0 0 4 -> 0 0 0 8
4 0 4 0 -> 0 0 0 8
4 4 0 0 -> 0 0 0 8
All of these combinations of 4s will result in 0 0 4 8
0 4 4 4 -> 0 0 4 8
4 4 0 4 -> 0 0 4 8
4 0 4 4 -> 0 0 4 8
4 4 4 0 -> 0 0 4 8
All of these combinations of numbered tiles will result in 0 0 8 8
4 4 4 4 -> 0 0 8 8
8 0 4 4 -> 0 0 8 8
8 4 0 4 -> 0 0 8 8
8 4 4 0 -> 0 0 8 8
0 4 4 8 -> 0 0 8 8
4 0 4 8 -> 0 0 8 8
4 4 0 8 -> 0 0 8 8
The tiles are represented in the program as a 4x4 grid held in a 16 element array of rows of 4 tiles in array Q.
A tile at X,Y can is indexed by X+Y*4, e.g. Q(X+Y*4)
To move tiles to the right we start at the right edge and scan left keeping track of the previous and current tile value
The previous tile is rightmost, closer to the right edge
The current tile is at some offset to the left of the previous tile and will be moving left
Zero value tiles are ignored or skipped (end of line 5 and line 6)
If the current and previous tiles have different values, the current tile is moved alongside the previous tile (line 7)
If the current tile and previous tile have the same value they are combined (line 8)
This logic needs to be applied in each direction so explicit loops are replaced with parametric values and exit conditions so the same code may operate in any of the 4 valid directions.
An index for grid processing loop parameters is looked up based on joystick input in line 4, only valid inputs result in valid indexes, all other inputs (diagonals, center) cause a loop back to line 4
The following variables are looked up from tables for each of the valid 4 input directions
S Start, the start index for processing, always at the target edge
For moving to the right it's the index of the rightmost element of the first row
D Delta, what to add to an index to move along a row or column away from the target edge
For moving to the right this is -1
E End, end value for processing a row or column
For moving right this is 0, or the left most element of the first row
R Delta to change rows/column, this is applied after each row/column to advance to the next row/column
For moving right, this is 4 to move to the same column in the next row
X Exit value, the row and column processing continues until this index is reached and grid processing is stopped
For moving right, this is 16, the first element of the row after the last row
In the loop, J is the index to the previous tile with value stored in P (rightmost when moving right), and is initialized to be the index of the rightmost tile on the first row on line 5
Current value index I FOR loops over the rest of the row on line 5 starting from J+D, which is the next tile away from the target edge, to E the end index incrementing by STEP D which increments away from the target edge. The current tile value at index I is stored in C
The end of line 5 then lines 6,7,and 8 apply the rules to the tiles as described above.
Line 9 finishes the row/column loop by NEXT I, then adds R to S to start the next row/column, adds R to E to define the end of the next row/column, and loops back to line 5 if E is not equal to X
Meaning the updated end index E is not equal to the exit index X.
When grid processing is done it loops back to line 1 for another turn e.g. table values for loop processing for a move right
Joystick value is 7
7-5 is index 2
Index from joystick table is 2
S Start value index 2 is 3, index for rightmost element of first row
D Delta value index 2 is -1, each row/column loop moves by -1
E End value index 2 is 0, stop row processing after processing 0
R Row value index 2 is 4, after processing a row/column, add R to the Start index and repeat, this moves to the next row/column
X Exit value index 2 is 16, which is the first element of the row after the last row
When the Start value for the next row is this value, grid processing is done
Use of conditional expressions as integers (booleans)
The result of a comparison (=,<,<=,>,>=,<>) is 1 if true and 0 if false.
This can be used to create conditional calculations in without using IF ... THEN.
This technique is used to validate input, and in GOTO statements to implement
IF .. THEN ... ELSE logic lacking in Atari BASIC
10 lines less than 80 columns (also see included "2048 Listing.png")
00000000011111111112222222222333333333344444444445555555555666666666677777777778 12345678901234567890123456789012345678901234567890123456789012345678901234567890 0DI.Q(99),S$(9):S$=" ":GR.18:F.I=0TO46:REA.X:Q(I)=X:N.I:G=2:W=1:SE.4,0,15 1IFG>0THENR=2+INT(RND(0)*1.1)*2:I=RND(0)*16:N=(Q(I)=0):Q(I)=Q(I)+N*R:G=G-N:G.1 2SE.0,W,4:SE.1,W,12:SE.2,W,8:SE.3,W+2,8:POS.0,0:?#6;"2°˜",,,," scoreº ";A,,, 3F.Y=0TO3:F.X=0TO3:N=Q(X+4*Y):D=5-LEN(STR$(N)):?#6;S$(1,D);N;:N.X:?#6:N.Y 4I=Q(11+STICK(0)):S=Q(27+I):D=Q(31+I):E=Q(35+I):R=Q(39+I):X=Q(43+I):G.4+(I<4) 5W=W-1:M=1024:POK.77,0:J=S:P=Q(J):F.I=J+D TO E STEP D:C=Q(I):IF(C=0)THENG.9 6IFP=0THENQ(J)=C:Q(I)=0:P=C:G=1:G.9:D.0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,2,4 7IF(P<>C)THENJ=J+D:Q(J)=C:Q(I)=C*(I=J):P=C:G=(G)OR(J<>I):G.9:D.4,4,1,4,3,0,4,0,0 8IF(P=C)THENT=P+C:Q(J)=T:A=A+T:J=J+D:Q(J)=0:Q(I)=0:P=0:G=1:W=10*((W)OR(T>M)) 9N.I:S=S+R:E=E+R:W=W+1:G.1+4*(E<>X):D.3,12,4,1,-1,-4,12,3,0,0,1,4,4,1,16,19,16,4
Program Overview:
Line 0 Initialization of variables and graphics
Line 1 Game loop, select and place random tiles
Line 2 Set colors, display game name and score
Line 4 Handle Joystick input
Line 5 Start the grid processing loop and reset hardware attract mode timer
Line 6 Handle moving a numbered tile onto an empty or zero tile location, data for initial grid and joystick lookup
Line 7 Handle moving different valued tiles next to each other, data for joystick lookup and some grid processing constants
Line 8 Handle combining same value tiles
Line 9 Finish grid loop processing, final Data for grid loop processing constants
Detailed program description:
Variables
A Score (initialized to 0 by the run command)
S$ Spaces for right justification of numbers
S Stick (14 up, 11 left, 7 right, 13 down)
S Start index for grid processing
E End index for grid processing
D Digit count in number for leading zeros calculation, also Delta index for grid processing
moves to next location in the grid based on joystick direction
R Delta start to next row
moves to the next column or row based on joystic direction
X Exit, tile index to stop grid processing
C Current tile value
P Previous tile value
G Generate tiles initially 2
only set t1 only if numbers moved or combined,
0 for moves that don't change the board
T temp
I loop index, temporary value
W Win flag, set to 1 normally then 10 once a 2048 tile is created
Q Array of game data read from DATA statements
Tables stored in Q
Ofs Len Description
========================================================================
0 16 Board (4x4)
Initial value: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
16 11 Table to convert joystick inputs to movement actions
Initial value: 4,4,2,4,4,4,1,4,3,0,4
Joystick direction values mapped to table indices
10 14 6 5 9 1
11 15 7 -5 => 6 10 2
9 13 5 4 8 0
Meaning, when STICK-5 is used to index the table, the values have the following meanings
0 Up
1 Left
2 Right
3 Down
4 No action (either center or any diagonal)
27 4 Start index for grid processing (S) based on joystick action
Initial value: 0,0,3,12
0 Upper left corner
3 Upper right corner
12 Lower left corner
31 4 Delta index for grid processing (D) based on joystick action
Initial value: 4,1,-1,-4
1 Move 1 column to the right
-1 Move 1 column to the left
4 Move one row down
-4 Move one row up
35 4 End index for grid processing (E) based on joystick action
Initial value: 12,3,0,0
0 Upper left corner
3 Upper right corner
12 Lower left corner
39 4 Delta start to next row (R) based on joystick action
Initial value: 1,4,4,1
1 Move one column to the right
4 Move one row down
43 4 Exit, tile index to stop grid processing (X) based on joystick action
Initial value: 16,19,16,4
These values are logically outside the 4x4 grid
4 5th element in the first row
16 5th element of the last row
19 4th element of the 5th row
Expanded listing (one instruction per line, abbreviations expanded, functional description)
Line 0 Initialization of variables and graphics
DIM Q(99),S$(9) Dimension Q data array and S$ spaces string
S$=" " Set Spaces string to 4 spaces for right justification of numbers
GRAPHICS 18 Graphics mode 2 large text +16 with no high resolution text window
FOR I=0 TO 46 Loop I to read the data from data statements into Q array
READ X Read X from DATA statement
Q(I)=X Store X in Q at index I
NEXT I Loop
G=2 Set G=2 to generate 2 random tiles at the start of the game
W=1 Set W=1 to indicate player has not yet won by reaching 2048
SETCOLOR 4,0,15 Set background to white
Line 1 Game loop, select and place random tiles
IF G>0 THEN If we need to generate random tiles
R=2+INT(RND(0)*1.1)*2 Generate a random value either 2 or 4 (4 has a 1 in 1.1 chance of being generated)
I=RND(0)*16 Pick random index, a location in the 4x4 grid
N=(Q(I)=0) N=1 if the destination location is zero
Q(I)=Q(I)+N*R Set the destination to the existing location plus N*R
This preserves any non zero number in the grid,
and will place a random value over a zero
G=G-N G=G-N will reduce the number of random tiles needed only if
a blank random location was chosen
GOTO 1 Loop until all needed random tiles have been generated
(loops forever when the game is over)
Line 2 Set colors, display game name and score
SETCOLOR 0,W,4 Dark Orange
SETCOLOR 1,W,12 Yellow
SETCOLOR 2,W,8 Orange
SETCOLOR 3,W+2,8 Purply red
POSITION 0,0 Position cursor in upper left corner of screen
PRINT #6;"2°˜",,,," scoreº ";A,,,
Print "2048" in 4 colored letters in upper left corner of the screen
Number colors are selected by printing numbers or corresponding control caracters in normal and inverted text.
The four comas are a quick way to print a blank line
The word Score is printed in a chosen color and the color in another color with the same trick to color text as the numbers used.
The actual score is printed followed by three comas to place the cursor to print the grid of numbers
Line 3 Display the grid of numbers
FOR Y=0 TO 3 Loop Y through 4 rows 0 through 3
FOR X=0 TO 3 Loop X through 4 columns 0 through 3
N=Q(X+4*Y) N is the number from the array indexed by X+4*Y (two dimensional array index)
D=5-LEN(STR$(N)) D is the number of leading spaces needed including number separation in the grid
PRINT #6;S$(1,D);N; Print leading spaces followed by number
NEXT X Next X, column loop
PRINT #6 Print blank line to space out grid
NEXT Y Next Y, row loop
Line 4 Handle Joystick input
I=Q(11+STICK(0)) Read stick value, and index table at 11
The stick value table starts at 16 but the lowest stick value is 5 so we index at 16-5=11
This lookup will return 0,1,2,3 for valid directions, 4 otherwise
S=Q(27+I) Read the starting index for sliding tile processing
D=Q(31+I) Read the delta for indexing the next tile during sliding tile processing
E=Q(35+I) Read the ending index for sliding tile processing (the end of a row or column)
R=Q(39+I) Read the next row (or column) delta for sliding tile processing
X=Q(43+I) Read the ending index that will end sliding tile processing
G.4+(I<4) GOTO 4 (this line) line 4 if the stick input was not a valid direction
GOTO 5 (next line) if the stick input value was less than 4
Line 5 Start the grid processing loop and reset hardware attract mode timer
W=W-1 Decrease the win flag. If it was 1 then it is 0, if it was 11, then it is 10
M=1024 Set the winning threshold, a tile value above this will win
POKE 77,0 Reset the Atari attract mode timer to prevent unwanted color cycling
J=S J the start index for grid processing
P=Q(J) P the previous value is initialized to the value at the start index
FOR I=J+D TO E STEP D Loop from the second element (J+D) to the end element in a row or column
by increments of delta D
This allows the same loop to apply the same rules to move and combine tiles
in any direction: up, down, left, or right.
C=Q(I) C, the Current value is read from index I
IF (C=0) THEN If the current value is 0 it does not need to move,
GOTO 9 GOTO line 9, end of processing loop
Line 6 Handle moving a numbered tile onto an empty or zero tile location, data for initial grid and joystick lookup
IF P=0 THEN The current tile is non-zero and the previous tile was 0
So we need to move the current tile to the previous tile location
Q(J)=C Set the value of the previous tile (index J) to the current value C
Q(I)=0 Set the value of the current tile to 0 since it has been moved
P=C Set the previous value to C
G=1 At least one tile moved so we need to generate a new tile
GOTO 9 GOTO line 9, end of processing loop
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,2,4
This data contains the initial playfield and some of the joystick table
Line 7 Handle moving different valued tiles next to each other, data for joystick lookup and some grid processing constants
IF (P<>C) THEN The current and previous tile values are non-zero and different
So move the current value to the next index after the previous tile
This may copy a tile on top of itself but that doesn't have negative impact
J=J+D Advance previous index J by delta D
Q(J)=C Set the new previous value at index J to current value C
Q(I)=C*(I=J) Set the Current value at index I to current value C or zero
if index I not equal to previous index J
P=C Set previous value to the current value
G=(G)OR(J<>I) Generate a tile if a tile moved which only happens if index I is not equal to index J
GOTO 9 GOTO line 9, end of processing loop
DATA 4,4,1,4,3,0,4,0,0 Data containing the rest of the joystick table and some grid processing constants
Line 8 Handle combining same value tiles
IF (P=C) THEN The current and previous tiles are non-zero and have the same value! Combine them!
T=P+C Temp T = P+C which is double either P or C as they are the same
Q(J)=T Set the previous location at index J to the sum in T
A=A+T Add the sum T to the player score
J=J+D Advance the previous index J by delta D
Q(J)=0 Set new previous index J to 0 - this handles the case where the tiles are adjacent
Q(I)=0 Set current index I to 0 - this handles the case where a tile slid through a blank space
P=0 Previous value is set to 0 to prevent over-combining in future loops
G=1 Tiles were combined so a new tile needs to be generated.
W=10*((W)OR(T>M)) Set the win mode to 10 if W was already nonzero or if the sum in T is greater than the max in M
Line 9 Finish grid loop processing, final Data for grid loop processing constants
NEXT I Next iteration along row or column
S=S+R Start index S is advanced by the delta to the next row (or column based on the move direction)
E=E+R End E index for row or column advanced by the delta to the next row R
W=W+1 Win value is incremented so it is either 1 or 11 as needed by SETCOLOR commands
G.1+4*(E<>X) If end index E is equal to exit index X for loop processing then GOTO line 1
If end index E is not equal to exit index X then GOTO line 5 to process the next row or column
DATA 3,12,4,1,-1,-4,12,3,0,0,1,4,4,1,16,19,16,4 Data containing grid processing constants
Download
Install instructions
Startup & Emulator Instructions
1. Run Atari800Win PLus
2. Set Machine Type to XL/XE
3. Set Video System to NTSC (not strictly necessary)
4. Make sure BASIC is enabled ("Disable BASIC when booting" is disabled in settings
4. Alt-D or drag and drop to attach "2048.atr" to the emulator
5. Shift-F5 to reset the emulator which will now be in BASIC at the READY prompt with the disk loaded in D1:
6. Type ENTER"D1:B2048.LST" and press enter to load the program (alternate LOAD"D1:B2048.BAS")
7. (optional) type "LIST" to see listing
8. type "RUN" to run the program
Comments
Log in with itch.io to leave a comment.
very good