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);
private readonly Winner _winner;
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)}");
Console.ReadLine();
}
}
}
}