# Rock Paper Scissors without arrays and if-statements, how to reduce

As working on a little private programming challenge, I tried "Rock Paper Scissors" without arrays or if-statements. It works as intended, though, I am sure this can be done a little bit more optimized. Especially in the context of Math/Programming.

What I try to achieve:

• Create 2 Players, one Computer one Human.
• They both can make a Gesture (Rock, Paper or Scissors at Random or to Choose for the Human Player).
• The value of each Gesture is calculated into a Score
• The calculated Scores are calculated into a Winner of the Duel

The Players are two classes that implement an abstract class. The Winner and Gesture are Enums with specified values

The random Method just sets a random Gesture value for the player like:

 public void Random() => _gesture = (Gesture)_random.Next(0, 3);


The score for a single Hand is created as if it were points on a circle at 0, 120 and 240 degrees ((double)(_winner + 1) * 3 + (double)_gesture * 2) % 6 * Math.PI / 3;


The opposite hand is done the same, however, it starts at 180 degrees ( 180, 300, 60 degrees)

I try to find the position of both hands on the circle and calculate that into a unique value that results in a winner.

(Winner)(Math.Round(Math.Sin(other.Score() - this.Score())) * -(int)_winner);


This all works nice, however I suppose that the latter both rules could be reduced.

double Score() => ((double)(_winner + 1) * 3 + (double)_gesture * 2) % 6 * Math.PI / 3;
public Winner Duel(Player other) => (Winner)(Math.Round(Math.Sin(other.Score() - this.Score())) * -(int)_winner);


Complete code:

using System;

namespace RockPaperScissors
{
public enum Winner
{
Draw = 0,
Computer = -1,
Human = 1
}

public enum Gesture
{
Rock = 0,
Paper = 1,
Scissors = 2,
}

public abstract class Player
{
private static readonly Random _random = new Random(DateTime.Now.Millisecond);
protected Gesture _gesture;

protected Player(Winner winner)
{
_winner = winner;
}

public Gesture Gesture => _gesture;
public void Random() => _gesture = (Gesture)_random.Next(0, 3);
double Score() => ((double)(_winner + 1) * 3 + (double)_gesture * 2) % 6 * Math.PI / 3;
public Winner Duel(Player other) => (Winner)(Math.Round(Math.Sin(other.Score() - this.Score())) * -(int)_winner);
}

public class Computer : Player
{
public Computer() : base(Winner.Computer)  { }
}

public class Human : Player
{
public Human() : base(Winner.Human) { }
public void Choose(Gesture gesture) => _gesture = gesture;
}

class Program
{

static void Main(string[] args)
{
Computer computer = new Computer();
Human human = new Human();

for(int i = 0; i < 10; i ++)
{
computer.Random();
human.Random();

Console.WriteLine($"Computer does {computer.Gesture}, Human does {human.Gesture}"); Console.WriteLine($"Winner = {computer.Duel(human)}");
Console.WriteLine(\$"Winner = {human.Duel(computer)}");

}
}
}
}

• Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. Feel free to ask a new question instead, although I'd recommend waiting at least 24 hours between questions. More answers may be coming in.
– Mast
Apr 14, 2020 at 13:41

int a = _random.Next(0, 3);

There is no need to subtract angles in radians or degrees as you can simply use integers. Technically a - b is sufficient to determine the winner and + 4 % 3 - 1 wraps it to the -1/0/+1 interval.