packyVak
packyVak

Reputation: 29

Rock, Paper, Scissors in C#

I'm making a Rock, paper, scissors game in C# and am currently having trouble trying to display a message when someone enters an input that is not R, S, or P. For example, I am trying to get default in the switch statement to work, but am having no luck. This is what I currently have. If there's any other problems that I have made, please let me know.

using System;

namespace Rockpaperscissors
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputPlayer, Computer;
            int randomnum;
            string loop;
            bool keepPlaying = true;

            while (keepPlaying)
            {

                int wins = 0;
                int Loses = 0;
                int ties = 0;


                while (keepPlaying)
                {

                    Random myRandomObject = new Random();
                    randomnum = myRandomObject.Next(1, 4);
                    Console.Write("To play: enter R for Rock, S for Scissors, P for Paper.");
                    inputPlayer = Console.ReadLine();
                    inputPlayer = inputPlayer.ToUpper();

                    switch (randomnum)
                    {

                        case 1:
                            Computer = "Rock";
                            Console.WriteLine("The computer played Rock");
                            if (inputPlayer == "R")
                            {
                                Console.WriteLine("Tie!!\n\n");
                                ties++;
                            }
                            else if (inputPlayer == "P")
                            {
                                Console.WriteLine("You win!!\n\n");
                                wins++;
                            }
                            else if (inputPlayer == "S")
                            {
                                Console.WriteLine("Computer wins!!\n\n");
                                Loses++;
                            }
                            break;
                        case 2:
                            Computer = "Paper";
                            Console.WriteLine("The computer played Paper");
                            if (inputPlayer == "P")
                            {
                                Console.WriteLine("Tie!!\n\n");
                                ties++;
                            }
                            else if (inputPlayer == "R")
                            {
                                Console.WriteLine("Computer wins!!\n\n");
                                Loses++;
                            }
                            else if (inputPlayer == "S")
                            {
                                Console.WriteLine("You win!!\n\n");
                                wins++;
                            }
                            break;
                        case 3:
                            Computer = "Scissors";
                            Console.WriteLine("The computer played Scissors");
                            if (inputPlayer == "S")
                            {
                                Console.WriteLine("Tie!!\n\n");
                                ties++;
                            }
                            else if (inputPlayer == "R")
                            {
                                Console.WriteLine("You win!!\n\n");
                                wins++;
                            }
                            else if (inputPlayer == "P")
                            {
                                Console.WriteLine("Computer wins!!\n\n");
                                Loses++;
                            }
                            break;
                        default:                      
                            Console.WriteLine("Please enter a correct entry");  
                            break;
                    }

                    Console.WriteLine("Scores:\tWins:\t{0},\tLoses:\t{1},\tties:\t{2}", wins, Loses, ties);

                Console.WriteLine("Would you like to continue playing? (y/n)");
                loop = Console.ReadLine();
                if (loop == "y")
                {
                    keepPlaying = true;

                }
                else if (loop == "n")
                {
                    keepPlaying = false;
                }
                else
                {

                }

                }

            }

        }
    }
}

Please help!

Upvotes: 2

Views: 3805

Answers (5)

John Alexiou
John Alexiou

Reputation: 29244

This is my take on the RPS game and how to handle user inputs. Design wise, I defined a few enum types to describe different moves or outcomes.

public enum Move
{
    Rock,
    Scissors,
    Paper,
}

public enum Outcome
{
    Tie,
    Loss,
    Win,
}

Then I have two helper functions, one for handling the user input (the part the op had trouble with) and the other for deciding the game, because the op gives me a headache with all the repetition.

In the spirit of C# functions such as int.TryParse(string, out int); I designed the PlayerMove() function such that it returns true if successful, and fase otherwise. The actual result of the function is assigned to the out variable named move.

static class Program 
{
    static readonly Random rng = new Random();

    // .. Main() goes here ==============

    /// <summary>
    /// Parses user input and decides what move was chosen if any.
    /// </summary>
    /// <param name="input">The user input.</param>
    /// <param name="move">The user move (output).</param>
    /// <returns>False if a move wasn't selected, true otherwise.</returns>
    static bool PlayerMove(string input, out Move move)
    {
        input = input.Trim().ToUpper();
        move = 0;
        if (string.IsNullOrWhiteSpace(input) || input.Length==0)
        {
            return false;
        }
        switch (input[0])
        {
            case 'R':
                move = Move.Rock;
                return true;
            case 'P':
                move = Move.Paper;
                return true;
            case 'S':
                move = Move.Scissors;
                return true;
            default:
                return false;
        }
    }

    /// <summary>
    /// Pick which combinations of plays wins for player, has a tie or a loss.
    /// </summary>
    /// <param name="player">The player move.</param>
    /// <param name="computer">The computer move.</param>
    /// <returns>The outcome of the game [Tie,Win,Loss]</returns>
    static Outcome DecideGame(Move player, Move computer)
    {
        if (player==computer)
        {
            return Outcome.Tie;
        }
        else if ((player==Move.Rock && computer==Move.Scissors)
            || (player==Move.Scissors && computer==Move.Paper)
            || (player==Move.Paper && computer==Move.Rock))
        {
            return Outcome.Win;
        }
        else
        {
            return Outcome.Loss;
        }
    }
}

and now for the game itself to be placed above where // Main() goes here is indicated.

There a variable keepPlaying that keeps track of when to quit. The main game loop is a do { } while(keepPlaying); loop.

The steps are

  1. Prompt the user
  2. Computer chooses Move randomly
  3. Parse user input and assign player Move
  4. If the user did not make a valid move goto step 1
  5. If the user just pressed enter, then input contains an empty string and the game quits.
  6. Decide the outcome of the game
  7. Display the outcome and adjust win/tie/loss counts.

And the main code below to does the above:

    static void Main(string[] args)
    {
        bool keepPlaying = true;
        int wins = 0, losses = 0, ties = 0;
        do
        {
            Console.WriteLine();
            Console.WriteLine($"Win={wins}, Loss={losses}, Tie={ties}");
            Console.Write("To play: enter R for Rock, S for Scissors, P for Paper.");
            var input = Console.ReadLine();                   
            var computer = (Move)rng.Next(0, 3);
            // Parse input and decide if the user made a move
            // or wants to quit (invalid input or none).
            if (PlayerMove(input, out Move player))
            {
                Console.Write($"Player: {player}, Computer: {computer} => ");
                // Decide the outcome of the game here
                Outcome game = DecideGame(player, computer);
                switch (game)
                {
                    case Outcome.Tie:
                        ties++;
                        Console.WriteLine("Tie");
                        break;
                    case Outcome.Loss:
                        losses++;
                        Console.WriteLine("loss");
                        break;
                    case Outcome.Win:
                        wins++;
                        Console.WriteLine("Win");
                        break;
                    default:
                        throw new NotSupportedException();
                }
            }
            else
            {
                // stop when user just pressed enter.
                keepPlaying = input.Length>0;
            }
        } while (keepPlaying);
    }

Upvotes: 0

Bruno Assis
Bruno Assis

Reputation: 1006

If you prefer a more object oriented approach, below it's a small example.

usage: dotnet run "Your Name"

Program.cs

using System;

namespace RockPaperScissors
{
    partial class Program
    {
        static void Main(string[] args)
        {           
            StartGame(args);
        }

        static void StartGame(string[] args)
        {
            var playerName = (args.Length == 1) ? args[0] : "Player 1";         
            
            var player1 = new Player(playerName);
            var player2 = new ComputerPlayer();

            var game = new RPSGame(player1, player2);

            game.Init();

            while (true)
            {
                game.DisplayAvailablePlay();
                game.ReadPlayerInput();

                if (!game.IsValidPlay())
                    continue;

                game.Play();

                game.DisplayResult();
            }
            
        }
    }
}

RPSGame.cs

using System;

namespace RockPaperScissors
{
    internal partial class RPSGame
    {
        public RPSGame(Player firstPlayer, ComputerPlayer secondPlayer)
        {
            Player1 = firstPlayer;
            Player2 = secondPlayer;
        }

        internal GameStatus CurrentGameStatus = GameStatus.UnStarted;     
        internal int MatchDraws = 0;

        internal IPlayer Player1 { get; }
        internal IPlayer Player2 { get; }
        public IPlayer CurrentPlayer { get; private set; }
        public IPlayer Winner { get; private set; }


        internal void Init()
        {
            SetStatus(GameStatus.Started);
            SetCurrentPlayer(Player1);
            Console.CancelKeyPress += Console_CancelKeyPress;
        }

        public void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            this.SetStatus(GameStatus.Ended);
            e.Cancel = true;
            Environment.Exit(1);
        }

        internal void DisplayAvailablePlay()
        {
            Console.WriteLine("To play: enter R for Rock, S for Scissors, P for Paper.");
            Console.WriteLine("Press (Ctrl+C or Ctrl+Break) to Exit the game.");
        }

        internal void ReadPlayerInput()
        {
            var playerSelectedKey = Console.ReadKey(false);
            CurrentPlayer.SetSelectKey(playerSelectedKey.Key);
        }

        internal void DisplayResult()
        {
            if (Winner != null)
            {
                Console.WriteLine();
                Console.WriteLine("The Winner is:" + this.Winner.Name);
                Console.WriteLine("Played:" + GetDisplayName(this.Winner.SelectedKey));

            } else
            {
                Console.WriteLine("Draw!");
                Console.WriteLine("You both Played:" + GetDisplayName(this.Player1.SelectedKey));
            }
            Console.WriteLine($"Your Score: wins({Player1.AmountWins}), losses({Player1.AmountLoss}), draws({MatchDraws})");
        }

        private string GetDisplayName(ConsoleKey selectedKey)
        {
            return Enum.GetName(typeof(ConsoleKey), selectedKey);
        }

        internal void Play()
        {          
            ((ComputerPlayer)Player2).GenerateRandomChoice();
            SetWinner(Player1, Player2);
        }

        private void SetWinner(IPlayer player1, IPlayer player2)
        {
            var differenceInState = player1.SelectedKey - player2.SelectedKey;
            var generatedGameState = (GameState)Math.Abs(differenceInState);

            switch (generatedGameState)
            {
                case GameState.RockScissor:
                    Winner = (differenceInState < 0) ? player1 : player2;
                    break;
                case GameState.RockPaper:
                    Winner = (differenceInState < 0) ? player1 : player2;
                    break;
                case GameState.PaperScissor:
                    Winner = (differenceInState < 0) ? player2 : player1;
                    break;
                default:
                    Winner = null;
                    break;
            }

            UpdateStatistics();
            SetStatus(GameStatus.Ended);
        }

        private void UpdateStatistics()
        {
            if (Winner == Player1)
            {
                Player1.AmountWins++;
                Player2.AmountLoss++;
            }
            else if (Winner == Player2)
            {
                Player2.AmountWins++;
                Player1.AmountLoss++;
            }
            else
            {
                MatchDraws++;
            }
        }

        internal bool IsValidPlay()
        {
            switch (CurrentPlayer.SelectedKey)
            {
                case ConsoleKey.R:
                case ConsoleKey.P:
                case ConsoleKey.S:
                    return true;
            }
            return false;
        }

        private void SetCurrentPlayer(IPlayer currentPlayer)
        {
            this.CurrentPlayer = currentPlayer;
        }

        private void SetStatus(GameStatus status)
        {
            this.CurrentGameStatus = status;
        }

    }

}

BasePlayer.cs

using System;

namespace RockPaperScissors
{
    class BasePlayer :  IPlayer
    {
        public ConsoleKey SelectedKey { get; set; }
        public string Name { get; set; }
        public int AmountWins { get; set; }
        public int AmountLoss { get; set; }

        public void SetSelectKey(ConsoleKey playerSelectedKey)
        {
            SelectedKey = playerSelectedKey;
        }
    }

}

ComputerPlayer.cs

using System;

namespace RockPaperScissors
{
    class ComputerPlayer : BasePlayer
    {        
        public ComputerPlayer()
        {
            Name = "Computer Player";
            GenerateRandomChoice();
        }

        public void GenerateRandomChoice()
        {
            var rnd = new Random();
            var choice = rnd.Next(1, 4);
            switch(choice)
            {
                case 1:
                    SetSelectKey(ConsoleKey.R);
                    break;
                case 2:
                    SetSelectKey(ConsoleKey.P);
                    break;
                case 3:
                    SetSelectKey(ConsoleKey.S);
                    break;
            }
        }

    }

}

GameState.cs

namespace RockPaperScissors
{
    public enum GameState
    {
        RockScissor = 1,
        RockPaper = 2,
        PaperScissor = 3,
    }
}

GameStatus.cs

namespace RockPaperScissors
{
    public enum GameStatus
    {
        UnStarted = 0,
        Started = 1,
        Ended = -1
    }
}

IPlayer.cs

using System;

namespace RockPaperScissors
{
    interface IPlayer
    {
        public string Name { get; set; }

        public int AmountWins { get; set; }
        public int AmountLoss { get; set; }

        public ConsoleKey SelectedKey { get; set; }

        void SetSelectKey(ConsoleKey playerSelectedKey);
    }
}

Player.cs

using System;

namespace RockPaperScissors
{
    class Player : BasePlayer
    {        
        public Player(string name)
        {
            Name = name;
        }
    }
}

Upvotes: 0

Jamshaid K.
Jamshaid K.

Reputation: 4567

I would suggest to declare your valid moves in an array like this:

string[] validMoves = new string[3] { "R", "P", "S" };

then before your switch statement match if the user has given an input that is valid or not, if it is not valid then re-run the while loop, otherwise, continue to the switch statement. Something like below:

if (!validMoves.Contains(inputPlayer))
{
    Console.WriteLine("Please select a valid move.");
    continue;
}

This is how your main method should look like:
static void Main(string[] args)
{

    string inputPlayer, Computer;
    int randomnum;
    string loop;
    bool keepPlaying = true;
    string[] validMoves = new string[3] { "R", "P", "S" };
    int wins = 0;
    int Loses = 0;
    int ties = 0;
    while (keepPlaying)
    {
      // while (keepPlaying) // You can get rid of this while loop as it is not helping you out.
      // { // second while loop opening
            Random myRandomObject = new Random();
            randomnum = myRandomObject.Next(1, 4);
            Console.Write("To play: enter R for Rock, S for Scissors, P for Paper.");
            inputPlayer = Console.ReadLine();
            inputPlayer = inputPlayer.ToUpper();

            if (!validMoves.Contains(inputPlayer))
            {
                Console.WriteLine("Please select a valid move.");
                continue;
            }

            switch (randomnum)
            {
                case 1:
                    Computer = "Rock";
                    Console.WriteLine("The computer played Rock");
                    if (inputPlayer == "R")
                    {
                        Console.WriteLine("Tie!!\n\n");
                        ties++;
                    }
                    else if (inputPlayer == "P")
                    {
                        Console.WriteLine("You win!!\n\n");
                        wins++;
                    }
                    else if (inputPlayer == "S")
                    {
                        Console.WriteLine("Computer wins!!\n\n");
                        Loses++;
                    }
                    break;
                case 2:
                    Computer = "Paper";
                    Console.WriteLine("The computer played Paper");
                    if (inputPlayer == "P")
                    {
                        Console.WriteLine("Tie!!\n\n");
                        ties++;
                    }
                    else if (inputPlayer == "R")
                    {
                        Console.WriteLine("Computer wins!!\n\n");
                        Loses++;
                    }
                    else if (inputPlayer == "S")
                    {
                        Console.WriteLine("You win!!\n\n");
                        wins++;
                    }
                    break;
                case 3:
                    Computer = "Scissors";
                    Console.WriteLine("The computer played Scissors");
                    if (inputPlayer == "S")
                    {
                        Console.WriteLine("Tie!!\n\n");
                        ties++;
                    }
                    else if (inputPlayer == "R")
                    {
                        Console.WriteLine("You win!!\n\n");
                        wins++;
                    }
                    else if (inputPlayer == "P")
                    {
                        Console.WriteLine("Computer wins!!\n\n");
                        Loses++;
                    }
                    break;
                default: // You can get rid of this default block, it won't ever hit.
                    Console.WriteLine("Please enter a correct entry");
                    break;
            }

            Console.WriteLine("Scores:\tWins:\t{0},\tLoses:\t{1},\tties:\t{2}", wins, Loses, ties);

            Console.WriteLine("Would you like to continue playing? (y/n)");
            loop = Console.ReadLine();
            
            if (loop == "y")
            {
                keepPlaying = true;
            }
            else if (loop == "n")
            {
                keepPlaying = false;
            }
        // } // second while loop closing

    }
}

Upvotes: 2

Rufus L
Rufus L

Reputation: 37030

Here's a method I've used with console applications that helps a lot. I actually have several of them for getting types (like int or double) from the user. It takes in a prompt, which is displayed to the user and includes an optional validator method that it will run against the input to see if it's valid.

Here's one for string input:

public static string GetStringFromUser(string prompt, Func<string, bool> validator = null)
{
    var isValid = true;
    string result;

    do
    {
        if (!isValid)
        {
            WriteLineColor("Invalid input, please try again.", ConsoleColor.Red);
        }
        else isValid = false;

        Console.Write(prompt);
        result = Console.ReadLine();
    } while (validator != null && !validator.Invoke(result));

    return result;
}

In your case, you would simply call it like this:

string playerInput = GetStringFromUser(
    "To play: enter R for Rock, S for Scissors, P for Paper: ",
    x => x.ToUpper() == "R" || x.ToUpper() == "S" || x.ToUpper() == "P");

Console.WriteLine($"You entered: {playerInput}");

Console.Write("\nPress any key to continue...");
Console.ReadKey();

And here's the sample output:

enter image description here

Upvotes: 2

Luke Vo
Luke Vo

Reputation: 20678

While this does not directly answer your question, it should show the logic/flow for a program that requests user's input and asks again if they enter an invalid input.

            while (true)
            {
                Console.WriteLine("1. Print A then C");
                Console.WriteLine("2. Print B then C");
                Console.Write("Enter option: ");

                var input = Console.ReadLine();
                switch (input)
                {
                    case "1":
                        Console.WriteLine("A");
                        break;
                    case "2":
                        Console.WriteLine("B");
                        break;
                    default:
                        Console.WriteLine("Invalid Input. Please try again");
                        continue;
                }

                Console.WriteLine("C");
            }

Here, printing A/B is like choosing your hand, while printing C is like showing the result. The default branch uses continue (see doc) to return to the beginning of the loop and so does not print C.

enter image description here

Upvotes: 1

Related Questions