loading...
Cover image for Rock, Paper, Scissors - Scala

Rock, Paper, Scissors - Scala

darbyo profile image Rob Darby ・4 min read

I recently began creating a Rock, Paper, Scissors, Dynamite, Waterbomb bot (RPSDW). The conventional rules of RPS apply, with the addition that Dynamite beats everything except Waterbomb and Waterbomb loses to everything except Dynamite. In this post, I will be covering the scenario of this kata, the process that was followed and the results of the bot battle.

The scenario

At our dev community meeting, we usually come up with a small kata that people can complete in a couple of hours. On this occasion, it was decided that we were going to do something substantially bigger. Each team was tasked with going away and producing a bot that plays RPSDW against other bots; with the idea that we would come back in a few weeks and pit all of the bots against each other in a tournament.

The rules of the competition were each team would play each other once and the outcome of the match would result in 3 points for a win, 1 for a draw and, of course, 0 for a loss. The bots would need to be fully automated and, once set off, should play each other over as many games needed with first to win 1000 hands taking the points. Finally, each team would receive 100 Dynamites to be used at will.

The process

The interesting part of this project was that we used our whole team to create this bot; with our devs, testers, business analyst and scrum master all getting stuck into the code. Mob-programming the whole project, we got together for an hour every Friday afternoon where we would plug into the big screen and get to work. With two chairs at the front and the rest observing, one person would write a unit test, the next would fix it and then write another. We would then rotate. This meant that everyone in the team, no matter their role or experience, got an equal share of this project.

Getting started

When creating the bot, we decided to use the technology stack most relevant to our job role. We used Scala with Play framework, Git for version control and Heroku to deploy. This was a great learning curve for all as we were able to take the whole project from nothing to a working app in a public environment; something that not everyone had experienced before.

Building the bot

We started by setting up our project and considered implementing AI and Machine Learning; we soon realised that this was a little optimistic. However, we did still implement some sort of intelligence into the bot. We came up with the concept of a 'Guesstimater' which would use different methods to try and predict patterns in the hands that the opposing bots were playing. We had varied levels of depth in our Guesstimater methods. Starting with a simple method that counted all of the previous hands in the game, found the most common hand and played the hand that beat this. We also implemented a method that would use Game theory to try and beat our opponents. Obviously, we made a Game theory defence method to counter any of our opponents who may have attempted implementing this common RPS technique.

Albeit, after initially sounding very confusing and taking a lot of head-mangling possibilities, the Game theory defence came down to simply returning the opponents previous move.

def predict(play: Play) = {
    if(play.result.contains(Result.DRAW)) random.getGuess else play.opponentMove.get
  }

For our Guesstimater to work, we made some patterns to decide when it would change the method is was going to use. We decided to check for losingAll, losingMost and draws; which meant that we would constantly check the state of the game and if losing 5 of the last 5 hands, 6 of the last 10 or 7 of the last 14 we would switch methods. This meant that winning methods would be used for longer and losing methods changed after as little as 5 hands.

Finishing touches

After finishing our bot, we needed to host it somewhere so that the rps-frontend app could make requests to our bot and provide a GUI for the match. We chose Heroku for this; a tool that none of us had experience with. This was a great decision; two commands and the Heroku app is created and deployed.

The results

On game day, we got off to a great start in the league winning our first 3 games comfortably. We sat in 1st place with a massive points difference over everyone; even with playing one game less than the closest rivals. With two games left, we were confident. We then played the team that was last in the league (with no points) and suffered a shock defeat. The final game of the day happened to be the decider. It was us in 1st place playing the team in 2nd - winner takes all. We started the frontend and watched the progress bar go to and fro between the two teams. It was neck and neck until the very end where the other team won by around 20/30 hands (a small margin, over ~2000 hands).

They beat us by such a small margin and we were keen to know our mistakes. It turns out we had missed what turned out to be a crucial rule; if there was a draw, then the winner of the next hand won a point for that hand and the previous. The other team had implemented nothing but a random method that detected a draw and, thus, played a Dynamite in the following hand to which our Guesstimaster just couldn't pick up on. When picking hands 1 of 5, there is a good chance of a few draws. I believe this was enough for them to take the win.

In our next iteration, we will be accounting for this...

You can see our finished bot @ RPS Bot

Discussion

pic
Editor guide