How could I replace these many if statement?

Hello! I made a game “Rock,Paper,Scissors” and I’m trying to figure out how to replace these if statements in my class. I’m not interested in replacing these with switch. Any ideas?

Everything works properly. I just want to refactor my code :wink:

private void CheckForWin()
   {
      if (_playerOneChoice == _playerTwoChoice)
      {
         StartCoroutine(ShowResultTextCo(_drawText, "DRAW"));
         
         ActivateEndRoundButtons();
      }

      if (_playerOneChoice == GameChoices.ROCK && _playerTwoChoice == GameChoices.SCISSORS)
      {
         EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
      }
      
      if (_playerOneChoice == GameChoices.SCISSORS && _playerTwoChoice == GameChoices.PAPER)
      {
         EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
      }
      
      if (_playerOneChoice == GameChoices.PAPER && _playerTwoChoice == GameChoices.ROCK)
      {
         EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
      }
      
      if (_playerOneChoice == GameChoices.ROCK && _playerTwoChoice == GameChoices.PAPER)
      {
         EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
      }
      
      if (_playerOneChoice == GameChoices.PAPER && _playerTwoChoice == GameChoices.SCISSORS)
      {
         EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
      }
      
      if (_playerOneChoice == GameChoices.SCISSORS && _playerTwoChoice == GameChoices.ROCK)
      {
         EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
      }
   }

A different approach would be to express which choice beats which. You can use a dictionary which is populated during Start.

Dictionary<GameChoices, GameChoices> rules;

void Start()
{
    rules = new Dictionary<GameChoices, GameChoices>();
    rules.Add(GameChoices.ROCK, GameChoices.SCISSORS);
    rules.Add(GameChoices.SCISSORS, GameChoices.PAPER);
    rules.Add(GameChoices.PAPER, GameChoices.ROCK);
}

private void CheckForWin()
{
    GameChoices other;
    if(rules.TryGetValue(_playerOneChoice, out other) && _playerTwoChoice == other)
    {
        EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
    }
    else if(rules.TryGetValue(_playerTwoChoice, out other) && _playerOneChoice == other)
    {
        EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
    }
    else
    {
        StartCoroutine(ShowResultTextCo(_drawText, "DRAW"));
        ActivateEndRoundButtons();
    }
}

This should work for the classic rock - paper - scissors. However with this approach each choice can only beat exactly one other choice.

A different approach would be to actually encode the “winning pairs” as a “key” like that:

public struct ChoicePair
{
    public GameChoices c1;
    public GameChoices c2;
    public ChoicePair(GameChoices aC1, GameChoices aC2)
    {
        c1 = aC1;
        c2 = aC2;
    }
}
HashSet<ChoicePair> rules = new HashSet<ChoicePair>();
private void Start()
{
    rules.Add(new ChoicePair(GameChoices.ROCK, GameChoices.SCISSORS));
    rules.Add(new ChoicePair(GameChoices.SCISSORS, GameChoices.PAPER));
    rules.Add(new ChoicePair(GameChoices.PAPER, GameChoices.ROCK));
}

private void CheckForWin()
{
    if(rules.Contains(new ChoicePair(_playerOneChoice, _playerTwoChoice)))
    {
        EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
    }
    else if(rules.Contains(new ChoicePair(_playerTwoChoice, _playerOneChoice)))
    {
        EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
    }
    else
    {
        StartCoroutine(ShowResultTextCo(_drawText, "DRAW"));
        ActivateEndRoundButtons();
    }
}

In this case we can essentially define any winning rules we like. For example if you want to introduce the common additional choices SPOCK and LIZARD the rules are simply:

private void Start()
{
    rules.Add(new ChoicePair(GameChoices.SCISSORS, GameChoices.PAPER));
    rules.Add(new ChoicePair(GameChoices.PAPER, GameChoices.ROCK));
    rules.Add(new ChoicePair(GameChoices.ROCK, GameChoices.LIZARD));
    rules.Add(new ChoicePair(GameChoices.LIZARD, GameChoices.SPOCK));
    rules.Add(new ChoicePair(GameChoices.SPOCK, GameChoices.SCISSORS));

    rules.Add(new ChoicePair(GameChoices.SCISSORS, GameChoices.LIZARD));
    rules.Add(new ChoicePair(GameChoices.LIZARD, GameChoices.PAPER));
    rules.Add(new ChoicePair(GameChoices.PAPER, GameChoices.SPOCK));
    rules.Add(new ChoicePair(GameChoices.SPOCK, GameChoices.ROCK));
    rules.Add(new ChoicePair(GameChoices.ROCK, GameChoices.SCISSORS));
}

After adding the two extra choices to the enum and using those rules instead, everything works the same way.

I dont know if this can be considered refract. You have all final options.

iF P1 = P2    -  DRAW

if P1 = sciss
    IF P2 = rock - P2 wins
    else P1 win

if P1 = Rock
    if P2 = sciss   - P1 win
    ELSE P1 win

if P1 = Paper
   if P2 = rock  P1 win
   else P1 win

This is not refactoring but I believe will make easier to do so later:

private void CheckForWin()
{
    PlayerOneWon();
    PlayerTwoWon();
    MatchIsDraw();
}

private static void PlayerOneWon()
{
    if (_playerOneChoice == GameChoices.ROCK && _playerTwoChoice == GameChoices.SCISSORS)
    {
        EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
    }
    else if (_playerOneChoice == GameChoices.SCISSORS && _playerTwoChoice == GameChoices.PAPER)
    {
        EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
    }
    else if (_playerOneChoice == GameChoices.PAPER && _playerTwoChoice == GameChoices.ROCK)
    {
        EndRoundUpdate(ref _playerOneScore, _playerOneScoreText, "PLAYER 1 WON");
    }
}

private static void PlayerTwoWon()
{
    if (_playerOneChoice == GameChoices.ROCK && _playerTwoChoice == GameChoices.PAPER)
    {
        EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
    }
    else if (_playerOneChoice == GameChoices.PAPER && _playerTwoChoice == GameChoices.SCISSORS)
    {
        EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
    }
    else if (_playerOneChoice == GameChoices.SCISSORS && _playerTwoChoice == GameChoices.ROCK)
    {
        EndRoundUpdate(ref _playerTwoScore, _playerTwoScoreText, "PLAYER 2 WON");
    }
}

private void MatchIsDraw()
{
    if (_playerOneChoice == _playerTwoChoice)
    {
        StartCoroutine(ShowResultTextCo(_drawText, "DRAW"));

        ActivateEndRoundButtons();
    }
}

Hope it helps