0

I am using the following method which works but wondering if there is a better algorithm to perform the test. Is there a better way to do it? Doing this in C# but putting syntax aside, believe the algorithm is going to be the same across OOP languages. Thank you.

public String play(int userInput)
        {   //ComputerIn is a randomly generated number between 1-3
            ComputerIn = computerInput();

            if (ComputerIn == userInput)
                return "Draw";

            else if (ComputerIn == 1 && userInput == 2)
                return "Win";

            else if (ComputerIn == 2 && userInput == 3)
                return "Win";

            else if (ComputerIn == 3 && userInput == 1)
                return "Win";

            else if (ComputerIn == 1 && userInput == 3)
                return "Lose";

            else if (ComputerIn == 2 && userInput == 1)
                return "Lose";

            else
                return "Lose";
        }
kar
  • 4,791
  • 12
  • 49
  • 74
  • 7
    Different languages may well have different idiomatic approaches to this. Are you *actually* interested in C#, Java or C? – Jon Skeet Nov 28 '13 at 16:56
  • Hi I would like to know it in C# and if there is a difference in Java language for the algorithm, would be interested in that too. Thanks. – kar Nov 28 '13 at 17:02
  • 2
    I dont see much of OOPs concept used in the given syntax. It is more of branching statement. – Miller Nov 28 '13 at 17:05
  • My solutions for Java and C# would be different due to the nature of Java enums vs C# enums. – Jon Skeet Nov 28 '13 at 17:16

8 Answers8

13
if ((ComputerIn) % 3 + 1 == userInput)
    return "Win";
else if ((userInput) % 3 + 1 == ComputerIn)
    return "Lose"
else
    return "Draw"

If you wrap 3 around to 1 (using %) then the winner is always 1 greater than the loser.

This approach is more natural when you use 0-2, in which case we would use (ComputerIn+1)%3. I came up with my answer by subbing ComputerIn with ComputerIn-1 and UserInput with UserInput-1 and simplifying the expression.

Edit, looking at this question after a long time. As written, if the ComputerIn is not used anywhere else, and is only used to determine win/lose/draw, then this method is actually equivalent to:

if (ComputerIn == 1)
    return "Win";
else if (ComputerIn == 2)
    return "Lose"
else
    return "Draw"

This can even be further simplified to

return new String[]{"Win", "Lose", "Draw"}[ComputerIn-1];

The results from this are entirely indistinguishable. Unless the randomly generated number is exposed to outside of this method. No matter what your input is, there's always 1/3 chance of all possibilities. That is, what you're asking for, is just a complicated way of returning "Win", "Lose", or "Draw" with equal probability.

Cruncher
  • 7,641
  • 1
  • 31
  • 65
  • does `if ((ComputerIn) % 3 + 1 == userInput) return "Draw";` satisfy `if (ComputerIn == userInput) return "Draw";` ? – Miller Nov 28 '13 at 17:12
  • @MillerKoijam No in fact those 2 conditionals are mutually exclusive. The draw comes from, if both of my conditions are false, then they must be equal. When there's only 3 possible values, either A>B, B>A or A=B. – Cruncher Nov 28 '13 at 17:14
2

Here's one of many possible solutions. This will print Win.

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      Input userInput = Input.Rock;
      Result result = Play(userInput);
      Console.WriteLine(Enum.GetName(result.GetType(), result));
      Console.ReadKey();
    }

    static Result Play(Input userInput)
    {
      Input computer = Input.Scissors;

      switch (userInput)
      {
        case Input.Paper:
          switch (computer)
          {
            case Input.Paper: return Result.Draw;
            case Input.Rock: return Result.Win;
            case Input.Scissors: return Result.Lose;
            default: throw new Exception("Logic fail.");
          }
        case Input.Rock:
          switch (computer)
          {
            case Input.Paper: return Result.Lose;
            case Input.Rock: return Result.Draw;
            case Input.Scissors: return Result.Win;
            default: throw new Exception("Logic fail.");
          }
        case Input.Scissors:
          switch (computer)
          {
            case Input.Paper: return Result.Win;
            case Input.Rock: return Result.Lose;
            case Input.Scissors: return Result.Draw;
            default: throw new Exception("Logic fail.");
          }
        default: throw new Exception("Logic fail.");
      }
    }
  }
  enum Input
  {
    Rock,
    Paper,
    Scissors
  }
  enum Result
  {
    Lose,
    Draw,
    Win
  }
}
Slate
  • 3,189
  • 1
  • 31
  • 32
1

This is how I would do it:

public class Program
{

    public enum RPSPlay { Rock, Scissors, Paper }
    public enum RPSPlayResult { Win, Draw, Loose }

    public static readonly int SIZE = Enum.GetValues(typeof(RPSPlay)).Length;

    static RPSPlayResult Beats(RPSPlay play, RPSPlay otherPlay)
    {
        if (play == otherPlay) return RPSPlayResult.Draw;
        return ((int)play + 1) % SIZE == (int)otherPlay 
            ? RPSPlayResult.Win 
            : RPSPlayResult.Loose;
    }

    static void Main(string[] args)
    {
        Random rand = new Random();
        while (true)
        {
            Console.Write("Your play ({0}) (q to exit) : ", string.Join(",", Enum.GetNames(typeof(RPSPlay))));
            var line = Console.ReadLine();
            if (line.Equals("q", StringComparison.OrdinalIgnoreCase))
                return;
            RPSPlay play;
            if (!Enum.TryParse(line, true, out play))
            {
                Console.WriteLine("Invalid Input");
                continue;
            }
            RPSPlay computerPlay = (RPSPlay)rand.Next(SIZE);
            Console.WriteLine("Computer Played {0}", computerPlay);
            Console.WriteLine(Beats(play, computerPlay));
            Console.WriteLine();
        }
    }
}
Ahmed KRAIEM
  • 10,267
  • 4
  • 30
  • 33
1

I would prefer to use a static 3x3 matrix to store the possible outcomes. But it is a question of taste, and I am a mathematician.

Philip Sheard
  • 5,789
  • 5
  • 27
  • 42
0

Here is one-liner that we created at lunchtime.

using System;

public class Rps {
  public enum PlayerChoice { Rock, Paper, Scissors };
  public enum Result { Draw, FirstWin, FirstLose};

  public static Result Match(PlayerChoice player1, PlayerChoice player2) {
    return (Result)((player1 - player2 + 3) % 3);
  }

  public static void Main() {
    Rps.Test(Match(PlayerChoice.Rock, PlayerChoice.Rock), Result.Draw);
    Rps.Test(Match(PlayerChoice.Paper, PlayerChoice.Paper), Result.Draw);
    Rps.Test(Match(PlayerChoice.Scissors, PlayerChoice.Scissors), Result.Draw);

    Rps.Test(Match(PlayerChoice.Rock, PlayerChoice.Scissors), Result.FirstWin);
    Rps.Test(Match(PlayerChoice.Rock, PlayerChoice.Paper), Result.FirstLose);

    Rps.Test(Match(PlayerChoice.Paper, PlayerChoice.Rock), Result.FirstWin);
    Rps.Test(Match(PlayerChoice.Paper, PlayerChoice.Scissors), Result.FirstLose);

    Rps.Test(Match(PlayerChoice.Scissors, PlayerChoice.Paper), Result.FirstWin);
    Rps.Test(Match(PlayerChoice.Scissors, PlayerChoice.Rock), Result.FirstLose);
  }

  public static void Test(Result sample, Result origin) {
    Console.WriteLine(sample == origin);
  }      
}
Nine
  • 15
  • 5
  • The enum stuff is all a good idea, even though it's a refactor from the original question. Even with it though, I would still rather write Match in more than 1 line. That can be painfully difficult to read – Cruncher Aug 07 '14 at 14:45
  • I think we speak about "better algorithm". When I watch Robert Sedgewick's course on algorithms, they were difficult to read too. – Nine Aug 10 '14 at 10:37
  • Programming is different than algorithm design. When programming, readability, and maintainability are your primary concern. When designing an algorithm (before you program it), the primary concern is correctness and efficiency. – Cruncher Aug 10 '14 at 11:41
0

\From A java beginner Perspective. User plays with the computer to infinity.

import java.util.Scanner;

public class AlgorithmDevelopmentRockPaperScissors{
    public static void main(String[] args){

        System.out.println("\n\nHello Eric today we are going to play a game.");
        System.out.println("Its called Rock Paper Scissors.");
        System.out.println("All you have to do is input the following");
        System.out.println("\n  1 For Rock");
        System.out.println("\n        2 For Paper");
        System.out.println("\n        3 For Scissors");

        int loop;
        loop = 0;

        while (loop == 0){
            System.out.println("\n\nWhat do you choose ?");


        int userInput;
        Scanner input = new Scanner(System.in);
        userInput = input.nextInt();

        while (userInput > 3 || userInput <= 0 ){ //ensure that the number input by the sure is within range 1-3. if else the loop trap.

            System.out.println("Your choice "+userInput+" is not among the choices that are given. Please enter again.");
            userInput = input.nextInt();
        }



        switch (userInput){
            case 1:
            System.out.println("You Chose Rock.");
            break;

            case 2:
            System.out.println("You Chose Paper.");
            break;

            case 3:
            System.out.println("You Chose Scissors");
            break;

            default:
            System.out.println("Please Choose either of the choices given");
            break;

        }



        int compInput;
        compInput = (int)(3*Math.random()+1);

        switch (compInput){
            case 1:
            System.out.println("\nComputer Chooses Rock.");
            break;

            case 2:
            System.out.println("\nComputer Chooses Paper.");
            break;

            case 3:
            System.out.println("\nComputer Chooses Scissors");
            break;

        }

        if (userInput == compInput){

            System.out.println(".........................................");
            System.out.println("\nYou Both chose the same thing, the game ends DRAW.");
            System.out.println(".........................................");
        }

        if (userInput == 1 && compInput == 2){

            System.out.println(".........................................");
            System.out.println("\nComputer wins because Paper wraps rock.");
            System.out.println(".........................................");
        }

        if (userInput == 1 && compInput == 3){

            System.out.println(".........................................");
            System.out.println("\nYou win because Rock breaks Scissors.");
            System.out.println(".........................................");
        }

        if (userInput == 2 && compInput == 1){

            System.out.println(".........................................");
            System.out.println("\nYou win Because Paper wraps Rock");
            System.out.println(".........................................");
        }

        if (userInput == 2 && compInput == 3){

            System.out.println(".........................................");
            System.out.println("\nComputer wins because Scissors cut the paper");
            System.out.println(".........................................");
        }

        if (userInput == 3 && compInput == 1){

            System.out.println(".........................................");
            System.out.println("\nComputer Wins because Rock Breaks Scissors.");
            System.out.println(".........................................");
        }

        if (userInput == 3 && compInput == 2){

            System.out.println(".........................................");
            System.out.println("\nYou win because scissors cut the paper");
            System.out.println(".........................................");
        }

        }


    }

}
Ahmet Emre Kilinc
  • 5,489
  • 12
  • 30
  • 42
0

A simple JavaScript implementation using sine wave function to calculate result:

<script>
    var tab = ["Lose","Draw","Win"];
    var dict = ["Paper","Stone","Scissors"];
    var i,text = '';
    for (i = 0; i < dict.length; i++) {
        text += i + '-' + dict[i] + ' ';
    }
    var val1 = parseInt(prompt(text));
    var val2 = Math.floor(Math.random() * 3);
    alert('Computer chose: ' + dict[val2]);
    result = Math.sin((val1*180+1) - (val2*180+1));
    alert(tab[Math.round(result)+1]);
</script>

No if's required, just for fun...

Check it

  • I would guess that because of inefficient and hard to maintain approach using Math.sin... However, this is not huge enterprise application so who cares :) – Obywatel 79 Jan 30 '20 at 11:50
  • Or if it was a reviewer from SO, giving a downvote is enough to move to the next review item and increase review count (get badge faster). – Tiago Martins Peres Jan 30 '20 at 11:59
0

Observation: The user wins if userInput is only one ahead of computerInput (case of (1,2), (2,3)) or lag two (case of (3,1)).

Conversely, if userInput lags one behind computerInput or two ahead, the user loses.

In the modulo 3, the lag one is the same as the advance two. (-1 mod 3 == 2 mod 3 == 2)

int decision = (userInput - computerInput + 3) % 3;
String[] answer = {"Draw", "Win", "Lose"};

return answer[decision];
Joo-Won Jung
  • 151
  • 1
  • 2
  • 6