Saturday, April 16, 2022

I Made a Wordle Cheating Program (by Mistake)

I recently was a guest speaker in an educational game design class at Old Dominion University. In preparation, I thought I'd check out Wordle given that it has been very popular recently. The "official" Wordle site is at the New York Times and it only provides a new word once a day. However, here is a good online version where you can play unlimited games.

The game's simplicity intrigued me - the graphic design just involves letters and simple colored boxes with a very simple user interface. It's quite a contrast when compared to other popular online games involving 3D graphics and virtual worlds. According to Wikipedia, Wordle was developed by Josh Wardle who eventually sold the game to the New York Times for "an undisclosed seven-figure sum." Hmm, I said to myself. I once created a word game called "Crack the Code." Maybe I have a seven-figure sum game I need to release to the world. Heck, I'd settle for a six-figure sum sale. As it turns out, I did "release this to the world" back in 2013 in a blog post. Unfortunately, my game is not much fun to play. How do I know? Well, when I asked people to play it and asked them how they liked it, they replied "Sorry, Lloyd, it's just not very fun to play." Pretty solid evaluation data there. The question of "What makes a game fun to play?" is actually a very interesting and profound question. So, it's worth thinking about why Wordle is so captivating.

Interestingly, even though I have much interest in games, I do not identify myself as a "gamer," mainly because I'm legitimately afraid of getting addicted and I just don't have time for that. Well, after playing Wordle for a short time, I was hooked. As I played it, it was clear to me that the first and second words you enter at the start of the game are very important. It turns out there are lots of web sites and videos that propose the best words to use. I've settled on "audio" as my favorite first word given that it contains so many vowels. Other favorites are "radio" and "audit." Here's an interesting video that provides some interesting statistics and advice for choosing a first word - bottomline: don't pick "fuzzy."

As I continued to play the game, I began to wonder how to determine the best way for myself to choose the first and second words. Given that the game is based on text processing, I thought this would be a perfect LiveCode project. So, last Sunday afternoon, I spent about two hours to quickly produce such a LiveCode program. A day or two later I thought this would be a good program to share with others on this blog, so I spent another two hours or so revising the user interface so others could use it. (As is typical, the time spent on the user design interface takes as long - and usually longer - than the programming for the software itself.)

Here's a screen shot of the interface:

I'll explain how this works in a moment, but the important point I want to make is my sole purpose in creating this app was only to gather statistics on the best words to choose at the beginning of the game. However, it turns out that my app also is the perfect tool to cheat at Wordle! The reason is that my program continues to whittle down the possible word matches as you go. Consequently, I can pretty much just choose a word at random at each turn of the game and win. As someone quickly asked me when I told them about this, doesn't that take the fun out of the game? The answer is yes. Of course, for me, I continue to find it quite exhilarating to see my little program chug along to beat the game.

Obviously, one needs a good list of five letter words from which to search for good and bad matches. I used the word list available at this site: https://eslforums.com/5-letter-words/

However, I really need to find a more complete word list because after using my app to play Wordle, I found my list was missing these common words: torte, motel, moron, spank.

Ok, here's a short video of me using the program as I played a round of Wordle.


The main code that makes this all work can be found in the "Search Word List" button. Here's the code:

1:  on mouseup  
2:    put empty into field "matches"  
3:      
4:    put the number of lines in field "word list" on card "resources" into L  
5:      
6:    repeat with i = 1 to L //word list loop  
7:     put false into varSkipWord  
8:     put line i of field "word list" on card "resources" into varWord  
9:       
10:     //Check first for matched letters in correct spot  
11:     put line 1 of field "first" into varFirstMatch  
12:     if field "first" is not empty then  
13:       if char 1 of varWord <> varFirstMatch then next repeat  
14:     end if  
15:     put line 1 of field "second" into varSecondMatch  
16:     if field "second" is not empty then  
17:       if char 2 of varWord <> varSecondMatch then next repeat  
18:     end if  
19:     put line 1 of field "third" into varThirdMatch  
20:     if field "third" is not empty then  
21:       if char 3 of varWord <> varThirdMatch then next repeat  
22:     end if  
23:     put line 1 of field "fourth" into varFourthMatch  
24:     if field "fourth" is not empty then  
25:       if char 4 of varWord <> varFourthMatch then next repeat  
26:     end if  
27:     put line 1 of field "fifth" into varFifthMatch  
28:     if field "fifth" is not empty then  
29:       if char 5 of varWord <> varFifthMatch then next repeat  
30:     end if  
31:       
32:     //Second, check for letters to exclude  
33:     put the number of lines in field "exclude" into M  
34:     repeat with j = 1 to M //use excluded letters loop  
35:       put line j of field "exclude" into varLetterToExclude  
36:       if varWord contains varLetterToExclude then   
37:        put true into varSkipWord  
38:        exit repeat //no need to keep looking, just exit out  
39:       end if  
40:     end repeat //END use excluded letters loop  
41:       
42:     //Third, check for letters to include  
43:     put the number of lines in field "include" into N  
44:     repeat with k=1 to N //use included letters loop  
45:       put line k of field "include" into varLetterToInclude  
46:       if varLetterToInclude is not in varWord then  
47:        put true into varSkipWord  
48:        exit repeat //no need to keep looking  
49:       end if  
50:     end repeat //END use included letters loop  
51:       
52:     //Fourth and last, check for matched letters but not yet in the right spot  
53:     put line 1 of field "notfirst" into varNotFirstMatch  
54:     if field "notfirst" is not empty then  
55:       if char 1 of varWord = varNotFirstMatch then next repeat  
56:     end if  
57:     put line 1 of field "notsecond" into varNotSecondMatch  
58:     if field "notsecond" is not empty then  
59:       if char 2 of varWord = varNotSecondMatch then next repeat  
60:     end if  
61:     put line 1 of field "notthird" into varNotThirdMatch  
62:     if field "notthird" is not empty then  
63:       if char 3 of varWord = varNotThirdMatch then next repeat  
64:     end if  
65:     put line 1 of field "notfourth" into varNotFourthMatch  
66:     if field "notfourth" is not empty then  
67:       if char 4 of varWord = varNotFourthMatch then next repeat  
68:     end if  
69:     put line 1 of field "notfifth" into varNotFifthMatch  
70:     if field "notfifth" is not empty then  
71:       if char 5 of varWord = varNotFifthMatch then next repeat  
72:     end if  
73:       
74:     if varSkipWord is false then put varWord&return after field "matches"  
75:    end repeat //END word list loop  
76:      
77:    put the number of lines in field "matches"&space&"matches" into field "matches label"  
78:      
79:    //Compute Statistics  
80:    put the number of lines in field "matches" into varMatchesCount  
81:    put line 1 of field "guess" into varGuess  
82:    put the number of lines in field "matches" into varNumerator  
83:    put the number of lines in field "word list" on card "resources"into varDenominator  
84:    put varGuess&comma&varMatchesCount&"("&round((varNumerator/varDenominator) * 100,3)&"%"&")"&return after field "statistics"  
85:      
86:  end mouseup  

I put a comment at the start of each important block of code. The key variable is varSkipWord. This variable will determine whether or not each word in the list of over 2500 words should be skipped. If skipped, the word does not match any still available word to try in the next guess. In line 7, I set this to false, meaning that unless something tells the computer otherwise, keep the word as a possible match - that is, don't skip it. At various places in the code, you'll see the code "put true into varSkipWord," such as in line 37. If varSkipWord remains false by the time the code reaches line 74, then the word is added to field "matches," which shows all of the words that are viable possibilities for the next guess.

In conclusion, this little project was perfect for LiveCode. Too bad I ruined my own Wordle game experience. I hope I don't ruin it for you.

5 comments:

  1. Not having run your program I'm still not sure why it would ruin the game for you in the future if you then return to playing it normally. Is it because you now understand the logic too well at this point? I could try your program and see for myself, but I don't want to risk any real threat to my future games.
    I'm not clear, is winning just finally getting the correct word, or in minimizing the number of guesses required for solution. I have no problem getting the word, the "fun" part is finding the word quickly.
    I agree, it is always tempting to use LiveCode for such applications, hard to resist. The development challenges are intriguing and insightful.

    ReplyDelete
  2. The reason it could ruin one's Wordle experience is because you can let my program play the game for you. All you need to do is pick a word from the ever-decreasing list of words. However, after thinking about it further, my app could be used by someone who just gets stuck at a certain point while playing the game. So, maybe that is a way for my app to enhance the gaming playing experience. But, I'm afraid that most people will be too tempted to just let my app do the hard (and fun) work, which then would take the fun out of the game. All that said, I am interested in continuing my exploration into the the mathematics of Wordle. For example, I may program into my app a button that chooses a word from the current list of words truly at random to see if my app can actually play the game and win without any human assistance.

    ReplyDelete
  3. Is 6 tries the criterion for winning, the same as in Wordle? Does your app record & display the sequence of tries?

    ReplyDelete
  4. Watch this short demo video - it will clear up what my app and doesn't do: https://www.youtube.com/watch?v=A8nGwptdLMc

    ReplyDelete
  5. Ah, yes, that clarifies it. I wasn't paying attention, I was thinking that it simply solved the puzzle for you (over-generalized the term 'cheat'). Now I see that it guides you through the process on the Wordle web site. Really interesting way to help a person tune in to possible strategies and practices and then they can continue solving puzzles in the future with their new insights and approach without the use of the app. Good job.

    ReplyDelete