Cooperative word-guessing in Scala
In our last Scala coding-dojo, we had some fun with word-guessing (think “hangman“, but without hanging anybody ;-).
The initial problem was like this: I brought game server (running on my laptop) and the task was to implement an interactive console-based client. A simple overview of the client logic can be illustrated like this:
Actually it was an Akka-based word-guessing server, for which I provided the bare-bones client project, which already came with the Akka-messages, the setup, and the message processing loop.
For those new to Akka, it translates to this: there is a game-server and all the clients connect to it. Client and server send each other “messages” over the network asynchronously. The messages are implemented in the form of simple case-classes:
// Request to participate in a game
case class RequestGame(playerName: String)
// Sent to the server to make a guess in the current game
case class MakeGuess(letter: Char)
// Reflects the (partial) status of a game. Unsolved letters are "None".
case class GameStatus(gameId: Int, letters: Seq[Option[Char]], remainingTries: Int)
abstract class GameOver
case class GameWon(finalStatus: GameStatus) extends GameOver
case class GameLost(finalStatus: GameStatus) extends GameOver // Sent when there are no more available games. Client should quit.
case class NoAvailableGames()
Given those messages, we can illustrate the message passing:
As I would have expected, the interactive client was done in no time. After 10 minutes or so all the pairs had finished their implementations and were already trying to guess some words.
This is where the surprise came in, as I connected my laptop to the beamer and showed this:
That’s right! The words for the individual games were actually coming from a larger text. I then revealed what the real goal of the dojo was, to:
…try to unfold the whole text, programmatically and together.
How so? There were two additional messages I previously didn’t focus on:
// Used to send a message to all other players
case class SendToAll(msg: String)
// Players get this message when talking to each other
case class MsgToAll(msg:String)
Using these two messages the clients could broadcast a String to all other clients.
Also something which I minimized at the beginning was the significance of the game-id, and its relation to the whole text. As you might have guessed the game-id was nothing more than the word-index within the text.
So, how to use this information and message-passing to solve the problem? The idea was to “share knowledge”. Clients would be communicating with each other about their successes and failures. Given a word that one client could not solve, the knowledge would be communicated about which letters worked and which didn’t. If another client got that word in the future, it would have much better chances of solving that word by relying on previous knowledge.
In short, a client would would ask itself: Do I have knowledge about the word? If so:
- Try the successful letters right away
- Avoid the letters known to fail
- Try letters still untried letters
- If the world is solved, bingo
- If it’s not, communicate what worked and what didn’t The results were pretty good: the pairs came up with a communication protocol and ultimately the problem was solved. Even by doing clever tricks like taking into account the probabilities of the letters given a word, or given the English language in general.
And while the code produced in such a rush would not have won a beauty contest (next dojo will focus on clean and idiomatic Scala), we had a lot of fun together. I certainly also had fun implementing the server, and learnt a lot (Akka, Play web-sockets) from the code it was based on.
If you are part of a Scala user-group, or just want to teach Scala, feel free to use/clone these projects (server/client word-guessing) if you also want to have fun word-guessing: