Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Flow Control Help
#1
I am having a hard time programming a Rock Paper Scissors Code:
import random, sys
Wins = int()
Losses = int()
Ties = int()
print ('Lets play Rock, Paper, Scissors!')
print ("0 Wins, 0 Losses, 0 Ties")
print ("Enter your move: (R)ock (P)aper (S)cissors or (Q)uit")
Player = input()
while Player == "R" or "P" or "S" or "Q":
    if Player == "R":
        print ("ROCK vs...")
    elif Player == "P":
        print ("PAPER vs...")
    elif Player == "S":
        print ("SCISSOR vs...")
    elif Player == "Q":
        print ("Thanks for playing, sore loser")
        sys.exit()

I use a while loop to limit the user to only input [R]ock [P]aper [S]cissors or [Q]uit
However, when inputting a value outside the R P S or Q range. The code still runs and returns the computer value.

How can I properly limit the user to only input R P S or Q?
Why does my while statement not properly limit the inputs?
Reply
#2
One way:
#! /usr/bin/env python3

acceptable = ['r', 'p', 's', 'q']

while True:
    print(f'Allowed input - {", ".join(acceptable)}')
    choose = input('>> ').lower()

    if choose == 'q':
        break
    if choose in acceptable:
        print(f'{choose} is allowed.')
    else:
        print(f'{choose} is not allowed')
BashBedlam likes this post
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#3
Updated code with While = True followed by If Conditions. Thanks
while True:
    if Player != "R"and Player != "P" and Player !="S" and Player !="Q":
        print ("Enter (R)ock, (P)aper, (S)cissors, or (Q)uit")
        Player = input()
    elif Player == "R" or Player == "P" or Player =="S" or Player == "Q" :
Reply
#4
You don't understand how "or" works. This is pretty common with new Python programmers. I will demonstrate how "or" works with some code.
def study_or(Player):
    print(f'{Player} == "R" is  {Player == "R"}')
    print(f'{Player} == "R" or "P" is  {Player == "R" or "P"}')
    print(f'{Player} == "R" or "P" or "S" is  {Player == "R" or "P" or "S"}')
    print(f'{Player} == "R" or "P" or "S" or "Q" is  {Player == "R" or "P" or "S" or "Q"}')
I run this code with Player = "R" and it prints this:
Output:
R == "R" is True R == "R" or "P" is True R == "R" or "P" or "S" is True R == "R" or "P" or "S" or "Q" is True
This is probably exactly what you expect to happen, so it is of little interest (for now)

Lets try Player = "P"
Output:
P == "R" is False P == "R" or "P" is P P == "R" or "P" or "S" is P P == "R" or "P" or "S" or "Q" is P
As expected, Player == "R" is False, but you didn't expect Player == "R" or "P" to be "P" did you?

From the documents : https://docs.python.org/3/library/stdtyp...and-or-not
Quote:x or y: f x is false, then y, else x
In your example, x is Player == "R" and y is "P". Player == "R" is False, so the "or" looks at "P". Is "P" True, or is it False? In Python most things are treated as "True" when used in a logic operation. The number of things treated as False is a much shorter list.

Things that are logic False:
Empty lists []
Empty tuples (,)
Empty dictionaries {}
Empty strings ""
Empty ranges range(0)
The number zero (0, 0.0, 0j)
None
False

"P" is a non-empty string, so it is True as far as our "or" statement. So if Player = "R", the "or" will return True (x is True), othewise the "or" will return "P". You may as well delete the or "S" or "Q" parts because they will never be evaluated.
ndc85430 likes this post
Reply
#5
Here's my suggestion:
import random, sys
Wins = 0 
Losses =  0
Ties = 0 
Acceptable = ['R', 'P', 'S', 'Q']

print ('\n\nLets play Rock, Paper, Scissors!')
while True :
	print ("0 Wins, 0 Losses, 0 Ties")
	print ("Enter your move: (R)ock (P)aper (S)cissors or (Q)uit")
	answer = input (' >>> ')
	if answer != '' :
		Player = answer [0].upper ()
	if Player == "R":
		print ("ROCK vs...")
	elif Player == "P":
		print ("PAPER vs...")
	elif Player == "S":
		print ("SCISSOR vs...")
	elif Player == "Q":
		print ("Thanks for playing :)")
		sys.exit()
	else :
		print (f'"{answer}" is not a valid choice.')
Reply
#6
This is kind of out there, but you might find it interesting. This code does not make a Rock/Paper/Scissors game, instead is a tool for creating R/P?S type games where you create a game by defining the game rules. The Game class is used to make a single player Rock/Paper/Scissors/Lizard/Spock game and a two player Rock/Paper/Scissors game.
import random

class Player:
    """A human player"""
    def __init__(self, plays, name=None):
        self.name = "Player" if name is None else name
        self.plays = {play.abbr:play for play in plays}
        prefix = "Select" if name is None else f"{name} select"
        self.prompt = f"{prefix} {', '.join([play.menu_name for play in plays])}: "

    def choice(self):
        """Get player choice"""
        while True:
            play = input(self.prompt).upper()
            if play in self.plays:
                return self.plays[play]
            print(f"{play} is not a valid selection")


class Computer:
    """A computer player"""
    def __init__(self, plays, name="Computer"):
        self.name = name
        self.plays = plays

    def choice(self):
        """Get player choice"""
        return random.choice(self.plays)


class Play:
    """A play in a Rock/Paper/Scissor type game"""
    abbreviations = []  # Keep track of abbreviations.  Must be unique for all plays in a game.

    def __init__(self, name):
        for index, abbr in enumerate(name):
            if abbr not in self.abbreviations:
                self.abbreviations.append(abbr)
                break
        self.name = name
        self.abbr = abbr
        self.menu_name = f"{name[:index]}({name[index]}){name[index+1:]}"
        self.rules = {}

    def add_rule(self, loser, rule):
        """Add a rule that affects me"""
        self.rules[loser] = rule

    def beats(self, other):
        """Return rule if I beat other, else None"""
        if other.name in self.rules:
            return self.rules[other.name]
        return None


class Game:
    """
    A Rock/Paper/Scissor type game.  I create a game based on a list of Rules
    in the form: MOVE_A defeats MOVE_B
    """
    def __init__(self, rules):
        Play.abbreviations = []
        self.plays = {}
        self.abbr = {}
        # Create plays.  Rules start and end with a play name.
        for rule in rules:
            words = rule.split()
            winner = words[0]
            loser = words[-1]
            if winner not in self.plays:
                self.plays[winner] = play = Play(winner)
                self.abbr[play.abbr] = play
            self.plays[winner].add_rule(loser, rule)

    def play(self, rounds=1, p1=None, p2=None):
        """Play the game.
        Use rounds to set how many rounds are played.  Default to 1
        Use p1 to set player 1 name.  If None, player name is "Player".
        Use p2 to set select player 2 type. If None, player 2 is Computer, else  Player(p1)"""
        plays = list(self.plays.values())
        player = [Player(plays, p1), Computer(plays) if p2 is None else Player(plays, p2)]
        results = {
            player[0].name: 0,
            player[1].name: 0,
            "Draw":0
        }

        # Play game
        for _ in range(rounds):
            play = [p.choice() for p in player]
            print(f"{player[0].name} selects {play[0].name}, {player[1].name} selects {play[1].name}.  ", end="")
            if (rule := play[0].beats(play[1])):
                print(f"{player[0].name} wins!  {rule}\n")
                results[player[0].name] += 1
            elif (rule := play[1].beats(play[0])):
                print(f"{player[1].name} wins!  {rule}\n")
                results[player[1].name] += 1
            else:
                print("Draw\n")
                results["Draw"] += 1

        print("\nResults")
        for name, count in results.items():
            print(f"{name:10} : {count}")

# Single player Rock/Paper/Scissors/Lizard/Spock game
Game([
    "ROCK crushes SCISSORS",
    "ROCK crushes LIZARD",
    "PAPER covers ROCK",
    "PAPER disproves SPOCK",
    "SCISSORS cuts PAPER",
    "SCISSORS decapitates LIZARD",
    "LIZARD eats PAPER",
    "LIZARD poisons SPOCK",
    "SPOCK smashes SCISSORS",
    "SPOCK vaporizes ROCK",
]).play(3)

# Bert and Ernie play Rock/Paper/Scissors
Game(["ROCK crushes SCISSORS", "PAPER covers ROCK", "SCISSORS cuts PAPER"]).play(3, "Bert", "Ernie")
The most interesting part for you might be how the code separates getting user input from game play. Here it is done so you can make single player or double player games, but it would be useful for something like your game. Also notice how little code is required to actually play the game. Determining the winner or a draw is only 3 lines of code!

Somewhere between writing very specific code like this:
    if Player == "R":
        print ("ROCK vs...")
    elif Player == "P":
        print ("PAPER vs...")
    elif Player == "S":
        print ("SCISSOR vs...")
And generic code like this:
Game(["ROCK crushes SCISSORS", "PAPER covers ROCK", "SCISSORS cuts PAPER"]).play(3, "Bert", "Ernie")
Is an appropriate balance point for a simple program like Rock/Paper/Scissors.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Alicat Flow Meter data acquisition marenr 0 354 Sep-29-2023, 10:59 PM
Last Post: marenr
  Node Flow Generation in Python Linenloid 0 657 Feb-21-2023, 07:09 PM
Last Post: Linenloid
  Understanding Raspberry PI RTS/CTS flow control zazas321 2 3,647 Oct-30-2020, 09:55 AM
Last Post: zazas321
  Understanding Raspberry PI RTS/CTS flow control zazas321 0 1,509 Oct-30-2020, 08:02 AM
Last Post: zazas321
  Reproducing assignment with min cost flow in networkx mntfr 0 2,137 Jun-13-2019, 04:06 PM
Last Post: mntfr
  Find Maximum Flow for graph with infinite capacities Dav 6 4,270 Apr-16-2019, 02:08 PM
Last Post: Dav
  program flow advice sampazzer 2 3,114 Aug-05-2017, 09:34 PM
Last Post: sampazzer
  Trouble with general code flow JCN 1 3,400 May-26-2017, 01:27 PM
Last Post: sparkz_alot

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020