RPSSL resolution logic#
How do we determine which player has won?
In other words, how do we resolve different situations into win, lose, and tie?
Analyzing an easier game: Rock paper scissors#
If we have only rock πͺ¨ paper ποΈ and scissors βοΈ, then we have 9 combinations for player 1 and player 2 named as p1 and p2, respectively.
| p1 | p2 | p1 β¦ | 
|---|---|---|
| πͺ¨ | πͺ¨ | tie | 
| πͺ¨ | ποΈ | loses | 
| πͺ¨ | βοΈ | wins | 
| ποΈ | πͺ¨ | wins | 
| ποΈ | ποΈ | tie | 
| ποΈ | βοΈ | loses | 
| βοΈ | πͺ¨ | loses | 
| βοΈ | ποΈ | wins | 
| βοΈ | βοΈ | tie | 
- How would you implement this in C? 
- Do you see any simplifications on the table that leads to less rows? 
After simplification we end up with:
| p1 | p2 | p1 β¦ | 
|---|---|---|
| πͺ¨ | ποΈ | loses | 
| πͺ¨ | βοΈ | wins | 
| ποΈ | πͺ¨ | wins | 
| ποΈ | βοΈ | loses | 
| βοΈ | πͺ¨ | loses | 
| βοΈ | ποΈ | wins | 
| else | tie | 
As a result, we have 3 * 3 - 3 = 6 if-else if lines with Boolean expressions and one else line.
Activity 29 (RPS resolution logic)
- 3 min. Draw a flowchart for the resolution table above. 
- Implement it using the template below: - 3 min. using - if-else
- 3 min. using - switch
 
- Which solution do you prefer? - if-else
- switch
 
#include <stdio.h>
enum { ROCK, PAPER, SCISSORS, SHAPE_COUNT } p1, p2;
const char *SHAPE_STRINGS[] = {"πͺ¨", "οΈποΈ", "βοΈ"};
int main() {
  for (size_t p1 = 0; p1 < SHAPE_COUNT; ++p1) {
    for (size_t p2 = 0; p2 < SHAPE_COUNT; ++p2) {
      printf("If p1: %s  and p2: %s  => ", SHAPE_STRINGS[p1],
             SHAPE_STRINGS[p2]);
      // YOUR CODE HERE
    }
    puts("");
  }
}
The output should be:
If p1: πͺ¨  and p2: πͺ¨  => Tie.
If p1: πͺ¨  and p2: οΈποΈ  => p1 looses.
If p1: πͺ¨  and p2: βοΈ  => p1 wins.
If p1: οΈποΈ  and p2: πͺ¨  => p1 wins.
If p1: οΈποΈ  and p2: οΈποΈ  => Tie.
If p1: οΈποΈ  and p2: βοΈ  => p1 looses.
If p1: βοΈ  and p2: πͺ¨  => p1 looses.
If p1: βοΈ  and p2: οΈποΈ  => p1 wins.
If p1: βοΈ  and p2: βοΈ  => Tie.
Important
switch only works with integers. You cannot use it with arrays like:
switch (player_tuple) {
  case {ROCK, SCISSORS}:
    ... 
}
Moving on to πͺ¨βοΈποΈπ¦π#
In our problem we have five different items. This corresponds to 5 * 5 - 5 + 1 = 21 if-else if-else lines. This is too long. A better idea is to analytically describe the win-lose table:
Fig. 14 rock paper scissors lizard Spock resolution diagram
 CC BY-SA 3.0. By DMacks (talk). Source: Wikimedia Commons#
Let us try to extract a pattern from the resolution diagram in Fig. 14. Assume that clock-wise rotation is a forwards direction.
In the diagram we see that Spock wins against scissors and stone, which are +1 and +3 forward in the circle. Spock loses against lizard and paper, which are +2 and +4 forward in the circle. In other words, if the second shape is +1 and +3 away, Spock wins, and if the second shape is +2 and +4 shapes away, then Spock loses.
Does the rule described above apply to all shapes? Why?
Describing the resolution using the distance between shapes#
If we generalize our rule for all items, we get:
If the second item is +1 or +3 away, then the first item wins. If the second item is +2 or +4 away, then the first item loses.
How can we determine if the second item is +1 or +3 away, i.e the distance? An idea is to attach numbers to all items, for example:
- Spock 
- scissors 
- paper 
- rock 
- lizard 
The numbers 0 to 4 become their ids. Now we can determine the distance by subtracting their ids.
Example: rock vs lizard. lizardβs id is 4, and rockβs id is 3, so we get 4-3=1, which means that rock wins against the lizard. The resolution diagram confirms this.
This approach can be summarized as a table, where id1 and id2 stand for the ids of the items.
| p2-p1 | p1 β¦ | 
|---|---|
| 0 | tie | 
| 1 or 3 | wins | 
| 2 or 4 | loses | 
This was too fast. Do you see any problems with this table?
Expanding the resolution table#
What happens if p1βs id is greater than p2βs id? Then we get negative numbers. For example for p1 = 4 and p2 = 0, we get p2 - p1 = -4. 4 means lizard and 0 Spock; and lizard wins against Spock.
We can look at the negative numbers from another perspective. -4 means a counter-clockwise turn, which is the same as if we moved 1 clockwise. So we can extend the table as follows:
| p2-p1 | p1 β¦ | 
|---|---|
| 0 | tie | 
| -4 or -2 or 1 or 3 | wins | 
| -3 or -1 or 2 or 4 | loses | 
Activity 30 (RPSSL resolution logic using difference between shapes)
Implement the resolution logic above either with
- if-else ...or
- switchstatement.
Two students with different approaches will demonstrate and we will compare.
Use the following template. Your output should be the same as the output below.
#include <stdio.h>
enum { SPOCK, SCISSORS, PAPER, ROCK, LIZARD, SHAPE_COUNT } player1, player2;
const char *SHAPE_STRINGS[] = {"π", "βοΈ", "οΈποΈ", "πͺ¨", "π¦"};
int main() {
  for (size_t player1 = SPOCK; player1 < SHAPE_COUNT; ++player1) {
    for (size_t player2 = SPOCK; player2 < SHAPE_COUNT; ++player2) {
      printf("If player1: %s  and player2: %s  => ", SHAPE_STRINGS[player1],
             SHAPE_STRINGS[player2]);
      // YOUR CODE HERE
    }
    puts("");
  }
}
If player1: π  and player2: π  => Tie.
If player1: π  and player2: βοΈ  => Player1 wins.
If player1: π  and player2: οΈποΈ  => Player1 looses.
If player1: π  and player2: πͺ¨  => Player1 wins.
If player1: π  and player2: π¦  => Player1 looses.
If player1: βοΈ  and player2: π  => Player1 looses.
If player1: βοΈ  and player2: βοΈ  => Tie.
If player1: βοΈ  and player2: οΈποΈ  => Player1 wins.
If player1: βοΈ  and player2: πͺ¨  => Player1 looses.
If player1: βοΈ  and player2: π¦  => Player1 wins.
If player1: οΈποΈ  and player2: π  => Player1 wins.
If player1: οΈποΈ  and player2: βοΈ  => Player1 looses.
If player1: οΈποΈ  and player2: οΈποΈ  => Tie.
If player1: οΈποΈ  and player2: πͺ¨  => Player1 wins.
If player1: οΈποΈ  and player2: π¦  => Player1 looses.
If player1: πͺ¨  and player2: π  => Player1 looses.
If player1: πͺ¨  and player2: βοΈ  => Player1 wins.
If player1: πͺ¨  and player2: οΈποΈ  => Player1 looses.
If player1: πͺ¨  and player2: πͺ¨  => Tie.
If player1: πͺ¨  and player2: π¦  => Player1 wins.
If player1: π¦  and player2: π  => Player1 wins.
If player1: π¦  and player2: βοΈ  => Player1 looses.
If player1: π¦  and player2: οΈποΈ  => Player1 wins.
If player1: π¦  and player2: πͺ¨  => Player1 looses.
If player1: π¦  and player2: π¦  => Tie.
