views:

145

answers:

1

Is there a formula without if/else/switch/? etc that could replace the solution[,] matrix and what are the implications or differences on performance/efficiency for that?

     class Program
{
    private static Random r = new Random();
    // names of the "moves"
    private static string[] rps = { "PAPER", "ROCK", "SCISSORS"};
    // result feedback string to be formatted
    private static string[] feedback = { "{1} Beats {0}, You Loose!","{0} Equals {1}, Draw!",  "{0} Beats {1}, You Win!" };
    // solution matrix ( 0 = loose ; 1 = draw ; 2 = win  // array1: for paper; array2: for rock; array3: for scissors; )
    private static int[,] solution = {{1, 2, 0},{0, 1, 2},{2, 0, 1}};

    /// <summary>
    /// Rock Paper scissors solution w/o calculation or if/case/else/
    /// </summary>
    /// <param name="args">dummy.</param>
    static void Main(string[] args)
    {
            // simulate the players move
            int player = r.Next(3);

            // simulate the computers move
            int computer = r.Next(3);

            // retrieve the result from the matrix
            int result = solution[player, computer];

            //write the result of the match
            Console.WriteLine(String.Format("you : {0} vs {1} : computer", rps[player], rps[computer]));
            Console.WriteLine(String.Format(feedback[result], rps[player], rps[computer]));

    }
}
+3  A: 

Yes, there is a quite simple formula:

player computer  solution  (c+4-p)%3
  0       0         1          1
  0       1         2          2
  0       2         0          0
  1       0         0          0
  1       1         1          1
  1       2         2          2
  2       0         2          2
  2       1         0          0
  2       2         1          1

So you can use:

int result = (computer + 4 - player) % 3;

Accessing the array and calculating the value would take rougly the same time. However, the difference in performance in this application is negligible. Just writing the result to the console takes a lot longer than either using the array or calculating the value. Of course, by calculating the value you don't need the array, but as it's so small that doesn't make much of a difference.

Consider also the readability of the solution. The formula has no logical connection to what you use it for, it's just a means to get to a specific result, so you would need a large comment that explains what it accomplishes...

Edit:

If you want focus on readability, you could put the logic in a separate class:

public class Play {

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

  private Value _value;

  public Play(Random rnd) {
    _value = (Value)rnd.Next(3);
  }

  public bool SameAs(Play other) {
    return _value == other._value;
  }

  public bool Beats(Play other) {
    return
      (_value == Value.Paper && other._value == Value.Rock) ||
      (_value == Value.Rock && other._value == Value.Scissors) ||
      (_value == Value.Scissors && other._value == Value.Paper);
  }

  public override string ToString() {
    switch (_value) {
      case Value.Paper: return "PAPER";
      case Value.Rock: return "ROCK";
      default: return "SCISSORS";
    }
  }

}

Now the logic gets clearer:

Random r = new Random();

Play player = new Play(r);
Play computer = new Play(r);

Console.WriteLine("you : {0} vs {1} : computer", player, computer);

string feedback;
if (player.SameAs(computer)) {
  feedback = "{0} Equals {1}, Draw!";
} else if (player.Beats(computer)) {
  feedback = "{0} Beats {1}, You Win!";
} else {
  feedback = "{1} Beats {0}, You Loose!";
}

Console.WriteLine(feedback, player, computer);
Guffa
thank you for the quick response. A test did indeed show that the formula worked! Perhaps you can explain what the 4 does? I've tried the same with 1, 2 and 3 but never came to 4. Funny But Thanks a lot!
Caspar Kleijne
@Caspar Kleijne: The 4 acts just like 1, as modulo 3 is then used, but it makes `(player+4)` always be larger than `computer`, so there is no negative numbers to worry about.
Guffa
Man...thanks for the great lesson! I love this kind of stuff!!
Caspar Kleijne
The problem with the readability is indeed an issue I was struggling with. One thing is that the Behaviour of the rps[] array is "linear" while the result approaches the rps[] with a more triangular or "ring" perspective. To clarify that in code is pretty hard. The short-notation makes it even harder I guess. Challenges ahead so to say.
Caspar Kleijne
@Caspar Kleijne: For readablily I think that an `if` statement would be the best choise. I added an example with a class that encapsualtes the logic, and uses an `enum` for the values, which make it pretty readable.
Guffa
@Caspar Kleijne: Why not try to apply it to rock, paper, scissors, spock, lizard? :)
Guffa
@guffa. Thanks for your reply....but...... The whole exercise for me was based on two things: 1.) Separation of data and behaviour and my eager to proof that an if/then statement is not necessary when dealing with values that are already "predetermined". In this case, we are able to oversee all results (there are only 9) and perhaps we want indeed scale the application to a larger one (like rock, paper, scissors, spock, lizard..all starwarsfigures..etc). In that case Enumerators and if/else would not be a good solution.But I agree in this case, your solution is more readable ;) Thanks anyway!
Caspar Kleijne
I mean: You are right, but there is too little space to explain all details of this small program ;)
Caspar Kleijne