HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Rock, Paper Scissor game (console-based) in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
paperscissorgamerockpythonbasedconsole

Problem

I'm a beginner at coding with Python, and I've only made small projects, and this is one of them. One part of the code is from an answer on Stack Overflow that I made to solve a problem (is the try part) and all the other code is mine.

```
import random,os,time
score = {'human':0,'robot':0}
def game(): #Basic Game code.
time.sleep(1)
os.system('clear')
print('IA: ' + str(score['robot']) + ' Human: ' + str(score['human']))
print('1.Rock 2.Scissors 3.Paper')
while True:
try:
choice = int(input("Input your choice:\n"))
if choice 3: #Valid number but outside range, don't let through
raise ValueError
else: #Valid number within range, quit loop and the variable selection contains the input.
break
except ValueError: #Invalid input
print("Enter a number from 1 to 3.")
rchoice = random.randint(1,3)
time.sleep(1)
if rchoice == 1:
print('IA choice is Rock.')
elif rchoice == 2:
print('IA choice is Scissors.')
elif rchoice == 3:
print('IA choice is Paper.')

if (rchoice==1 and choice==2)or(rchoice==2 and choice==3)or(rchoice==3 and choice==1):
print('IA wins!\n')
score['robot'] += 1
time.sleep(0.5)
elif (rchoice == choice):
print("Draw, let's repeat")
time.sleep(0.5)
game()
else:
print('You win!\n')
time.sleep(0.5)
score['human'] += 1

def startgame(): #The introduction of the game.
os.system('clear')
print('Rock-Paper-Scissors v.1')
print('Developed by P.R.B.\n')
ngames = int(input('How many games do you want to play?\n'))
time.sleep(1)
i = 0
while i != ngames:
game()
i += 1
print('Final Score:')
print('IA: ' + str(score['robot']) + ' Human: ' + str(score['human']))
if score['human'] > score['robot']:
print('You win the game!\n')
else:
print('Game Over')

Solution

It looks like you are familiar with dictionaries and maybe lists. So, let's look at how you collect and enter input. It looks like you are trying to control erroneous input with your try/except and if statement. There is some trouble though. I can send a float through your code if it has a value like 1.2 or 2.5. Your code will turn it into an int and then try to use the value, but there's another way to handle something like this:

if choice not in ['1','2','3']:
    raise ValueError
else:
    break


So, in this case, I'm using a list of the only acceptable values, checking if the choice is in there, and then moving forward.

Your control flow looks a little messy. There are a couple of ways to handle this.

If we keep the same general approach, you can make it more readable by spreading it out. I would actually make a new function for this:

def compare(x,y):
    if x == y:
        state = "It's a Draw!"
    if x == '1':
        if y == '2':
            state = "You Lose!"
        else:
            state == "You Win!"
    elif x == '2':
        if y == '1':
            state = "You Win!"
        else:
            state == "You Lose!"
    else:
        if y == '1':
            state = "You Lose!"
        elif y == '2':
            state = "You Win!"
    return state


However, depending on how comfortable you are with lists, there is another, simpler way!

You can setup a list of the possible game conditions and then do whatever you want to them:

game_result = ["tie!", "win!", "lose!"]


(Actually, that sequence in the list was coded for 1) Rock, 2)Paper, and 3)Scissors. There should be another arrangement for rock-scissors-paper though that makes things smooth).

Then define a comparison function that just looks at the modulated difference between the user and robot input (you'll need to convert them to the int data type first).

def compare(x,y):
result = game_result[ (x-y)%3 ]
return result


There's a few tricky things with how you're checking which round you should be on. So, first thing, it might be helpful/more readable if you change the variable name to something useful like round_number or matches_left.

Then, you have it set to end the while loop if the round number is not equal to n. There's another potential bug here. What if the user enters a float or something you don't want? -- Actually, you're using int() on the input, which corrects for this. So good call! But, that design pattern doesn't always carry over well and it may not be as clear to other readers ( it wasn't to me anyways).

Suppose the player enters 1.2, then your while loop goes on for ever if you aren't using int(). One way to handle this is to use try/except; another way is to use isinstance; and another way is to do something like this:

while num_of_rounds <= ngames:
        game()
        num_of_rounds += 1


In this way, you cover a broader set of what is acceptable/unacceptable and don't have your code hinging on a small window of operation (and exploitability).

Overall, your code works and was fun to play! The biggest things are style, readability, and different ideas on how to handle incorrect input. I would check out the PEP 8 Python style Guide for some general insights: https://www.python.org/dev/peps/pep-0008/

Code Snippets

if choice not in ['1','2','3']:
    raise ValueError
else:
    break
def compare(x,y):
    if x == y:
        state = "It's a Draw!"
    if x == '1':
        if y == '2':
            state = "You Lose!"
        else:
            state == "You Win!"
    elif x == '2':
        if y == '1':
            state = "You Win!"
        else:
            state == "You Lose!"
    else:
        if y == '1':
            state = "You Lose!"
        elif y == '2':
            state = "You Win!"
    return state
game_result = ["tie!", "win!", "lose!"]
def compare(x,y):
result = game_result[ (x-y)%3 ]
return result
while num_of_rounds <= ngames:
        game()
        num_of_rounds += 1

Context

StackExchange Code Review Q#157528, answer score: 3

Revisions (0)

No revisions yet.