Categories
algorithm Arduino software

Rock/Paper/Scissors Arduino Game

Rock/Paper/Scissors (RPS) is a game using simple rules and a circular winning strategy that I thought would be interesting to code. Additionally, there is an element of suspense/anticipation to the game that adds to its enjoyment, and I challenged myself with trying to capture this part of the experience as well.

So, during a few of the many recent rainy days I decided to spend some time seeing what I could do with an Arduino Uno, some tact switches and a few LED matrix modules.

All the code and supporting materials are available as the MD_MAX72xx_RPS_Game example of the MD_MAX72xx library.

Rules of the Game

I expect that most readers are familiar with this game, so here is a brief summary of the rules.

RPS is a hand game usually played between two people in which each player simultaneously forms one of three shapes with their hand. These shapes are a closed fist, a flat hand, and a fist with index and middle fingers forming a V (representing rock, paper and scissors respectively).

The game has three possible outcomes – win, draw or loss – based on the following simple rules:

  • Rock beats scissors (rock ‘breaks’ scissors).
  • Paper beats rock (paper ‘covers’ rock).
  • Scissors beats paper (scissors ‘cuts’ paper).
  • If both players form the same shape the result is a draw.

When the game is played with more than two players, everyone in the group plays their hand as in the two-player game, but the result is determined by the following additional rules:

  • Everyone plays again if all shapes are the same or all three shapes are shown (ie, 1 shape or 3 shapes are shown).
  • If only two shapes are showing, the rules for two players are applied to each group’s shape and players in the winning group remain in the game.
  • When only two players remain, the rules revert to the normal two-player game.

An important aspect of the game experience is the countdown (1, 2, 3 or Ready, Set, Go) before each player simultaneously shows their hand, followed by the quick survey of hands to determine the winner.

Hardware

To keep things really simple, each player has three to select the shape they choose for the next turn (R, P or S). These switches don’t need to be debounced as we are only interested in knowing the switch has been activated. Once this is detected, the player’s turn is complete until the next run of the game. This implementation allows up to four players and so needs 12 switches.

Gameplay is displayed on 8×8 LED modules, one module per player. The displays are connected using the hardware SPI interface and managed by the MD_MAX72xx library.

The photo below shows the setup using my prototyping system (described in this earlier post) connected to an Arduino Uno.

Programming

Breaking it Down

For the purposes of organizing the play sequence, each play session is divided into 3 separate parts.

  1. A Session is the entire sequence from when the processor is reset to the next time it is reset. The number of players (between 1 and 4) is selected at the start of the session and is fixed for its duration.
  2. A Game is a sequence of Runs (defined below) that result in one winner. At the end of a Game the winner is shown on the display and a new Game is started.
  3. A Run is a sequence of player turns. When multiple players are involved, individuals may be excluded from the succeeding Runs until the end of a Game, at which time they are start participating again.

The LED displays show a sequence of symbols to direct the game and some basic animation to convey status.

The icon (glyphs) used are managed as characters in a MD_MAX72xx font definition. The small number of resources required were designed using a Microsoft Excel spreadsheet.

Glyph Design

The use of an Excel sheet is a variation on the technique discussed here.

Cells in the sheet were conditionally formatted to show a red ‘LED’ icon when the cell is 1 and an empty ‘LED’ when 0. A spreadsheet formula creates the numeric for each column and another formula concatenates the codes into a cut-and-paste format for the font definition. These are shown in the image below.

This method makes it easy to visualize and create the data for LED patterns, especially when only a few bitmaps are needed. The spreadsheet is included with the code. (Yes, the scissors are impossible …)

Flow and Interaction

The game sequencing is organized as a finite state machine implemented in the loop() function.

Session Initialization

The Session phase is used to initialize the number of players. The Rock switch for Player 1 is used to cycle through choices for 1P, 2P, 3P or 4P to select the number of human players. The selection is completed when either of the other 2 switches are pressed.

If 1P is selected, the Arduino becomes the second player and will automatically takes its turn after a countdown.

Switches for unused players are not scanned for the duration of the Session and their associated displays remain blank.

Game Initialization

A Game encapsulates a number of Runs. At the start of a Game all valid players are initialized to their start state. Group players that may have been excluded during the previous Runs are brought back into the new Game.

Run Cycle

The Run cycle are where most of the game interactions occur.

The start of a Run is a Ready/Set/Go display where all valid player’s displays show an animated square decreasing in size until it is at the center.

At that point, the players are allowed to make their choice using one of their RPS switches. As each player makes their choice the center dot display expands into a square (both shown in the image below) so that all players can keep track of progress.

This simple countdown and animation sequence is quite effective at capturing the feeling of an actual game’s Ready/Set/Go phase.

Once all players have made their choice, the outcome of the game is simultaneously displayed to all players (shown below).

For a 2-player game, if the Run results in a winner, the winning player’s display is flashed a number of times and a new Game is started.

For multi player games, the result of a Run meets the criteria for a winning group, all the players in the losing group are excluded from further runs and their displays show an ‘X’ to indicate this exclusion. The remaining players then participate in the next Run.

Keeping Track of Players

As well as game sequencing, players are managed by being in assigned status during play:

  • Unused if the player was not selected for the Session. For example, players 3 and 4 of a 2 player game.
  • Neutral if they are participating in a Run before a result.
  • A Winner, Loser or Drawn once a run is completed and a result is determined.
  • Out of the game and not able to participate in a Run.

Any player that loses during a Run is categorised as out at the end of the run. A Game ends when only one player remains not out.

Leave a comment