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

Published 21 hours ago
StatusReleased
AuthorBASIC 10Liner
GenreStrategy
Tags10liner, 8-Bit, atari, basic

Download

Download
B2048.BAS 1.3 kB
Download
B2048.LST 781 bytes
Download
B2048.LST.TXT 781 bytes
Download
README 2048.txt 19 kB
Download
2048.atr 90 kB

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