DEV Community

Cover image for Everyday is an API day with Jotto 2020
Tony DeFusco
Tony DeFusco

Posted on • Edited on

Everyday is an API day with Jotto 2020

For my very first MuleSoft Hackathon, I decided to recreate a word puzzle game known as Jotto. The game engine is an API implemented in Mule 4 using DataWeave 2 scripts along with some encryption from the Mule Crypto module. The source code for the game API has been uploaded to GitHub and can be found here.

For the game's user interface, I created a simple web client using EnyoJS v2.7. The majority of my hours spent working on this hackathon were devoted to the web client (learning the basics of the EnyoJs JavaScript application framework and debugging my JavaScript code). The source code for the web client has been uploaded to GitHub and can be found here.

I created a free account with Fauna so that I could have an online document database at my disposal for persisting a small amount of game state data. I used FaunaDB's API to manage a running count of Jotto games played for each of the different word lengths. Persisted running counts are leveraged to ensure that a fresh word gets served up with each new game.

For the MuleSoft Hackathon, I created a free 30-day trial Anypoint Platform account to host the game's API along with the game's web client.

A demo of the Jotto 2020 game can be played online in your browser >>>>> right here <<<<<

Jotto 2020 demo video


To Build the Mule Application Project:

  1. Clone the Jotto 2020 API project from GitHub
  2. You may need to adjust the URLs of the two API endpoints.

In src/main/resources/web/jotto-2020.js (around line 615) is where the endpoint URLs for the Mule APIs are configured.

The "url" field for "newGameWebService" and "newGuessWebService" must be set appropriately for the web client to function.

    {
      kind: WebService,
      name: "newGameWebService",
...
      //url: "http://localhost:8081/api/game/jotto",
      url: "http://jotto2020.us-e2.cloudhub.io/api/game/jotto",
      method: "POST",
...
    },
    {
      kind: WebService,
      name: "newGuessWebService",
...
      //url: "http://localhost:8081/api/game/jotto/guess/",
      url: "http://jotto2020.us-e2.cloudhub.io/api/game/jotto/guess/",
      method: "PUT",
...
    },
Enter fullscreen mode Exit fullscreen mode
  1. Assuming the Mule application builds and deploys, you can access the web client in your browser with a URL that references the same host that is servicing the API. For example, if you are running the application in the standalone Mule 4 server and you have the endpoint URLs set to localhost, then you would browse to http://localhost:8081/ui/index.html.

API Endpoints

The Jotto 2020 API has two endpoints used to manage the game:

  • An API endpoint to request the game server to start a new game:

POST:/api/game/jotto?letters=n where n for the letters query parameter is an integer value between 2 and 12.

Sample JSON response body (a new game has started)

{
  "stats": {
    "puzzleUuid": "46b602ec-cf04-4d39-9b88-18a41c1318c1",
    "puzzleIndex": 109,
    "puzzleLength": 8,
    "maximumTurns": 6,
    "gameOver": false,
    "turnsRemaining": 6,
    "victory": false
  },
  "turnsTaken": [

  ],
  "token": "ewogICJzdGF0cyI6IHsKICAgICJwdXp6bGVVdWlkIjogIjQ2YjYwMmVjLWNmMDQtNGQzOS05Yjg4LTE4YTQxYzEzMThjMSIsCiAgICAicHV6emxlSW5kZXgiOiAxMDksCiAgICAicHpbXVtVHVybnMiOiAyMCwKICAgICJnYW1lT3ZlciI6IGZhbHNlLAogICAgInR1cm5zUmVtYWluaW5nIjogMjAsCiAgICAiV6emxlTGVuZ3RoIjogOCwKICAgICJtYXhdmljdG9yeSI6IGZhbHNlCiAgfSwKICAidG9rZW4iOiBudWxsLAogICJ0dXJuc1Rha2VuIjogWwogICAgCiAgXQp9"
}
Enter fullscreen mode Exit fullscreen mode
  • An API endpoint to submit a guess to the game server and receive feedback of the game's running state.

PUT:/api/game/jotto/guess/{guess} where guess is a word of the proper length (between 2 and 12 letters depending on the length requested when the game was started).

The PUT request must also include an HTTP header parameter named x-session which contains the value of the token field extracted from the most recent API response (the API will respond with an HTTP 400 status if the x-session HTTP header parameter is omitted). The x-session HTTP parameter and the token response body field together implement the mechanism used to maintain game state between client and server in a stateless manner.

Sample JSON response body (the final round of a winning game)

{
  "stats": {
    "puzzleUuid": "5b449db2-1aeb-4962-b7e8-ac913f5d38e5",
    "puzzleIndex": 106,
    "puzzleLength": 8,
    "maximumTurns": 6,
    "gameOver": true,
    "turnsRemaining": 0,
    "victory": true,
    "puzzleWord": "document"
  },
  "turnsTaken": [
    {
      "guess": "hooligan",
      "result": ".*.....o"
    },
    {
      "guess": "tonality",
      "result": "o*o....."
    },
    {
      "guess": "national",
      "result": "o.o.o..."
    },
    {
      "guess": "vocation",
      "result": ".**.o..o"
    },
    {
      "guess": "lockment",
      "result": ".**.****"
    },
    {
      "guess": "document",
      "result": "********"
    }
  ],
  "token": "ewogICJzdGF0cyI6IHsKICAgICJwdXp6bGVVdWlkIjogIjViNDQ5ZGIyLTFhZWItNDk2Mi1iN2U4LWFjOTEzZjVkMzhlNSIsCiAgICsKICAgICAgImd1ZXNzIjogImhvb2xpZ2FuIiwKICAgICAgInJlc3VsdCI6ICIuKi4uLi4ubyIKICAgIH0sCiAgICB7CiAgICAgICJndWVzcyI6ICJub3Rpb25hbCIsCiAgICAgICJyZXN1bHQiOiAibypvLi4uLi4iCiAgICB9LAogICAgewogICAgICAiZ3Vlc3MiOiAidG9uYWxpdHkiLAogICAgICAicmVzdWx0IjogIm8qby4uLi4uIgogICAgfSwKICAgIHsKICAgICAgImd1ZXNzIjogIm5hdGlvbmFsIiwKICAgICAgInJlc3VsdCI6ICJvLm8uby4uLiIKICAgIH0sCiAgICB7CiAgICAgAicHV6emxlSW5kZXgiOiAxMDYsCiAgICAicHV6emxlTGVuZ3RoIjogOCwKICAgICJtYXhpbXVtVHVybnMiOiAyMCwKICAgICJnYW1lT3ZlciI6IHRydWUsCiAgICAidHVybnNSZW1haW5pbmciOiAxMywKICAgICJ2aWN0b3J5IjogdHJ1ZQogIH0sCiAgInRva2VuIjogbnVsbCwKICAidHVybnNUYWtlbiI6IFsKICAgIHICJndWVzcyI6ICJ2b2NhdGlvbiIsCiAgICAgICJyZXN1bHQiOiAiLioqLm8uLm8iCiAgICB9LAogICAgewogICAgICAiZ3Vlc3MiOiAibG9ja21lbnQiLAogICAgICAicmVzdWx0IjogIi4qKi4qKioqIgogICAgfSwKICAgIHsKICAgICAgImd1ZXNzIjogImRvY3VtZW50IiwKICAgICAgInJlc3VsdCI6ICIqKioqKioqKiIKICAgIH0KICBdCn0="
}
Enter fullscreen mode Exit fullscreen mode

The puzzleWord field is only included in the response body when the gameOver field has a value of true. In the values of the "result" fields, the . denotes a non-matching letter, the o denotes a matching letter in the incorrect position, and the * denotes a matching letter in the correct position.


How to Play Jotto 2020

Jotto 2020 is a word puzzle game. The game server will select a secret English word between 2 and 12 letters; you get to select the word length.

The object of the game is to guess that secret word. Each guess you make will be answered by a report of the letters (or "jots") in the guess word that match or occur in the secret word.

You will also be told how many of the letters are in the correct position in the secret word.

Through a process of elimination, you should be able to deduce the correct letters using logic.

The number of allowed guesses to solve the secret word varies based on the length of the secret word. The minimum is five guesses.

  1. Start by selecting the number of letters for the mystery word via the number picker button on the top-left. You can select a mystery word as short as two letters, or as long as twelve letters.

  2. Type your test or guess word; it must be the same number of letters as the mystery word.

  3. After you have entered your guess word, click the "->" button on the on-screen keypad or press the "Enter" key on your computer's keyboard to submit your guess to the game server. Click the "<-" key on the keypad or press the backspace on your computer keyboard to erase the last entered letter of your guess. Click the "!" key on the keypad or press the "Esc" key on your computer keyboard to erase all of the letters of your guess.

  4. The game server will report which letters of your guess occur in the secret word and whether or not any of those letters are in the correct position.
    Yellow letters will be displayed for those letters that are in the secret word but are in the wrong position.
    Green letters will only be displayed for those letters that are both in the secret word and in the correct position.
    Red letters will be displayed for letters that do not exist in the secret word or for any extra copies of letters that have already been displayed as yellow or green letters.

For example:

If the secret 5-letter word is "radar"...

  ... and you guessed "arrow", 
  then the game server will report a result displayed as
  three yellow letters and two red letters.

  ... and you guessed "razor", 
  then the game server will report a result displayed as 
  three green letters and two red letters.

  ... and you guessed "raarr", 
  then the game server will report a result displayed as 
  four green letters and one red letter; the extra 'R' is 
  not in the secret word.
Enter fullscreen mode Exit fullscreen mode
  1. Continue submitting guesses to the game server until you correctly solve the mystery word or you run out of allowed guess attempts.

Parting Thoughts

The web client consumed way too much of the free time I budgeted for this hackathon, and as a result, this whole project was badly rushed to meet the submission deadline.

Some unfinished business remains:

  1. Remove trace log statements from web client code.
  2. Add more tool tips and prepare better help instructions in the web client.
  3. Employ better EnyoJS and JavaScript coding best practices by refactoring the web client source code to create reusable components.
  4. Enable HTTPS by requesting a proper TLS certificate for the host server's domain.
  5. Use the FaunaDB to persist more data for the game server.
  6. Do more play-testing. Are the minimum number of guesses enforced by the game server suitable for the different word lengths?
  7. Remedy the "uglify" compatibility bug in the node.js build script that is preventing a production build of the EnyoJS project.
  8. Figure out how to make the "x-session" HTTP header response parameter accessible to the web client. Currently, the "x-session" HTTP header parameter does not show up after invoking the getAllResponseHeaders() function in the browser's XMLHttpRequest response object. This is why the "token" field had to be included in the API's response body.
  9. Move the RAML out of the Mule 4 project and into Exchange, and then manage it with API Manager.
  10. Host the web client separately from the API? A proper web server would be best.
  11. Secure the API endpoints.
  12. I like using the different colors to provide visual feedback for qualifying a guess, but I do realize that an alternate feedback mechanism would be needed to accommodate players with color blindness.

Game enhancements:

  1. Add features to the game server such as player game history management; the game client could then be enhanced to display all time best scores and personal best scores, etc.
  2. Improve the game client and then convert it into a mobile application and/or standalone executable for PC or Mac.

Top comments (4)

Collapse
 
akaak profile image
AK Adapa

@tonedef71 this is an excellent post. Thanks for commenting on my post.
More folks should know about your work that predated now familiar Wordle!

You have all the pieces of the Wordle and I am sure you will come up with more in the future. Wish you the best.

Collapse
 
tonedef71 profile image
Tony DeFusco

Jotto 2020 is online to play (for a limited time only) to commemorate its debut two years ago.

7-letter game of Jotto 2020 in progress

Collapse
 
tonedef71 profile image
Tony DeFusco • Edited

Introduction

It is January 2022, and the recent explosion of public interest for Josh Wardle's Wordle game has inspired me to revisit my MuleSoft Hackathon 2020 submission page here and talk about Jotto 2020. Back in 2020/2021, I was hardly feeling any enthusiasm to talk about the game then: my entry placed poorly in the contest standings (somewhere in the bottom 50%); it did not earn an honorable mention -- or any mention for that matter. Apart from the MuleSoft Hackathon 2020 Dev.To page, my official contest entry page here is the only record, I believe, of my participation in that 2020 virtual hackathon.

Jotto 2020

Jotto 2020 was a labor of love for me. I first conceived of the idea to create a game that merged Jotto with the color-coded-hint mechanism of Mastermind back in 2013; I wanted to create the game as a mobile application to play on my HP TouchPad tablet. I wrote the rudiments of the application in JavaScript using the EnyoJS framework, but I never completed it.

The MuleSoft Virtual Hackathon 2020

The MuleSoft Hackathon 2020 was what motivated me to finally create the Jotto game I always wanted to play on my HP TouchPad. I have to thank Jordan Schuetz; for without his initial encouragement, I would have deemed my idea unworthy of pursuing as a contest submission (the Mule Invaders game that Jordan created to get folks excited about the Hackathon was fantastic and a bit intimidating in its impressiveness).

For the hackathon, I would approach development of the game differently this time, by leveraging my proficiency with the MuleSoft middleware platform:

  1. I would make it a web-only game; I might consider creating a mobile app at a later date
  2. I would code the game's engine as a server-side web API
  3. I would again utilize the EnyoJS framework, but this time I would code the UI as a web client

After my Jotto 2020 game debuted to the public, it failed to garner much public interest during the 30 days it was available to play online. I did nothing to promote it online; promotion of myself, or my work, is something which I have never been comfortable doing and was never very good at; I would be equally uncomfortable paying for a service to promote something I was giving away freely. I installed Jotto 2020 on my employer's sandbox Mule server so that I could play it regularly along with my colleagues; only a handful of them showed an interest in playing it along with me at that time.

Wordle

Wordle has captured the public's imagination in a way that Jotto 2020 never could. I tip my hat to Josh and his team; I really dig the UI he created for Wordle. Although visually similar to Jotto 2020, it is superior in a number of ways. The coloring of the keyboard to help players avoid choosing letters which have already been revealed as not being in the puzzle was a feature I had recently considered adding to Jotto 2020; Wordle already has that feature, and it is super useful! I believe Wordle has also implemented the feature to enforce that the guesses be valid five-letter words (by comparing to a robust list of five letter words). I had considered implementing that feature in Jotto 2020, but I thought it might be unwieldy to implement it for 3-letter, 4-letter, 6-letter, 7-letter, 8-letter, 9-letter, 10-letter, 11-letter, and 12-letter word puzzles as well.

My coworkers and I had been posting screenshots on Slack to each other of our Jotto 2020 games (the best wins and the toughest losses): Sharing Jotto 2020 scores on Slack

It just never occurred to me to add a mechanism to Jotto 2020 for sharing the results of a completed game. That "share" button feature Josh added to his Wordle game was a stroke of genius. I believe it was the killer feature which rocketed his game's audience from 90 dedicated players to over 2.5 million in just under a couple of months; that feature proved to be one heck of an effective grassroots, word-of-mouth momentum builder.

Josh Wardle

Josh seems like a developer after my own heart; we both created our word games simply for "the fun of it", and I am grateful to him for sharing Wordle with the world. By proxy, Wordle's success has given me a boost of pride: I now know that my quaint little word game truly had the potential to appeal to a broader, global audience, versus just a select handful of "word nerds" like myself at the office (which is what my personal experience had led me to believe).

The Next Evolution and Possible Future Collaboration

I still have some really fun ideas that could be implemented to take Wordle to the next level, and it would be a thrill for me to join forces with Josh and his team to share this next evolution of the game with all of the "Wordlers" out there. Unfortunately, I do not know the best way to connect with him. I did make a couple of attempts to engage with folks who might know how to reach him personally, but I really had no idea how to go about getting his attention, so I was ultimately unsuccessful.

Collapse
 
roystonlobo profile image
Royston Lobo

Thanks for your submission @tonedef71 !