Hadn't touched QB in a few years, so I decided to dust off the old IDE and give this project a go.
Introducing WorDOSle!
This is a clone of the popular web game Wordle but written in QuickBASIC for DOS.
Now you can finally play Wordle on your Tandy 1000 or that old 286 sitting in the closet!
All in all, the game is just over 300 lines and was written in a single afternoon.
I made the game using QuickBASIC PDS 7.1, but it should run on QB45, or even QBasic if you comment out the COMMAND$ line.
Source available on my website:
http://grahamdowney.com/software/WorDOSle/WorDOSle.htm
WorDOSle -- Wordle for DOS made in QB!
Re: WorDOSle -- Wordle for DOS made in QB!
Nice! Can I make three suggestions? They are trivial to implement, except for the last one.
In GetWord$, use the file size to obtain the number of words in the dictionary rather than using a hard-coded value (so words can be added or removed without modifying the program.)
Allow the player to give up by pressing escape (ASCII code 27.) It should only be a matter of converting GetGuess to a function (when it returns -1, leave the "for" loop as if all attempts were made, so we get to see the word and have the "play again" prompt.)
Now for the tricky part: Wordle only allows the user to input existing words, while your version allows completely random letter sequences. It is possible to test the input word against the dictionary with a binary search (it's super fast but requires the word list to be alphabetically ordered.) It would be preferable to store the whole dictionary in memory to make the search faster while it will obviously increase the initial loading time so I understand if you don't want that.
I did some legwork if you're interested...
In GetWord$, use the file size to obtain the number of words in the dictionary rather than using a hard-coded value (so words can be added or removed without modifying the program.)
Allow the player to give up by pressing escape (ASCII code 27.) It should only be a matter of converting GetGuess to a function (when it returns -1, leave the "for" loop as if all attempts were made, so we get to see the word and have the "play again" prompt.)
Now for the tricky part: Wordle only allows the user to input existing words, while your version allows completely random letter sequences. It is possible to test the input word against the dictionary with a binary search (it's super fast but requires the word list to be alphabetically ordered.) It would be preferable to store the whole dictionary in memory to make the search faster while it will obviously increase the initial loading time so I understand if you don't want that.
I did some legwork if you're interested...
Code: Select all
DEFINT A-Z
DECLARE FUNCTION openlist% (filename AS STRING)
DECLARE FUNCTION wordIndex% (myWord AS STRING)
REDIM SHARED wordLst(0) AS STRING * 5
DIM user AS STRING, id AS INTEGER
PRINT "Loading list..."
IF (NOT openlist%("words.dat")) THEN PRINT "Something went wrong": END
' picking a random word from the list...
PRINT "picking a random word: "; CHR$(34); wordLst(INT(RND * (UBOUND(wordLst) + 1))); CHR$(34)
' testing user input (only accept existing words)
DO
INPUT "Guess a word:", user
IF LEN(user) THEN
id = wordIndex%(user)
IF (id < 0) THEN
PRINT "This word is not in the dictionary"
ELSE
PRINT "This word is index #"; id
END IF
ELSE
EXIT DO
END IF
LOOP
' Open word list. The list MUST be formatted and orderly; if not, the routine
' will handle that for you and update the file so it loads faster next time.
' Users can add (or remove) words from the list. In a perfect world, we should
' make sure there's enough memory available to store the dictionary and also
' verify data integrity (so only words with characters in range A-Z are ok'd.)
FUNCTION openlist% (filename AS STRING)
DIM ff AS INTEGER, update AS INTEGER, tmp as string * 5
DIM count AS INTEGER, offset AS INTEGER, max AS INTEGER, hiRef AS INTEGER
' open file
ff = FREEFILE
OPEN filename FOR INPUT AS #ff
' file size should be multiple of 7 (doesn't guarantee data integrity)
IF (LOF(ff) MOD 7) THEN
CLOSE #ff
EXIT FUNCTION
END IF
' resize word array
REDIM wordLst(LOF(ff) \ 7 - 1) AS STRING * 5
' store all in uppercase, then close file
FOR i% = 0 TO UBOUND(wordLst)
INPUT #ff, tmp
wordLst(i%) = ucase$(tmp)
NEXT i%
CLOSE #ff
' now make sure they are alphabetically sorted, this can take a while
' depending on the number of words and how disorderly the list is.
count = UBOUND(wordLst) + 1
offset = count \ 2
DO WHILE offset
max = count - offset - 1
DO
hiRef = 0
FOR i% = 0 TO max
IF (wordLst(i%) > wordLst(i% + offset)) THEN
SWAP wordLst(i%), wordLst(i% + offset)
update = -1
hiRef = i%
END IF
NEXT i%
max = hiRef - offset
LOOP WHILE hiRef
offset = offset \ 2
LOOP
' list had to be sorted, re-save so it loads faster next time
IF update THEN
OPEN filename FOR OUTPUT AS #ff
FOR i% = 0 TO UBOUND(wordLst)
PRINT #ff, wordLst(i%)
NEXT i%
CLOSE #ff
END IF
' all done
openlist% = -1
END FUNCTION
' Binary search. It's much faster than a linear search (one entry after the
' other) but it requires the array to be alphabetically ordered. This function
' returns the index of the word within the wordLst() array. If the word cannot
' be found, this function returns -1.
FUNCTION wordIndex% (myWord AS STRING)
DIM search AS STRING, cueLo AS INTEGER, cueHi AS INTEGER, cueMid AS INTEGER
search = UCASE$(myWord) ' make sure the input is formatted
cueHi = UBOUND(wordLst) ' upper boundary
wordIndex% = -1 ' assume the word doesn't exist
DO WHILE (cueLo <= cueHi)
cueMid = (cueLo + cueHi) \ 2 ' test central word
SELECT CASE wordLst(cueMid)
CASE IS < search
cueLo = cueMid + 1 ' word must be in the 2nd half
CASE IS > search
cueHi = cueMid - 1 ' word must be in the 1st half
CASE ELSE
wordIndex% = cueMid ' found it!
EXIT FUNCTION
END SELECT
LOOP
END FUNCTION
Re: WorDOSle -- Wordle for DOS made in QB!
Hey Mike, thanks for the suggestions! Those shouldn't be too much hassle to add in the next update.
The only thing I was concerned with the word lookup would be how fast it's gonna run on an 8088 (that was my initial benchmark for getting this to run). If I do add it I'll probably just pre-sort the whole text file that way it won't rely on having to sort it when it loads initially.
I'll also need to check how the load time for that is off the 360k diskette drive, but I'm thinking worst case scenario I could probably make some changes to the .dat file so I could just load the whole thing in a single GET # command.
Fun fact: the word list I'm using was actually the original Wordle word-set from before New York Times changed the dictionary! I originally considered adding the day counter like they had so that I could sync up with past words from there, but the random word selection seemed more fun in the end.
The only thing I was concerned with the word lookup would be how fast it's gonna run on an 8088 (that was my initial benchmark for getting this to run). If I do add it I'll probably just pre-sort the whole text file that way it won't rely on having to sort it when it loads initially.
I'll also need to check how the load time for that is off the 360k diskette drive, but I'm thinking worst case scenario I could probably make some changes to the .dat file so I could just load the whole thing in a single GET # command.
Fun fact: the word list I'm using was actually the original Wordle word-set from before New York Times changed the dictionary! I originally considered adding the day counter like they had so that I could sync up with past words from there, but the random word selection seemed more fun in the end.
Re: WorDOSle -- Wordle for DOS made in QB!
Great! I'm fairly confident a binary search is fast enough to return the index in the array, but you're right about the ordered list: it takes time... I gave a try with Quick sort, and even though it's 4x faster than Shell sort, it also takes 2x the time to parse an already sorted list. Storing the formatted and sorted strings with BSAVE and reload with BLOAD would definitely be faster. That would also shave about 4 Kbs off the word list too.
Re: WorDOSle -- Wordle for DOS made in QB!
Was pretty busy the last few days, but managed to get together an update!
Here's everything that I changed in version 1.1:
- Only accept guess if it's in the dictionary
- Don't register key used to close menu as game input
- Can give up round by pressing [Esc]
- Optimized dictionary (~4.5kb smaller)
- Improved monochrome display mode
Updated binaries and source are both available on the website.
Here's everything that I changed in version 1.1:
- Only accept guess if it's in the dictionary
- Don't register key used to close menu as game input
- Can give up round by pressing [Esc]
- Optimized dictionary (~4.5kb smaller)
- Improved monochrome display mode
Updated binaries and source are both available on the website.
Re: WorDOSle -- Wordle for DOS made in QB!
Nice job! I had a lot of fun with this game so far. I've never really played the original WORDLE game so this was new to me.
I loaded it up on my IBM XT and ran it off a 360Kb floppy and then off the CF hard drive (MFM drive is sticking so I wasn't able to try that today... need to go in and manually spin it a few times to get it going again).
Off a 360Kb floppy, it took around 7-8 seconds to start. Off the CF card, it started in just under 2 seconds. Those times are with using the compiled EXE file.
Here's a pic of it running on my XT using the /mono flag. The picture doesn't really do the screen justice. It looks much better in person.
![Image](https://i.imgur.com/eZ1bLBo.png)
![Smile :)](./images/smilies/icon_smile.gif)
I loaded it up on my IBM XT and ran it off a 360Kb floppy and then off the CF hard drive (MFM drive is sticking so I wasn't able to try that today... need to go in and manually spin it a few times to get it going again).
Off a 360Kb floppy, it took around 7-8 seconds to start. Off the CF card, it started in just under 2 seconds. Those times are with using the compiled EXE file.
Here's a pic of it running on my XT using the /mono flag. The picture doesn't really do the screen justice. It looks much better in person.
![Image](https://i.imgur.com/eZ1bLBo.png)
Re: WorDOSle -- Wordle for DOS made in QB!
Damn, that's really cool!