Quantcast
Channel: Rock-Paper-Scissors-Lizard-Spock Challenge - Code Review Stack Exchange
Viewing all articles
Browse latest Browse all 5

Rock-Paper-Scissors-Lizard-Spock Challenge

$
0
0

"Scissors cuts paper, paper covers rock, rock crushes lizard, lizard poisons Spock, Spock smashes scissors, scissors decapitate lizard, lizard eats paper, paper disproves Spock, Spock vaporizes rock. And as it always has, rock crushes scissors."

-- Dr. Sheldon Cooper

So these are the rules.

Building blocks

The first thing I thought was "I need a way to compare the possible selections" - this sounded like IComparable<T>, so I started by implementing that interface in a SelectionBase class. Now because I knew I'd derive Rock, Paper, Scissors, Lizard and Spock classes from this, I decided to include a Name property that returns the type name, and since I also needed a way to display different verbs depending on the type of the opponent's selection, I also included a GetWinningVerb method:

public abstract class SelectionBase : IComparable<SelectionBase>{    public abstract int CompareTo(SelectionBase other);    public string Name { get { return GetType().Name; } }    public abstract string GetWinningVerb(SelectionBase other);}

The base class is implemented by each of the possible selections:

public class Rock : SelectionBase{    public override string GetWinningVerb(SelectionBase other)    {        if (other is Scissors) return "crushes";        if (other is Lizard) return "crushes";        throw new InvalidOperationException("Are we playing the same game?");    }    public override int CompareTo(SelectionBase other)    {        if (other is Rock) return 0;        if (other is Paper) return -1;        if (other is Scissors) return 1;        if (other is Lizard) return 1;        if (other is Spock) return -1;        throw new InvalidOperationException("Are we playing the same game?");    }}public class Paper : SelectionBase{    public override string GetWinningVerb(SelectionBase other)    {        if (other is Rock) return "covers";        if (other is Spock) return "disproves";        throw new InvalidOperationException("Are we playing the same game?");    }    public override int CompareTo(SelectionBase other)    {        if (other is Rock) return 1;        if (other is Paper) return 0;        if (other is Scissors) return -1;        if (other is Lizard) return -1;        if (other is Spock) return 1;        throw new InvalidOperationException("Are we playing the same game?");    }}public class Scissors : SelectionBase{    public override string GetWinningVerb(SelectionBase other)    {        if (other is Paper) return "cuts";        if (other is Lizard) return "decapitates";        throw new InvalidOperationException("Are we playing the same game?");    }    public override int CompareTo(SelectionBase other)    {        if (other is Rock) return -1;        if (other is Paper) return 1;        if (other is Scissors) return 0;        if (other is Lizard) return 1;        if (other is Spock) return -1;        throw new InvalidOperationException("Are we playing the same game?");    }}public class Lizard : SelectionBase{    public override string GetWinningVerb(SelectionBase other)    {        if (other is Paper) return "eats";        if (other is Spock) return "poisons";        throw new InvalidOperationException("Are we playing the same game?");    }    public override int CompareTo(SelectionBase other)    {        if (other is Rock) return -1;        if (other is Paper) return 1;        if (other is Scissors) return -1;        if (other is Lizard) return 0;        if (other is Spock) return 1;        throw new InvalidOperationException("Are we playing the same game?");    }}public class Spock : SelectionBase{    public override string GetWinningVerb(SelectionBase other)    {        if (other is Rock) return "vaporizes";        if (other is Scissors) return "smashes";        throw new InvalidOperationException("Are we playing the same game?");    }    public override int CompareTo(SelectionBase other)    {        if (other is Rock) return 1;        if (other is Paper) return -1;        if (other is Scissors) return 1;        if (other is Lizard) return -1;        if (other is Spock) return 0;        throw new InvalidOperationException("Are we playing the same game?");    }}

User Input

Then I needed a way to get user input. I knew I was going to make a simple console app, but just so I could run unit tests I decided to create an IUserInputProvider interface - the first pass had all 3 methods in the interface, but since I wasn't using them all, I only kept one; I don't think getting rid of GetUserInput(string) would hurt:

public interface IUserInputProvider{    string GetValidUserInput(string prompt, IEnumerable<string> validValues);}public class ConsoleUserInputProvider : IUserInputProvider{    private string GetUserInput(string prompt)    {        Console.WriteLine(prompt);        return Console.ReadLine();    }    private string GetUserInput(string prompt, IEnumerable<string> validValues)    {        var input = GetUserInput(prompt);        var isValid = validValues.Select(v => v.ToLower()).Contains(input.ToLower());        return isValid ? input : string.Empty;    }    public string GetValidUserInput(string prompt, IEnumerable<string> validValues)    {        var input = string.Empty;        var isValid = false;        while (!isValid)        {            input = GetUserInput(prompt, validValues);            isValid = !string.IsNullOrEmpty(input) || validValues.Contains(string.Empty);        }        return input;    }}

The actual program

class Program{    /*"Scissors cuts paper, paper covers rock,          rock crushes lizard, lizard poisons Spock,          Spock smashes scissors, scissors decapitate lizard,          lizard eats paper, paper disproves Spock,          Spock vaporizes rock. And as it always has, rock crushes scissors."                                                          -- Dr. Sheldon Cooper    */    static void Main(string[] args)    {        var consoleReader = new ConsoleUserInputProvider();        var consoleWriter = new ConsoleResultWriter();        var game = new Game(consoleReader, consoleWriter);        game.Run();    }}

IResultWriter

public interface IResultWriter{    void OutputResult(int comparisonResult, SelectionBase player, SelectionBase sheldon);}public class ConsoleResultWriter : IResultWriter{    public void OutputResult(int comparisonResult, SelectionBase player, SelectionBase sheldon)    {        var resultActions = new Dictionary<int, Action<SelectionBase, SelectionBase>>        {            { 1, OutputPlayerWinsResult },            { -1, OutputPlayerLosesResult },            { 0, OutputTieResult }        };        resultActions[comparisonResult].Invoke(player, sheldon);    }    private void OutputPlayerLosesResult(SelectionBase player, SelectionBase sheldon)    {        Console.WriteLine("\n\tSheldon says: \"{0} {1} {2}. You lose!\"\n", sheldon.Name, sheldon.GetWinningVerb(player), player.Name);    }    private void OutputPlayerWinsResult(SelectionBase player, SelectionBase sheldon)    {        Console.WriteLine("\n\tSheldon says: \"{0} {1} {2}. You win!\"\n", player.Name, player.GetWinningVerb(sheldon), sheldon.Name);    }    private void OutputTieResult(SelectionBase player, SelectionBase sheldon)    {        Console.WriteLine("\n\tSheldon says: \"Meh. Tie!\"\n");    }

The actual game

I didn't bother with building a complex AI - we're playing against Sheldon Cooper here, and he systematically plays Spock.

public class Game{    private readonly Dictionary<string, SelectionBase> _playable =        new Dictionary<string, SelectionBase>            {                { "1", new Rock() },                { "2", new Paper() },                { "3", new Scissors() },                { "4", new Lizard() },                { "5", new Spock() }            };    private readonly IUserInputProvider _consoleInput;    private readonly IResultWriter _resultWriter;    public Game(IUserInputProvider console, IResultWriter resultWriter)    {        _consoleInput = console;        _resultWriter = resultWriter;    }    public void Run()    {        while (true)        {            LayoutGameScreen();            var player = GetUserSelection();            if (player == null) return;            var sheldon = new Spock();            var result = player.CompareTo(sheldon);            _resultWriter.OutputResult(result, player, sheldon);            Pause();        }    }    private void Pause()    {        Console.WriteLine("\nPress <ENTER> to continue.");        Console.ReadLine();    }    private void LayoutGameScreen()    {        Console.Clear();        Console.WriteLine("Rock-Paper-Scissors-Lizard-Spock 1.0\n{0}\n", new string('=', 40));        foreach (var item in _playable)            Console.WriteLine("\t[{0}] {1}", item.Key, item.Value.Name);        Console.WriteLine();    }    private SelectionBase GetUserSelection()    {        var values = _playable.Keys.ToList();        values.Add(string.Empty); // allows a non-selection        var input = _consoleInput.GetValidUserInput("Your selection? <ENTER> to quit.", values);        if (input == string.Empty) return null;        return _playable[input];    }}

Output

  • Rock: "Spock vaporizes Rock. You lose!"
  • Paper: "Paper disproves Spock. You win!"
  • Scissors: "Spock smashes Scissors. You lose!"
  • Lizard: "Lizard poisons Spock. You win!"
  • Spock: "Meh. Tie!"

Viewing all articles
Browse latest Browse all 5

Latest Images

Trending Articles





Latest Images