A downloadable game

Wordle

By D. Scott Williamson

For the PUR-80 category of the 2025 BASIC 10 Liner contest

(Warning, spoilers below!)


Table of contents:

Included Files

Startup & Emulator Instructions

Description

Rules

How to Play

Cards

Gameplay Instructions

Strategy

Program features

Dictionary (Warning, spoilers)

Data Compression 

Redundancy

Bit Packing

Representation in the program

Decompression (Lines 3,4)

Creation of the dictionary

Compression script

Encoding

Verification

Audio Visuals

Font & colors

Sound

Input method

Use of conditional expressions as integers (booleans)

Proof of 10 lines less than 256 columns

Program overview

Detailed program description


Included Files 

README Wordle.txt This file

WORDLE.ATR Floppy disk image containing DOS, WORDLE.BAS, and WORDLE.LST

WORDLE.BAS BASIC file that can be loaded with LOAD

WORDLE.LST BASIC Listing that can be loaded with ENTER

WORDLE.LST.TXT BASIC Listing with line endings converted to LF (Unix style) for PC editors

WORDLE Listing.png Image of program listing

WORDLE1.png Screenshot of initial game screen

WORDLE2.png Screenshot during gameplay

WORDLE3.png Screenshot of winning game


Description

Rules

The objective of the game is to guess a secret 5 letter word.  

The player takes up to 6 turns, each turn the player enters 5 letters.

At the end of each turn the color of each tile will change to show you how close the guess was.

* If the tile turns green, the letter is in the word, and it is in the correct spot.

* If the tile turns yellow, the letter is in the word, but it is not in the correct spot.

* If the tile remains gray, the letter is not in the word.

At the end of the game a win or loss sound is played, the secret word is displayed at the top of the screen for 1 turn, and a new game is started.

The secret word will not be a proper noun, a place name, a plural, or a past tense of a word.


How to play

This version of the popular WORDLE word game is true to the original and features a compressed 46 word dictionary in only 10 lines of 80 characters.  

Which words?  You'll have to play to find out!  

You'll be able to play for a long time before likely to see a repeated word!

Press letter keys (A-Z) on the keyboard to input letters


Program features

Dictionary (Warning, spoilers)

Implementing a dictionary was the greatest challenge of this game.  I made sure to use a source dictionary of 2310 legitimate Wordle words and worked to select and compress as many of those words as possible in ways that are easy to index and decompress in Atari BASIC.  In earlier versions of the game I had as many as 71 words in the dictionary but had to reduce the word count to 46 in order to display the secret word at the end of the game.

Data Compression 

Redundancy and bit packing are used to compress the dictionary to the point where each 5 letter word is packed into two bytes except the last word which requires (half of) one additional byte.  

Redundancy: Game dictionary words were selected such that the first letter of each word is the same as the last letter of the previous so words overlap by one letter.  I explored overlaps of 2,3, and even 4 letters but there were not enough overlapping 5 letter words to make a sizeable dictionary.  

Bit Packing: Nibble packing or packing letters into 4 bits cuts character sizes in half storing two characters in a single byte or character in a string.  The limitation is that only 16 letters may be used in all the words in the dictionary (61% of the letters in a 26 letter alphabet)

I explored three types of nibble packing, or packing characters into 4 bits:

Try to find words that shared any 16 unique letters - this requires a 16 byte character lookup which takes space from the dictionary

Try to find words that use any 16 contiguous letters in the alphabet - this requires a single hard coded offset to the first letter

Try to find words that use the first 16 contiguous letters in the alphabet - most of the dictionaries that use 16 contiguous letters used the first 16 due to the frequency of the letter "A" in words.  This is the compression ultimately used.


Representation in the program

The dictionary is represented in the program as a string of characters (bytes) in Q$ and a word count in N.

There is only enough room on one 80 character line to represent 34 words but there was some room on subsequent lines so I start the game with 34 words and then I ran into an unpleasant problem at one point where the string contained Atari's carriage return character or ASCII line feed, the conversion between Atari format and ANSI would harm the dictionary.  In the end I was able to select a dictionary that avoided those two bytes, but until I figured out what was going on it was a real head scratcher.

Decompression (Lines 3,4)

To index a word in the dictionary string multiply the word index by 2 and that is the offset of the compressed word in the dictionary string.

To decompress a word:

Loop through 3 bytes (6 letters)

Fetch a character

Divide by 16 and truncate using INT to get the high nibble

Subtract the high nibble*16 from the input character to get the low nibble

add the offset to "A" to each nibble and store them and you've decompressed two letters

repeat for 3 bytes or 6 letters 

What's even better is that since the first and last letter of each word is the same, each word is effectively 4 characters long and since characters are compressed two to a byte, each word starts on a 2 byte boundary.  If this was not done more work would be needed to decompress words starting on odd or even (low or high) nibbles.

Creation of the dictionary

Compression script 

I wrote a python script to explore compression options and find dictionaries.  The problem of finding sequences of words where each pair of words overlap by N letters, and all words use a subset of 16 characters from a 26 character set is an NP Hard problem.  An exhaustive search for dictionaries would literally take forever in any practical sense.  Fundamentally it's a graph coverage problem.  I used recursion, the creation of a connectivity graph between all the words in the source dictionary, greedily selecting and sorting potential words in the sequence by their impact on the symbol table, providing early exits where solutions were not easily found, and ultimately finally providing a time limit to recursions I was able to extract sizeable dictionaries.

Encoding

I used this BASIC program to encode the dictionary string (Warning Spoiler, this contains the actual game dictionary in human readable text)

REM CREATE COMPRESSED DICTIONARY STRING 

10 CLR:DIM S$(200)

20 S$="NINJABACKEBABADGEAGLEKINGAFFELFINEIGHEDGELIDEMAILABELADENICHEMBEDANCEMCEENEMABIDELOPEPOCHELLOAKENOMADECALAPELEACHIPPOFFALEGALIBELILACABALIMBOMEGABLEDENIMADAMAFIAGINGAMMAHEADINGOCEANIECEA"

30 ?"1Q$=";CHR$(34);:F.I=1 TO LEN(S$) STEP 2:?CHR$(27);CHR$((ASC(S$(I))-65)*16+ASC(S$(I+1))-65);:N.I:?


Verification

I used a line like this to print out and verify the dictionary in the game to make sure it was not malformed due to special characters, newlines, or string offset mistakes

10 FOR W=0 TO (N-1)*2 STEP 2:F.I=1TO3:J=ASC(Q$(W+I)):H=INT(J/S):W$(I*2-1)=CHR$(H+E):W$(I*2)=CHR$(J-H*S+E):N.I:?W$(1,5);" ";:N.W:?


Audio Visuals

Font & colors

Atari 8 bit computer graphics are usually are limited to 4 onscreen colors, 3 colors and a background.  Additional colors are available using player missile graphics, display list interrupts (which require assembly language), GTIA fat pixel modes, or special character modes in graphics 1 or 2.  I chose to use the big bold Graphics 2 because it filled the screen nicely for this game and it is able to display text in 4 colors (upper case, lower case, upper case inverted, and lower case inverted) on a fifth color background.  The problem is that in graphics mode 2 characters do not have a background or outline that I could use to show the tile colors, only the color of the text itself may be changed.  To allow multiple background colors I copied and inverted the Atari character set (line 2), that way all the character graphics are the black Atari background or overscan color on 4 different apparent tile background colors: white, grey, yellow, and green.

Sound

Even though the original Wordle has no sound I thought there should be a little more feedback at the completion of a game so I added dynamic sound controlled by the game state to the turn loop in line 9.  The loop either loops once with a 0 value for regular turns or 31 times when the game is over.  The sound statement uses the loop variable and the win/not win variable to configure the sound hardware to make different sounds.  

Input method

There are too many options to use the joystick and it would have been unintuitive and using BASIC's INPUT requires pressing enter after every input and validating inputs so I decided to access the keyboard device to get blocking input on individual keypresses.  The keyboard device is opened for input in line 0 O.#1,4,0,"K" (OPEN #1,4,0,"K") then keys are retrieved in input loop on line 5 GET#N1,K (GET #1,K).  The GET statement waits for a key and returns the ATASCII value in K which is then tested to make sure the key pressed is valid, between "A" and "Z" inclusively V=(K>63)*(K<91).

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 extensively in this program to handle input, make conditional calculations in hand ranking, and in GOTO statements to vector to intended lines based on conditions.

10 lines less than 80 columns (also see included "WORDLE Listing.png")

00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000011111111112222222222333333333344444444445555555555666666666677777777778
12345678901234567890123456789012345678901234567890123456789012345678901234567890
0DI.Q$(200),W$(11):GR.18:SE.0,0,15:SE.1,14,12:SE.2,11,10:SE.3,0,10:O.#1,4,0,"K"
1N=34:Q$="ØÙ¤6@kJ`UKXÔ†t6KƒL°°4Ø'L0ÒL$MLƒKïOât»à¤ÞÀ4 °ô´xÿåP´`¸¸° ¸Á
2E=225:S=16:?#6;"WORDLE":F.I=0TO896:POK.10240+I,255-PEEK(57344+I):N.I:POK.756,40
3W$="":W=INT(RND(0)*N)*2:F.I=1TO3:J=ASC(Q$(W+I)):H=INT(J/S):W$(I*2-1)=CHR$(H+E)
4W$(I*2)=CHR$(J-H*S+E):N.I:F.Y=3TO8:POS.7,Y:?#6;"€€€€€":N.Y:R=3:C=6:Z=0
5GET#1,K:V=(K>63)*(K<91):K=V*(K+160)+(1-V)*128:W$(C)=CHR$(K):POS.C+1,R:?#6;W$(C)
6Y=0:G=0:F.I=1TO5:M=CHR$(K)=W$(I,I):Y=Y+(1-Y)*M:G=G+(I=C-5)*M:N.I:Z=Z+G
7W$(C)=CHR$(K-Y*128+G*96):C=C+V:O=((R=8)OR(Z=5))*2:Q$(71)="ìF´4ØÀ":G.5+3*(C=11)
8POS.7,1:?#6;"     ":IF O THEN POS.7,1:?#6;W$(1,5):N=46:Q$(78)="0ÀX`Ì@8Öâ@ØB@
9F.I=O*15TO0STEP-1:POS.7,R:?#6;W$(6):SO.0,9+I,10*(Z=5),I:C=6:N.I:Z=0:R=R+1:G.5-O
Program Overview:

Line 0 Dimension strings, initialize graphics, initialize input device

Line 1 Initialize initial dictionary with first 34 words

Line 2 Initialize variables, print title, setup custom font

Line 3 Game loop, select random word from dictionary and begin decompression

Line 4 Finish decompressing word, clear letter playfield, set up game variables

Line 5 This is the main input loop, get key, validate input, 

store and display character entered

Line 6 Evaluate input character to determine if it should be 

yellow (in the word) or green (in the right place)

Line 7 Update character in the string to display correct color when printed later, 

extend the dictionary string by 7 bytes, test for game over and loop

Line 8 At this point 5 characters have been entered and a line is complete, 

display colored line, check for game over and display secret word, 

add 16 bytes to the dictionary increasing size to 46 words

Line 9 Print the colored letter string for end of turn, make sound if the game is over, 

take another turn if the game is not over, else start a new game


Detailed program description:

VARIABLES

Q$ String holding the compressed dictionary

N Number of words in the dictionary (starts with 37 and is expanded to 46 after the first turn)

W Word index in dictionary string, randomly selected on line 3

W$ String containing decompressed word, and letters input from the player

E Encoded index to first letter of decompressed word, inverse lower case

S Sixteen

K Key input

V Whether a key input is valid   

I Loop variable

J Temporary variable used to hold nibble pair during word decompression

H High nibble of byte from dictionary

Y Vertical location on the screen in loop on line 4, and whether letter should be yellow on line 6 (in word in wrong place)

R Row on screen for printing letter inputs

C Character index in word (W$), also used to position cursor for printing characters

M   Match, 1 if a character matches, 0 if it does not

G Whether character should be green on line 6

Z Number of Green characters in a word, if all 5 letters are in the correct place the player wins

O Whether the current game is over - either all letters are correct or 6 failed attempts


Expanded listing (one instruction per line, abbreviations expanded, functional description)

Line 0 Dimension strings, initialize graphics, initialize input device

DIM Q$(200),W$(11) Dimension dictionary and word strings

GRAPHICS 18 Graphics mode 2 large text +16 with no high resolution text window

SETCOLOR 0,0,15 Set background color to white

SETCOLOR 1,14,12 Set yellow color

SETCOLOR 2,11,10 Set green color 

SETCOLOR 3,0,10 Set grey color

OPEN #1,4,0,"K" Open the keyboard device for reading keys with GET

Line 1 Initialize initial dictionary with first 34 words

N=34 Set number of words in the dictionary to 34

Q$="ØÙ¤6@kJ`UKXÔ†t6KƒL°°4Ø'L0ÒL$MLƒKïOât»à¤ÞÀ4 °ô´xÿåP´`¸¸° ¸Á

Initialize dictionary 

(Closing quote not needed at end of line in Atari BASIC, full 80 character line used)

Line 2 Initialize variables, print title, setup custom font

E=225 Set the encode value for decompressing letters from the dictionary

S=16 Set sixteen variable 

PRINT #6;"WORDLE" Print the title

FOR I=0 TO 896 Loop through 112 characters of font

POKE 10240+I,255-PEEK(57344+I) Copy characters from ROM to RAM and invert bits so backgrounds may be colored

NEXT I Loop

POKE 756,40 Set CHBASE to new font location in RAM (8192 = 32*256)

Line 3 Game loop, select random word from dictionary and begin decompression

W$="" Clear the word string

W=INT(RND(0)*N)*2 Select a random word start location in dictionary

FOR I=1 TO 3 Loop to decompress 6 letters from dictionary (only 5 are used)

J=ASC(Q$(W+I)) Fetch a byte from the string

H=INT(J/S) Isolate the high nibble by dividing by 16 and truncating with INT

W$(I*2-1)=CHR$(H+E) Add encoding offset to nibble, convert to character and place in word string 

Line 4 Finish decompressing word, clear letter playfield, set up game variables

W$(I*2)=CHR$(J-H*S+E) Remove the high nibble from the byte, add encoding offset, and place in word string

NEXT I Loop

FOR Y=3 TO 8 Loop to draw/clear the grey word box for the turn 

POSITION 7,Y Position the cursor

PRINT #6;"€€€€€" Print 5 inverted spaces as grey boxes

NEXT Y Loop

R=3 Set the row to 3, this is row on the screen during the turn, gameplay ranges from 3 to 8

C=6 Set the column on the screen during the turn, gameplay ranges from 6 to 10

Z=0 Set the win detect (green count) to zero

Line 5 This is the main input loop, get key, validate input, store and display character entered

GET #1,K Fetch keyboard input

V=(K>63)*(K<91) Calculate key validity, will be 1 if A-Z are pressed, 0 otherwise

K=V*(K+160)+(1-V)*128 Update the key to be either a valid encoded letter or space

W$(C)=CHR$(K) Set the character in the input part of the word string to validated encoded k

POSITION C+1,R Position the cursor

PRINT #6;W$(C) Print the key black on grey

Line 6 Evaluate input character to determine if it should be 

yellow (in the word) or green (in the right place)

Y=0 Set number of yellows to 0

G=0 Set number of greens to 0

FOR I=1 TO 5 Loop through the characters in the word string

M=CHR$(K)=W$(I,I) Set the match variable if the last input character matches the character at index I

Y=Y+(1-Y)*M Yellow will be set to 1 if the character matches any position

G=G+(I=C-5)*M Green will be set to 1 only if the character matches the position where index I equals the current column

NEXT I Next loop

Z=Z+G

Line 7 Update character in the string to display correct color when printed later, test for game over and loop

W$(C)=CHR$(K-Y*128+G*96) Subtracting 128 will remove invert and cause background to be yellow, adding 96 will go to upper case causing the color to be green 

C=C+V Advance to next column only if the input character was valid, if not just repeat in the current column

O=((R=8)OR(Z=5))*2 O is 2 if the game is over; if the current row is 8 or if all five letters are green

Q$(71)="ìF´4ØÀ" Add 7 bytes to dictionary

GOTO 5+3*(C=11) Input loop, if column is not 11 loop back to line 5 for more input, otherwise continue to next line 8

Line 8 At this point 5 characters have been entered and a line is complete, display colored line, 

check for game over and display secret word, add 7 words to the dictionary increasing size to 46 words

POSITION 7,1 Position the cursor at the top of the screen 

PRINT #6;"     " Clear the previous word area of the screen

IF O THEN If the game is over...

POSITION 7,1 If the game is over position the cursor at the top of the screen

PRINT #6;W$(1,5) Print the secret word

N=46 Increase dictionary size to 46 words

Q$(78)="0ÀX`Ì@8Öâ@ØB@ Add 16 bytes to the dictionary string

(Closing quote not required at end of line in Atari BASIC, full 80 character line used)

Line 9 Print the colored letter string for end of turn, make sound if the game is over, 

take another turn if the game is not over, else start a new game

FOR I=O*15 TO 0 STEP -1 Loop to make sound at end of game, either one iteration of I=0, or 31 iterations from 30 to 0

POSITION 7,R Position the cursor to print the color coded user input word (in the loop to slow down sound at end of game)

PRINT #6;W$(6) Print the color coded user input string (in the loop to slow down sound at end of game)

SOUND 0,9+I,10*(Z=5),I Make sound:

If the game is not over, there is only an I=0 loop setting a sound with volume 0

If the game is over I loops 30 to 0 which rises pitch (9+I) and decreases volume (I), the distortion is set to 0 for noise if the player didn't win, and pure tone if the player matched all 5 letters (10*Z=5)

C=6 Set the column (C) to 6 for the next turn (in the loop to slow down sound at end of game)

NEXT I Complete sound loop

Z=0 Set the count of letter matches (green letters) to 0 for next turn

R=R+1 Advance to next row on the screen

GOTO 5-O If the game is won GOTO line 3 to start new game, otherwise GOTO line 5 to take next turn

Published 1 day ago
StatusReleased
AuthorBASIC 10Liner
GenrePuzzle
Tags10liner, 8-Bit, atari, basic

Download

Download
README Wordle.txt 19 kB
Download
WORDLE.atr 90 kB
Download
WORDLE.BAS 1.4 kB
Download
WORDLE.LST 791 bytes
Download
WORDLE.LST.TXT 791 bytes

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 "Wordle.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:WORDLE.LST" and press enter to load the program (alternate LOAD"D1:WORDLE.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