WORDS

Unsurprisingly, Wordle is a game about words, so we need to have a section of the code dedicated to them.

DAILY

Each day the players are allowed to guess a single word which is automatically selected by the script.

I didn’t want to make a fully functioning Wordle clone with a vast set of words, so the set here is quite small and is stored in a single string. The words are base64-encoded to obfuscate the words from people seeing the code like yourself.

%%[
/* Select the word for the day in the encoded form */
set @words = 'U1RFQU0=|T1BFUkE=|Q0xPQUs=|Q0xFQVI=|TklHSFQ=|R0hPU1Q=|U1RBRkY=|U1RPVVQ=|UElMT1Q=|S0VCQUI=|QUJZU1M=|Uk9VR0U=|V09STEQ=|UVVFUlk=|VUxDRVI=|U0lFR0U=|QkxPS0U=|RlJBTUU=|Q0hFQVQ=|RVBPQ0g=|U1BJQ1k=|RUxERVI=|RkVJR04=|Q1JBVEU=|VElNSUQ=|U1BJTEw=|QlJFQUs=|UEFVU0U=|R1JJTUU=|Q0hBTVA=|TllNUEg='

set @rowset = BuildRowsetFromString(@words, '|')
set @day = DatePart(@now, 'D')
set @row  = Row(@rowset, @day)
set @theWordEncoded = Field(@row, 1)
set @theWord = Base64Decode(@theWordEncoded, "UTF-8")

The processing is quite simple:

  • We use the BuildRowsetFromString() function to make our string work as an array of words
  • We get the number representing the @day of the month
  • This number is used to select the corresponding row from our @rowset of words)
  • The encoded word is retrieved using the Field function
  • Finally, we decode the string obtained in the last step to get the daily word

Consider this example:

  • I’m writing this on April 12 2022
  • This means the @day variable would get the value of 12
  • The 12th word is Uk9VR0U= which decoded means ROUGE

VOCAB

To ensure players don’t submit non-existing words to easily find the letters from the searched word, we need to have a data extension with a list of allowed words:

  • I’m using the Wordle - Allowed Word List name in my script
  • The DE has just a single column called Words with the obvious text data type and length of 5 characters
  • You can see the allowed word list here – this txt file stores 12.972 words
NOTE

Why do we need this? We want to prevent players from optimizing their search for the daily word by using strings like EAIOU or NRSTC allow them to eliminate letters without flexing their knowledge of the English vocabulary.

CHECK

If the player has submitted a word, we perform a validation to see if we can accept this @lastGuess.

Words are accepted if they fulfill the following conditions:

  • they were not submitted before
  • they exist in our dictionary data extension
/* Validation of incoming words*/
IF 
    IndexOf(@guesses, @lastGuess) < 1
    AND
    Empty(@lastGuess) == false
        THEN
            set @lookup = RowCount(LookupRows('Wordle - Allowed Word List', 'Word', @lastGuess))

            IF 
                @lookup == 1
                AND
                Empty(@guesses) == true
                THEN
                    set @guesses = @lastGuess
            ELSEIF 
                @lookup == 1
                AND
                Empty(@guesses) == false
                THEN
                    set @guesses = Concat(@guesses, '|', @lastGuess)
            ELSE
                    set @feedback = Concat("'", @lastGuess, "' is not an allowed word")
            ENDIF
ELSEIF
    IndexOf(@guesses, @lastGuess) > 0
        THEN
            set @feedback = 'Repeat guesses are not allowed'
ENDIF

Submitted words are validated in two ways:

  • we check if they exist in our data extension with allowed words
    • if the word is found by the lookupRows fucntion, the @lastGuess variable is added to the @guesses string conditionally:
      • if it is the first submitted word, it becomes the @guesses value
      • any words submitted later are delimited with the | separator
  • we check if the word was submitted previously

INPUT

You might have thought that there’s a flaw in the validation of the submitted word – the submitted @lastGuess is never checked for length or if it only contains letters. That part of the validation is done entirely client-side by HTML form validation and the properties of the main input.

The submited word needs to fit with the [A-Za-z]{5} pattern: must have 5 letters (case insensitive). If the input value does not match this value, the browser will display the message: This needs to be a 5-letter word.

RESET

The following block checks if the daily word has expired in the middle of our session:

/* Check if the last word has expired */
IF 
    Empty(@previousWord) == false
    AND
    @theWord != Base64Decode(@previousWord)
    THEN 
        set @feedback = 'The daily word has reset'
        set @guesses = ''
        set @lastGuess = ''
ENDIF

While the script is running, we check if the current run is a reaction to a form submission event (the @previousWord values is not empty) and later compare the current daily word with the one that was submitted in the @previousWord in the encoded form. If those conditions are met:

  • we remove all @guesses which resets the progress
  • the @lastGuess is removed so that a lucky guess from the last try does not accidentally count as a submission for a new day