Skip to content

Instantly share code, notes, and snippets.

@geoff-m
Last active April 20, 2021 07:58
Show Gist options
  • Save geoff-m/7ff37fae4efc6645fc42ed8f8f2dad2e to your computer and use it in GitHub Desktop.
Save geoff-m/7ff37fae4efc6645fc42ed8f8f2dad2e to your computer and use it in GitHub Desktop.
How to tell who wins in rock paper scissors
enum RockPaperScissorsChoice
{
Rock = 1,
Paper = 2,
Scissors = 4
}
static string DescribeRockPaperScissorsResult(RockPaperScissorsChoice first, RockPaperScissorsChoice second)
{
if (first == second)
return "Tie.";
if ((((int)first >> 1) | ((int)first << 2) & 5) == (int)second)
return $"{first} beats {second}.";
return $"{second} beats {first}.";
}
static void Test() {
Assert(RockPaperScissorsChoice.Rock, RockPaperScissorsChoice.Rock, "Tie.");
Assert(RockPaperScissorsChoice.Rock, RockPaperScissorsChoice.Paper, "Paper beats Rock.");
Assert(RockPaperScissorsChoice.Rock, RockPaperScissorsChoice.Scissors, "Rock beats Scissors.");
Assert(RockPaperScissorsChoice.Paper, RockPaperScissorsChoice.Rock, "Paper beats Rock.");
Assert(RockPaperScissorsChoice.Paper, RockPaperScissorsChoice.Paper, "Tie.");
Assert(RockPaperScissorsChoice.Paper, RockPaperScissorsChoice.Scissors, "Scissors beats Paper.");
Assert(RockPaperScissorsChoice.Scissors, RockPaperScissorsChoice.Rock, "Rock beats Scissors.");
Assert(RockPaperScissorsChoice.Scissors, RockPaperScissorsChoice.Paper, "Scissors beats Paper.");
Assert(RockPaperScissorsChoice.Scissors, RockPaperScissorsChoice.Scissors, "Tie.");
}
static void Assert(RockPaperScissorsChoice first, RockPaperScissorsChoice second, string expected)
{
var actual = DescribeRockPaperScissorsResult(first, second);
if (actual == expected)
Debug.WriteLine($"PASS Expected: {expected} \tActual: {actual}");
else
Debug.Fail($"FAIL Expected: {expected} \tActual: {actual}");
}
@geoff-m
Copy link
Author

geoff-m commented Apr 20, 2021

Theory of operation

As any schoolchild will tell you, the possible outcomes of a rock-paper-scissors game are described by a directed cyclic graph on three vertices, where each player choice is a vertex and the edges connect each choice to what it beats, or alternatively, to what beats it. Starting with such a graph, determining the winner between choices X and Y can then be done by following the edge from X and checking whether it takes you to Y. If it does, X wins (or X loses, depending on how you defined the graph). If X = Y, the outcome is a tie. If following the edge from X did not lead to Y and there was no tie, then Y must beat X (or X wins, depending on how you defined the graph). The funny idea that led to this code was to realize this traversal of the cycle using a bitwise rotation of a 3-bit integer. I submit it as a simultaneously obfuscated and succinct solution to this well-known toy problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment