- Home /
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 ;)
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");
}
}
Answer by Bunny83 · Mar 05, 2020 at 01:02 AM
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.
Note I haven't tested the code but it should work ;) Of course for such a game using ScriptableObjects ins$$anonymous$$d of an enum would be more flexible as Ryan Hipple explained in his talk over here. He's actually mentioning the talk of Richard Fine which should get you started on how to use ScriptableObjects as an "enum". I don't want to go into details here since all that wasn't part of the question asked here.
ps: I can highly recommend watching those two talks from the beginning.
Thank you, it looks very well! I will use this and I will give you feedback if everything works properly :D
This works perfectly, thank you :D Still have a lot to learn about coding :)
Answer by tormentoarmagedoom · Mar 04, 2020 at 08:54 PM
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
Answer by erickluiss · Mar 05, 2020 at 03:58 AM
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
Your answer
Follow this Question
Related Questions
How to call invoke from a monobehaviour class using a function from an object class. 1 Answer
BoxCollider2d.bounds.Intersects Not Working 2 Answers
how do I edit a component of a specific child of an instantiated object? 2 Answers
Oculus VR Drag Slider With Finger 0 Answers
Trouble with Triggering Animation - Please help!!! 0 Answers