There are a million clones of Wordle, the guess-a-five-letter-word game. This post describes number a million and one, using, of course - MQTT.

Before I describe how it works, here is how to play. The game is hosted on test.mosquitto.org, and you need an MQTT client that can both publish and subscribe, and that can print emoji characters from the payload.

One client that can do this is mosquitto_rr, where "rr" is "request-response". This client subscribes to a topic, then sends a request message to a second topic and awaits a response and prints it out. In our case both request and response topics are the same. The request message we send is our first guess, and the response shows our result:

MQTT wordle round one

You see the round number, out of six, your guess with yellow/green highlighted letters indicating whether the letter was present but in the wrong place or in the correct place, plus the alphabet showing what letters you have used.

Play more rounds using the same command with different words until you win or lose:

MQTT wordle rounds two to four

There is only one game per day per IP address.

How does it work? The code is in a github repo. This implements a plugin for Mosquitto (for the develop branch only) which controls access to the wordle topic and processes messages for it.

The plugin registers to receive ACL events. In the event handler it returns MOSQ_ERR_PLUGIN_IGNORE for topics that are not exactly wordle, which tells the broker it is not handling those topics. For the wordle topic, it allows all subscribe and unsubscribe events. Publish events going to the client are all allowed. Publish events coming from the client are word guesses. Using the remote IP address as a key, we check to see if the client has made previous guesses for this word, to determine what round they are on or if they have won/lost already. This is a fairly crude control mechanism, but the game isn't intended as a serious production ready implementation.

After some data validation the plugin calculates the result, queues the response up to the sending client and crucially denies access to the publish sent from the client. This means we receive the publish it, process its payload and only after we are finished with it do we reject the message so it is not sent to other clients.

There are a few more details, but the ACL handler is the crux of the operation.

The word list was generated with something like:

grep '^[a-z]\{5\}$' /etc/dictionaries-common/words | shuf > words