How to Make a Wordle Solver with Twilio Serverless, Studio, and SMS
Tags: twilio, javascript, serverless, datamuse
Published: 2022-02-24 00:00:06

---
title: How to Make a Wordle Solver with Twilio Serverless, Studio, and SMS
published: true
description: Learn how to build a Wordle solver over SMS using Twilio Serverless, Studio, JavaScript, and the Datamuse API!
tags: twilio, javascript, serverless, datamuse
cover_image: https://twilio-cms-prod.s3.amazonaws.com/images/Copy_of_C01_Blog_Text_HacANFr.width-1616.png
---
This blog post was written for [Twilio](https://www.twilio.com/) and [originally published on the Twilio blog](https://www.twilio.com/blog/wordle-solver-serverless-studio-sms).

Like many word nerds and puzzle lovers, I am obsessed with Wordle, a word puzzle game created by Brooklyn-based software engineer Josh Wardle for his word game-loving partner. I [made a Wordle version over SMS with Twilio Serverless](https://www.twilio.com/blog/build-wordle-like-sms-game-serverless) to play even more Wordle, but sometimes, I get stuck while playing. Read on to learn how to build a SMS Wordle solver using [Twilio Studio](https://www.twilio.com/studio), [Twilio Functions](https://www.twilio.com/docs/runtime/functions), the [Twilio Serverless Toolkit](https://www.twilio.com/docs/labs/serverless-toolkit), and the [Datamuse API](https://www.datamuse.com/api/) to find words given a set of constraints, or <strong>test it out by texting anything to +18063046212</strong>!

This was built with my coworker [Craig Dennis](https://twitter.com/craigsdennis) on [my Twitch channel](https://www.twitch.tv/lizziepikachu).
![sms example](https://twilio-cms-prod.s3.amazonaws.com/images/textexample.width-500.png)
Want a brief overview of how it's built? [Check out this Tiktok](https://www.tiktok.com/@lizziepikachu/video/7066953223139282222)!

### Prerequisites
1. A Twilio account - [sign up for a free one here and receive an extra $10 if you upgrade through this link](http://www.twilio.com/referral/iHsJ5D)
2. A Twilio phone number with SMS capabilities - [configure one here](https://support.twilio.com/hc/en-us/articles/223135247-How-to-Search-for-and-Buy-a-Twilio-Phone-Number-from-Console)
3. Node.js installed - [download it here](https://nodejs.org/en/download/)

### Get Started with the Twilio Serverless Toolkit
The Serverless Toolkit is CLI tooling that helps you develop locally and deploy to [Twilio Runtime](https://www.twilio.com/docs/runtime). The best way to work with the Serverless Toolkit is through the Twilio CLI. If you don't have the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart) installed yet, run the following commands on the command line to install it and the Serverless Toolkit:
```bash
npm install twilio-cli -g
twilio login
twilio plugins:install @twilio-labs/plugin-serverless
```
Create your new project and install our lone requirement `[superagent](https://www.npmjs.com/package/superagent)`, an HTTP client library to make HTTP requests in Node.js, by running:
```bash
twilio serverless:init wordle-solver --template=blank && cd wordle-solver && npm install superagent
```
### Hit the Datamuse API to Receive Potential Wordle Words with JavaScript
You can do a lot with the Datamuse API. For example, to retrieve words that start with <em>t</em>, end in <em>k</em>, and have two letters in-between, you would hit [api.datamuse.com/words?sp=t??k](https://api.datamuse.com/words?sp=t??k) and see:
![words starting with t, ending in k, with 2 letters in-between](https://twilio-cms-prod.s3.amazonaws.com/images/-2GN2oDA1UvffqDp5L-GK1Dpnp6Vz3fQmtmEzX4z2eDpCK.width-800.png)
Make a file in the <em>functions</em> folder of your `wordle-solver` serverless project from <em>solver.js</em>. At the top, import <em>superagent</em> and make a helper function to, given a letter and a word, return indices found to later calculate black letters from the yellow squares and guesses input.
```javascript
const superagent = require("superagent");
function findIndices(letter, word) {
  return word
    .split("")
    .map((l, i) => {
      if (l === letter) {
        return i;
      }
    })
    .filter((index) => index >= 0);
}
```
The meat of the code is in the Function handler method:
```javascript
exports.handler = function (context, event, callback) {
  // Here's an example of setting up some TWiML to respond to with this function
  let greenSquares = String(event.green.toLowerCase());
  let yellowSquares = event.yellow ? event.yellow.toLowerCase() : "";

  let guesses = event.guesses.toLowerCase().split(",");
  // Finds yellow places (right letter wrong space)
  // Looks like {'e': [4, 3], 'a': [0]}
  const yellowIndices = yellowSquares.split("").reduce((indices, letter) => {
    guesses.forEach((guess) => {
      if (indices[letter] === undefined) {
        indices[letter] = [];
      }
      const foundIndices = findIndices(letter, guess);
      indices[letter] = indices[letter].concat(foundIndices);
    });
    return indices;
  }, {});
  console.log(`yellowIndices ${JSON.stringify(yellowIndices)}`);
  console.log(`guess ${guesses}, greenSquares ${greenSquares}, yellowSquares ${yellowSquares}`);
  const blackSquares = guesses
    // To an array of arrays of letters
    .map((word) => word.split(""))
    // To a single array
    .flat()
    // Only the missing letters
    .filter((letter) => {
      return !yellowSquares.includes(letter) && !greenSquares.includes(letter);
    }); //get black squares
  console.log(`blackSquares ${blackSquares}`);
  let messagePattern = greenSquares + `,//${yellowSquares + '?'.repeat(5 - yellowSquares.length)}`;
  //let messagePattern = greenSquares + `,*${yellowSquares}*`; 
  console.log(`messagePattern ${messagePattern}`);
  superagent.get(`https://api.datamuse.com/words?max=1000&sp=${messagePattern}`).end((err, res) => {
    if (res.body.length <= 2) { //Datamuse doesn't have any related words
      console.log("no related words");
      return callback(null, { "words": [] });
    } //if
    let allWords = res.body.map(obj => obj.word);
    let wordsWithoutBlackLetters = allWords.filter(
      word => {
        return word.split("").every(letter => !blackSquares.includes(letter));
      });
    console.log(`wordsWithoutBlackLetters ${wordsWithoutBlackLetters}`);
    const withoutIncorrectYellow = wordsWithoutBlackLetters.filter((word) => {
      // for each letter in the indices
      for (const [letter, indices] of Object.entries(yellowIndices)) {
        for (const index of indices) {
          if (word.charAt(index) === letter) {
            // Short circuit (Johnny 5 alive)
            return false;
          }
        }
      }
      // It's a keeper!
      return true;
    });
    return callback(null, { 
      "words": withoutIncorrectYellow.slice(0, 10), //due to message length restrictions and these are the likeliest words
      "guesses": guesses
    });
  });
};
```
The [complete code can be found on GitHub here](https://github.com/elizabethsiegle/wordle-solver-p2-ty-craig).

Go back to the <em>wordle-solver</em> root directory and run `twilio serverless:deploy`. Copy the function URL from the output and save it for later. It will look like this: [https://wordle-solver-xxxx-dev.twil.io/solver](https://wordle-solver-2520-dev.twil.io/solver). Now the Function is deployed, but we need to make the Twilio Studio Flow that will call this Twilio Function to return possible Wordle words to the user texting in.

### Make the App Logic with Twilio Studio
I tried to build this Wordle Solver solely with Twilio Functions, but Craig insisted Twilio Studio was perfectly-suited for this project. Studio is Twilio's drag-and-drop visual builder, a no-code to low-code platform. I had not used Studio that much and after seeing Craig work his magic on Twitch, I am now a Studio evangelist/convert!

[Open up this gist](https://gist.github.com/elizabethsiegle/2d03165e1370b7478c77d77d8ef83c24) and copy the JSON to a file - you'll need to replace a few variables (<em>service_sid</em>, <em>environment_sid</em>, and <em>function_sid</em>) so this makes it easier to edit.

To get <em>service_sid</em>, run the following command with the Twilio CLI:
```bash
twilio api:serverless:v1:services:list
```
Keep adding on what you get, so from the last command (take the <em>service_sid</em> corresponding to our project <em>wordle-solver</em>), run
```bash
twilio api:serverless:v1:services:environments:list --service-sid= SERVICE-SID-FROM-THE-LAST-COMMAND
```
to get the <em>environment_sid</em>. Then run the following command to get the <em>function_sid</em>.
```bash
twilio api:serverless:v1:services:functions:list --service-sid=YOUR-SERVICE-SID-FROM-ABOVE
```
Lastly, replace the <em>url</em> with the URL of your Twilio Function URL ending in "/solver" you receive when you deploy your serverless function.

To make a new Twilio Studio flow, log in to your Twilio account and go to the Studio Dashboard. Then, click the blue plus sign and give your flow the name “wordle-solver” Click next in the setup modal, scroll down and choose “Import from JSON” from the provided templates.
![import from json](https://twilio-cms-prod.s3.amazonaws.com/images/oUj875cZp2hMd5uSOFjzHCyzCjzLLe-7mZSeVxbnw5jbGq.width-500.png)
Paste in the JSON (with the replaced placeholders) copied from the gist. Once you finish the setup, you should see a flowchart like the one below. Hit the Publish button at the top of the flow.
![part of studio flow](https://twilio-cms-prod.s3.amazonaws.com/images/RiOzAvpTwejeLxSMSpAAv7Q1FJKyIkgaajb9-I6adPUzNQ.width-500.png)
When someone first texts a Twilio number (that will be configured with this Studio Flow), they will be asked what words they guessed. We check their input using a <em>Split Based On...</em> widget that uses regex to make sure they only sent five-letter words separated by commas and if they did, we set a variable called <em>guesses</em>.
![transitions of split based on...widget](https://twilio-cms-prod.s3.amazonaws.com/images/7uvaedtU1EXA-EitVdCAuzEtPy49O7sK1KGwqvl-7vyoiD.width-500.png)
Else, the flow goes back to the initial <em>Send and Wait for Reply</em> widget to ask them what they guessed again. Then the Flow asks for their green squares and yellow squares, with similar corresponding conditional widgets using more regex. If the user sent a "!" to represent no yellow squares, we replace that with an empty string to pass to the Datamuse API to return possible Wordle words based on the green and yellow square input using a <em>Run Function</em> widget.
![run function widget](https://twilio-cms-prod.s3.amazonaws.com/images/tzYh3-yOSJBm_gP6Uz4Us4l7IP-Q5FT8rlxpY10RC32Dfl.width-500.png)
My widget config looks like this:
![run function widget config](https://twilio-cms-prod.s3.amazonaws.com/images/xpagqEpNtXEpjxAgOjKOZsp_Ms9uvWweOUxf2aUZh4Guq-.width-500.png)
We also pass our Twilio Function either the variables we set or the user input as Function parameters:
![function parameters](https://twilio-cms-prod.s3.amazonaws.com/images/wGWT7WOOv257dkMPvq4LMG5J_RG8oLBlFgaZiEClqWlSQx.width-500.png)
We then send a message from Twilio Studio with the words returned from the Datamuse API and check if whatever the user guessed was the correct Wordle word. If it was, they receive a <em>congrats</em> message. Else, the Studio Flow asks what they guessed and adds it to the <em>guesses</em> variable in Studio before going back up to ask what their green squares are again. This flow should run until the user has solved Wordle!
### Configure the Studio Flow with a Twilio Phone Number
In the [phone numbers section of your Twilio Console](https://www.twilio.com/console/phone-numbers/incoming), select the Twilio number you purchased and scroll down to the <em>Messaging</em> section. Under <em>A MESSAGE COMES IN</em> change <em>Webhook</em> to <em>Studio Flow</em> and select <em>wordle-solver</em> (or whatever you named your Studio Flow.)
![a message comes in is configured with our wordle-solver studio flow](https://twilio-cms-prod.s3.amazonaws.com/images/e16gQ-cWe6rahE-G4xd8SbeoGS3TcVm_e4Z6Yc85popHOh.width-500.png)
Test it by texting anything to your Twilio number! You can use it [during your daily Wordle game](https://www.nytimes.com/games/wordle/index.html) or [you can also make your own Wordle here](https://mywordle.strivemath.com/).
![gif of sms example of wordle solver](https://twilio-cms-prod.s3.amazonaws.com/original_images/wordlesolver.gif)
### What's Next for Twilio Serverless, Studio, and Word Games?
Twilio Studio blew my mind. You can use it to:
- Handle state
- Parse complex conditional statements with regex
- Seamlessly integrate with Twilio Functions

Thank you so much to Craig for constantly improving the app and teaching me and so many others what we could use Studio for.