0

I have to write a program game similar to rock paper scissors, but with five options instead of three. I was able to write the code with a system of ifs, but I would like to know if there is a better way to write the code.

Game rules:

As you can see, there are a total of 5 options (X → Y means X wins over Y):

  1. Rock → Lizard & Scissors
  2. Paper → Rock & Spock
  3. Scissors → Paper & Lizard
  4. Lizard → Spock & Paper
  5. Spock → Scissors & Rock

Main Code:

import random
from ex2_rpsls_helper import get_selection
def rpsls_game():
 com_score = 0
 player_score = 0
 draws = 0
 while(abs(com_score - player_score) < 2):
 print(" Please enter your selection: 1 (Rock), 2 (Paper), 3 (Scissors), 4 (Lizard) or 5 (Spock): ")
 selection = int(input())
 # a while loop to make sure input i between 0<x<6
 while(selection <= 0 or selection > 5):
 print( "Please select one of the available options.\n")
 selection = int(input())
 com_selection = random.randint(1,5)
 print(" Player has selected: "+get_selection(selection)+".")
 print(" Computer has selected: "+get_selection(com_selection)+".")
 # A set of else and elseif to determin who is the winner
 if(give_winner(selection, com_selection)):
 print(" The winner for this round is: Player\n")
 player_score += 1
 elif(give_winner(com_selection,selection)):
 print(" The winner for this round is: Computer\n")
 com_score += 1
 else:
 print(" This round was drawn\n")
 draws += 1
 print("Game score: Player "+str(player_score)+", Computer "+str(com_score)+", draws "+str(draws))
 if(player_score > com_score):
 return 1
 else:
 return -1

The IFS system:

def give_winner(first_selection, second_selection):
 if(first_selection is 1):
 if(second_selection is 3 or second_selection is 4):
 return True
 elif(first_selection is 2):
 if(second_selection is 1 or second_selection is 5):
 return True
 elif(first_selection is 3):
 if(second_selection is 2 or second_selection is 4):
 return True
 elif(first_selection is 4):
 if(second_selection is 2 or second_selection is 5):
 return True
 elif(first_selection is 5):
 if(second_selection is 3 or second_selection is 1):
 return True
 return False

Any ideas?

glglgl
91.5k13 gold badges157 silver badges230 bronze badges
asked Oct 25, 2013 at 7:56
1
  • 5
    Don't compare values with is. Even if that usually works with integers in the range from -5 to 255, it is not correct. You are not interested on if you have the same object, but if they have the same value. Thus, use ==. Commented Oct 25, 2013 at 8:12

6 Answers 6

5

Instead of a complicated series of if statements, you could have an list or dictionary of (first, second) tuples,

a = [(1,3), (1,4), (2,1), (2,5) ...]
def give_winner(first_selection, second_selection):
 return (first_selection, second_selection) in a

You could also use a frozenset to improve performance.

answered Oct 25, 2013 at 8:02
Sign up to request clarification or add additional context in comments.

Comments

4

You could use a dictionary.

dictionary = {
 1: [3, 4],
 2: [1, 5],
 3: [2, 4],
 4: [2, 5],
 5: [3, 1]
}
def give_winner(first_selection, second_selection):
 if dictionary.has_key(first_selection):
 if second_selection in dictionary[first_selection]:
 return True
 return False
answered Oct 25, 2013 at 8:05

3 Comments

You are re-creating the dictionary every time here, which is unnecessary
BTW You can simply say first_selection in dictionary instead of .has_key.
@Kos and indeed, first_selection in dictionary is preferred - has_key is long since deprecated, and no longer exists in Python 3. It would be even better to skip the check entirely, just do return second_selection in dictionary[first_selection] and possibly catch any KeyError up in the user interaction code.
0

give winner alternative also:

def give_winner(first_selection, second_selection):
 rules = {
 1: lambda x: x in (3, 4),
 2: lambda x: x in (1, 5),
 3: lambda x: x in (2, 4),
 4: lambda x: x in (2, 5),
 5: lambda x: x in (3, 1)
 }
 return rules[first_selection](second_selection)
answered Oct 25, 2013 at 8:05

2 Comments

@aIKid In general, I disagree: lambdas are not unreadable per se. But here, they are overhead. This approach seems better to me.
well, now seeing the other solutions, I vote for those as well.. would like to ask the OP to change the accepted answer.
0

You can make use of classes in python. For example, you can make player as a class with the following attributes:-

 Score
 Name
 OptionChosen

etc similarly, you can make methods like

 UpdateScore()
 DeclareWinner()

etc. This way your program will feel more "neat". You can also make a main() function which contains a

 while True:

and put all your content there. for ex

 class Player:
 def __init__(self,name, score = 0):
 self.name = name
 self.score = score # initially score is zero
 def ChooseOption(self, name):
 if name == "computer":
 # select choice randomly code
 else:
 var = int(input("Enter choice: "))
 def UpdateScore(self):
 self.score += 1
 def main():
 player1 = Player("Name")
 player2 = Player("Computer") 
 while True:
 resp1 = player1.ChooseOption()
 resp2 = player2.ChooseOption()
 # add other code to manipulate resp1 and resp2 here 

and similarly you can code other things, Hope this gives you some idea

answered Oct 25, 2013 at 7:58

1 Comment

Don't name functions and methods with CamelCase, or with caps at all. Use choose_option, update_score, etc. See PEP 8.
0

I enjoyed building my own little version of Rock Paper Scissor Lizard Spock.

You started your post by explaining som rules. So i figured, why not incorporate the rules inside the code. And i wanted to use real words instead of numbers since it would be easier to understand. But i agree it would be a hassle to spell scissors correct everytime, so i wanted numbers to work as input as well.

from random import randint
# ex. scissors and lizard is beaten by rock
beaten_by = {'rock': ['scissors', 'lizard'],
 'paper': ['rock', 'spock'],
 'scissors': ['paper', 'lizard'],
 'lizard': ['spock', 'paper'],
 'spock': ['scissors', 'rock']}
def rplsls_game():
 player_score, computer_score = 0, 0
 weapons = ['rock', 'paper', 'scissors', 'lizard', 'spock']
 while(abs(player_score - computer_score) < 2):
 print "-----------------------------------------------------------"
 print " Please enter your selection: "
 print " 1 (Rock), 2 (Paper), 3 (Scissors), 4 (Lizard) or 5 (Spock)"
 computer_weapon = weapons[randint(0, 4)]
 weapon = raw_input()
 if weapon in '12345': weapon = weapons[int(weapon) - 1]
 if weapon not in weapons:
 print "invalid input"
 continue 
 print "You selected: " + weapon
 print "Computer selected: " + computer_weapon
 if computer_weapon in beaten_by[weapon]:
 print "You won!"
 player_score += 1
 elif weapon in beaten_by[computer_weapon]:
 print "Computer won!"
 computer_score += 1
 else:
 print "Draw!"
 print "Player: " + str(player_score)
 print "Computer: " + str(computer_score)
 if player_score > computer_score:
 print "Congratulations! you won the game"
 else:
 print "Computer won the game..."
rplsls_game()
answered Oct 25, 2013 at 14:09

Comments

-1

You can use also raw_input instand:

print(" Please enter your selection: 1 (Rock), 2 (Paper), 3 (Scissors), 4 (Lizard) or 5 (Spock): ")
selection = int(input())
try:
 selection = input("Please enter your selection: 1 (Rock), 2 (Paper), 3 (Scissors), 4 (Lizard) or 5 (Spock): ")
except ...

You complete forgot about exceptions.

And if stemtmants in your give_winner function is too large, use dictionar or lambda function.

answered Oct 25, 2013 at 8:06

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.