Play Again In a While Loop Python
Game programming is a bang-up manner to learn how to program. You use many tools that y'all'll run into in the real world, plus you get to play a game to test your results! An platonic game to start your Python game programming journeying is rock paper pair of scissors.
In this tutorial, you'll learn how to:
- Code your own rock paper scissors game
- Take in user input with
input() - Play several games in a row using a
whileloop - Clean up your code with
Enumand functions - Ascertain more than complex rules with a dictionary
What Is Stone Paper Scissors?
You may have played rock paper scissors before. Maybe yous've used information technology to decide who pays for dinner or who gets first choice of players for a team.
If yous're unfamiliar, stone newspaper scissors is a paw game for two or more players. Participants say "rock, newspaper, scissors" and so simultaneously form their easily into the shape of a rock (a fist), a piece of paper (palm facing downward), or a scissors (two fingers extended). The rules are straightforward:
- Rock smashes scissors.
- Newspaper covers rock.
- Pair of scissors cutting paper.
Now that you take the rules downward, y'all tin can start thinking about how they might translate to Python code.
Play a Single Game of Rock Paper Pair of scissors in Python
Using the description and rules above, you can brand a game of stone paper pair of scissors. Earlier y'all dive in, you're going to need to import the module y'all'll apply to simulate the computer's choices:
Crawly! Now you're able to use the dissimilar tools inside random to randomize the computer's actions in the game. At present what? Since your users volition besides need to exist able to choose their actions, the first logical thing you need is a manner to accept in user input.
Take User Input
Taking input from a user is pretty straightforward in Python. The goal here is to ask the user what they would like to choose equally an action and then assign that choice to a variable:
user_action = input ( "Enter a option (rock, paper, pair of scissors): " ) This will prompt the user to enter a selection and save it to a variable for later on utilise. Now that the user has selected an activity, the computer needs to determine what to practice.
Make the Computer Cull
A competitive game of stone paper scissors involves strategy. Rather than trying to develop a model for that, though, you can save yourself some time by having the calculator select a random action. Random selections are a nifty way to accept the calculator cull a pseudorandom value.
You lot can apply random.choice() to have the estimator randomly select between the actions:
possible_actions = [ "rock" , "paper" , "scissors" ] computer_action = random . option ( possible_actions ) This allows a random chemical element to be selected from the list. You can besides print the choices that the user and the figurer made:
print ( f " \due north You chose { user_action } , figurer chose { computer_action } . \n " ) Printing the user and estimator actions tin can be helpful to the user, and it tin also aid y'all debug afterwards on in case something isn't quite correct with the outcome.
Determine a Winner
Now that both players accept fabricated their pick, yous but need a way to decide who wins. Using an if … elif … else cake, you can compare players' choices and decide a winner:
if user_action == computer_action : print ( f "Both players selected { user_action } . Information technology'southward a tie!" ) elif user_action == "rock" : if computer_action == "scissors" : print ( "Stone smashes pair of scissors! You lot win!" ) else : print ( "Paper covers rock! You lose." ) elif user_action == "paper" : if computer_action == "rock" : print ( "Paper covers rock! You win!" ) else : impress ( "Scissors cuts paper! Yous lose." ) elif user_action == "scissors" : if computer_action == "newspaper" : print ( "Scissors cuts paper! You win!" ) else : print ( "Rock smashes scissors! You lose." ) By comparing the tie status offset, you become rid of quite a few cases. If you didn't practice that, then you'd demand to check each possible action for user_action and compare it against each possible action for computer_action. By checking the tie condition first, you're able to know what the computer chose with only ii provisional checks of computer_action.
And that's it! All combined, your code should at present look like this:
import random user_action = input ( "Enter a pick (rock, paper, pair of scissors): " ) possible_actions = [ "rock" , "paper" , "scissors" ] computer_action = random . choice ( possible_actions ) print ( f " \n You chose { user_action } , computer chose { computer_action } . \north " ) if user_action == computer_action : print ( f "Both players selected { user_action } . It'south a necktie!" ) elif user_action == "stone" : if computer_action == "scissors" : print ( "Stone smashes scissors! You win!" ) else : impress ( "Paper covers rock! You lose." ) elif user_action == "paper" : if computer_action == "rock" : print ( "Paper covers rock! You win!" ) else : print ( "Scissors cuts newspaper! You lose." ) elif user_action == "scissors" : if computer_action == "paper" : print ( "Scissors cuts paper! Yous win!" ) else : print ( "Rock smashes scissors! You lose." ) You've now written code to take in user input, select a random action for the computer, and decide the winner! But this just lets you play one game earlier the program finishes running.
Play Several Games in a Row
Although a single game of rock paper scissors is super fun, wouldn't it exist better if you could play several games in a row? Loops are a great style to create recurring events. In item, y'all can apply a while loop to play indefinitely:
import random while Truthful : user_action = input ( "Enter a choice (rock, paper, scissors): " ) possible_actions = [ "rock" , "newspaper" , "scissors" ] computer_action = random . selection ( possible_actions ) print ( f " \north You chose { user_action } , computer chose { computer_action } . \n " ) if user_action == computer_action : print ( f "Both players selected { user_action } . It's a tie!" ) elif user_action == "rock" : if computer_action == "scissors" : print ( "Rock smashes scissors! You lot win!" ) else : print ( "Newspaper covers rock! Yous lose." ) elif user_action == "paper" : if computer_action == "rock" : impress ( "Paper covers rock! You win!" ) else : print ( "Scissors cuts newspaper! You lose." ) elif user_action == "scissors" : if computer_action == "paper" : print ( "Pair of scissors cuts newspaper! Y'all win!" ) else : print ( "Rock smashes scissors! You lose." ) play_again = input ( "Play again? (y/due north): " ) if play_again . lower () != "y" : break Notice the highlighted lines above. Information technology'south of import to check if the user wants to play over again and to break if they don't. Without that check, the user would be forced to play until they terminated the panel using Ctrl + C or a similar method.
The check for playing again is a check against the cord "y". But checking for something specific like this might make information technology harder for the user finish playing. What if the user types "yeah" or "no"? Cord comparison is often tricky because you never know what the user might enter. They might do all lowercase, all uppercase, or even a mixture of the two.
Here are the results of a few different string comparisons:
>>>
>>> play_again = "yes" >>> play_again == "n" Simulated >>> play_again != "y" True Hmm. That's not what you lot want. The user might non be too happy if they enter "aye" expecting to play once again merely are kicked from the game.
Describe an Action With enum.IntEnum
Because cord comparisons can crusade bug like you saw above, information technology's a expert idea to avoid them whenever possible. One of the get-go things your program asks, all the same, is for the user to input a string! What if the user inputs "Rock" or "rOck" by mistake? Capitalization matters, and so they won't be equal:
>>>
>>> impress ( "rock" == "Stone" ) Fake Since capitalization matters, "r" and "R" aren't equal. 1 possible solution would exist to use numbers instead. Assigning each activity a number could save you some problem:
ROCK_ACTION = 0 PAPER_ACTION = i SCISSORS_ACTION = 2 This allows yous to reference unlike deportment by their assigned number. Integers don't suffer the same comparison issues as strings, and so this could work. At present y'all can have the user input a number and compare information technology directly against those values:
user_input = input ( "Enter a option (rock[0], paper[1], scissors[2]): " ) user_action = int ( user_input ) if user_action == ROCK_ACTION : # Handle ROCK_ACTION Because input() returns a string, y'all need to convert the render value to an integer using int(). Then you can compare the input to each of the actions to a higher place. This works well, but information technology might rely on you naming variables correctly in order to continue track of them. A better way is to apply enum.IntEnum and define your own action form!
Using enum.IntEnum allows y'all to create attributes and assign them values similar to those shown in a higher place. This helps make clean up your code by group deportment into their own namespaces and making the code more expressive:
from enum import IntEnum form Action ( IntEnum ): Rock = 0 Paper = ane Pair of scissors = 2 This creates a custom Action that you can use to reference the different types of actions you support. It works by assigning each attribute within it to a value you specify.
Comparisons are still straightforward, and now they take a helpful course proper noun associated with them:
>>>
>>> Activeness . Rock == Action . Rock Truthful Because the member values are the same, the comparison is equal. The class names as well make it more obvious that y'all desire to compare 2 deportment.
You tin even create an Action from an int:
>>>
>>> Activity . Rock == Action ( 0 ) True >>> Action ( 0 ) <Action.Rock: 0> Action looks at the value passed in and returns the appropriate Action. This is helpful because now y'all can take in the user input every bit an int and create an Action from it. No more worrying about spelling!
The Menstruum(chart) of Your Program
Although rock newspaper pair of scissors might seem uncomplicated, it's of import to carefully consider the steps involved in playing information technology and then that yous can be sure your programme covers all possible scenarios. For any project, even small ones, it's helpful to create a flowchart of the desired behavior and implement code effectually information technology. You could achieve a similar result using a bulleted list, but it'd be harder to capture things like loops and conditional logic.
Flowcharts don't accept to be overly complicated or fifty-fifty apply real code. Just describing the desired beliefs ahead of time tin can help you set problems before they happen!
Here's a flowchart that describes a unmarried game of stone paper scissors:
Each player selects an activeness and and so a winner is determined. This flowchart is accurate for a single game every bit you've coded it, simply information technology's not necessarily authentic for existent-life games. In existent life, the players select their deportment simultaneously rather than one at a time like the flowchart suggests.
In the coded version, however, this works because the role player's choice is hidden from the computer, and the computer's choice is hidden from the player. The two players can make their choices at unlike times without affecting the fairness of the game.
Flowcharts help yous catch possible mistakes early on and besides let you see if you want to add together more functionality. For example, here'south a flowchart that describes how to play games repeatedly until the user decides to stop:
Without writing code, you can come across that the first flowchart doesn't accept a way to play again. This arroyo allows you to tackle issues like these before programming, which helps you lot create neater, more manageable lawmaking!
Divide Your Code Into Functions
Now that you've outlined the flow of your plan using a flowchart, you tin try to organize your lawmaking and then that information technology more closely resembles the steps you've identified. One natural way to do this is to create a function for each stride in the flowchart. Functions are a slap-up fashion to separate larger chunks of code into smaller, more than manageable pieces.
You don't necessarily need to create a role for the conditional check to play again, but you can if you'd like. Y'all can beginning by importing random if you haven't already and defining your Activity grade:
import random from enum import IntEnum class Action ( IntEnum ): Stone = 0 Paper = 1 Pair of scissors = ii Hopefully this all looks familiar then far! Now hither's the lawmaking for get_user_selection(), which doesn't accept in whatsoever arguments and returns an Action:
def get_user_selection (): user_input = input ( "Enter a pick (stone[0], paper[1], pair of scissors[ii]): " ) selection = int ( user_input ) action = Action ( selection ) return activity Notice how you lot take in the user input every bit an int and get back an Action. That long message for the user is a bit cumbersome, though. What would happen if y'all wanted to add more actions? Yous'd accept to add together even more than text to the prompt.
Instead, y'all can use a list comprehension to generate a portion of the input:
def get_user_selection (): choices = [ f " { action . name } [ { activeness . value } ]" for activeness in Activity ] choices_str = ", " . join ( choices ) selection = int ( input ( f "Enter a choice ( { choices_str } ): " )) action = Action ( choice ) return action Now you no longer need to worry most adding or removing actions in the future! Testing this out, you tin see how the code prompts the user and returns an activeness associated with the user's input value:
>>>
>>> get_user_selection () Enter a pick (rock[0], newspaper[1], scissors[two]): 0 <Activity.Rock: 0> Now yous demand a role for getting the computer's action. Like get_user_selection(), this function should take no arguments and return an Action. Because the values for Activeness range from 0 to 2, you're going to want to generate a random number within that range. random.randint() tin can help with that.
random.randint() returns a random value betwixt a specified minimum and maximum (inclusive). You tin use len() to help effigy out what the upper bound should be in your code:
def get_computer_selection (): selection = random . randint ( 0 , len ( Activeness ) - ane ) action = Action ( selection ) return action Because the Action values offset counting from 0, and len() starts counting from 1, it'due south of import to exercise len(Action) - 1.
When y'all test this, there won't be a prompt. It volition but render the activity associated with the random number:
>>>
>>> get_computer_selection () <Activity.Scissors: 2> Looking adept! Next, yous need a way to determine a winner. This function will accept two arguments, the user'southward activity and the reckoner'due south activeness. It doesn't need to return anything since information technology'll just brandish the result to the panel:
def determine_winner ( user_action , computer_action ): if user_action == computer_action : print ( f "Both players selected { user_action . name } . It's a tie!" ) elif user_action == Action . Rock : if computer_action == Action . Pair of scissors : impress ( "Stone smashes pair of scissors! You win!" ) else : print ( "Paper covers rock! You lose." ) elif user_action == Action . Paper : if computer_action == Activeness . Rock : print ( "Newspaper covers stone! Y'all win!" ) else : print ( "Scissors cuts paper! You lose." ) elif user_action == Action . Scissors : if computer_action == Activity . Newspaper : print ( "Scissors cuts paper! Y'all win!" ) else : print ( "Stone smashes scissors! You lose." ) This is pretty similar to the first comparison you used to determine a winner. At present you lot can just directly compare Action types without worrying about those pesky strings!
You can fifty-fifty test this out by passing different options to determine_winner() and seeing what gets printed:
>>>
>>> determine_winner ( Action . Rock , Action . Scissors ) Rock smashes scissors! You win! Since y'all're creating an activity from a number, what would happen if your user tried to create an action from 3? Remember, largest number you lot've defined so far is ii:
>>>
>>> Action ( three ) ValueError: 3 is not a valid Activity Whoops! You don't want that to happen. Where in the flowchart could you add some logic to ensure the user has entered a valid choice?
It makes sense to include the check immediately after the user has made their choice:
If the user enters an invalid value, then you repeat the step for getting the user'southward pick. The only real requirement for the user selection is that it's between 0 and 2, inclusive. If the user'due south input is outside this range, then a ValueError exception will be raised. To avert displaying the default error bulletin to the user, yous tin handle the exception.
Now that you've defined a few functions that reflect the steps in your flowchart, your game logic is a lot more organized and compact. This is all your while loop needs to contain now:
while Truthful : try : user_action = get_user_selection () except ValueError as e : range_str = f "[0, { len ( Activity ) - 1 } ]" impress ( f "Invalid choice. Enter a value in range { range_str } " ) continue computer_action = get_computer_selection () determine_winner ( user_action , computer_action ) play_again = input ( "Play once more? (y/n): " ) if play_again . lower () != "y" : break Doesn't that wait a lot cleaner? Observe how if the user fails to select a valid range, so you use proceed rather than interruption. This makes the code continue to the side by side iteration of the loop rather than break out of it.
Rock Paper Scissors … Lizard Spock
If y'all've seen The Big Bang Theory, so you may exist familiar with rock paper scissors lizard Spock. If not, then hither's a diagram depicting the game and the rules deciding the winner:
Yous tin can apply the same tools you learned about to a higher place to implement this game. For example, you could add to Activeness and create values for lizard and Spock. And so yous would just need to modify get_user_selection() and get_computer_selection() to contain these options. Updating determine_winner(), however, would be a lot more than piece of work.
Instead of calculation a lot of if … elif … else statements to your code, you tin can apply a lexicon to help show the relationships betwixt actions. Dictionaries are a not bad mode to show a cardinal-value relationship. In this case, the fundamental can be an activeness, similar scissors, and the value can be a list of actions that information technology beats.
And so what would this await like for your determine_winner() with only three options? Well, each Action can trounce merely 1 other Activeness, so the list would contain only a single detail. Here's what your code looked like before:
def determine_winner ( user_action , computer_action ): if user_action == computer_action : print ( f "Both players selected { user_action . name } . It's a necktie!" ) elif user_action == Action . Rock : if computer_action == Action . Pair of scissors : print ( "Stone smashes scissors! Yous win!" ) else : print ( "Paper covers stone! You lot lose." ) elif user_action == Activity . Paper : if computer_action == Action . Rock : impress ( "Paper covers rock! Y'all win!" ) else : impress ( "Pair of scissors cuts paper! You lose." ) elif user_action == Action . Scissors : if computer_action == Action . Paper : print ( "Scissors cuts newspaper! You win!" ) else : print ( "Rock smashes scissors! You lose." ) Now, instead of comparing to each Action, you can have a lexicon that describes the victory weather condition:
def determine_winner ( user_action , computer_action ): victories = { Activeness . Rock : [ Activity . Pair of scissors ], # Rock beats scissors Action . Newspaper : [ Action . Stone ], # Paper beats stone Activity . Scissors : [ Action . Paper ] # Scissors beats paper } defeats = victories [ user_action ] if user_action == computer_action : print ( f "Both players selected { user_action . name } . It's a tie!" ) elif computer_action in defeats : print ( f " { user_action . name } beats { computer_action . proper noun } ! You win!" ) else : print ( f " { computer_action . proper name } beats { user_action . name } ! You lose." ) You nevertheless do the same equally before and check the tie condition first. But instead of comparison each Action, you instead compare the action that the user_input beats against the computer_action. Since the key-value pair is a listing, you lot can apply the membership operator in to check if an element resides inside information technology.
Since you lot no longer employ long if … elif … else statements, information technology's relatively painless to add together checks for these new deportment. You can starting time by calculation lizard and Spock to Activeness:
grade Activity ( IntEnum ): Rock = 0 Newspaper = 1 Scissors = two Cadger = 3 Spock = four Next, add all the victory relationships from the diagram. Make sure to exercise this underneath Activeness so that victories will be able to reference everything in Activeness:
victories = { Action . Scissors : [ Action . Lizard , Action . Paper ], Action . Paper : [ Action . Spock , Activity . Rock ], Activeness . Rock : [ Action . Lizard , Activity . Scissors ], Action . Lizard : [ Action . Spock , Activity . Newspaper ], Action . Spock : [ Action . Pair of scissors , Action . Rock ] } Notice how now each Action has a list containing two elements that it beats. In the basic stone newspaper scissors implementation, there was only i element.
Because yous intentionally wrote get_user_selection() to suit new actions, you lot don't take to alter anything about that code. The same is true for get_computer_selection(). Since the length of Activity has inverse, the range of random numbers will also change.
Expect at how much shorter and more manageable the lawmaking is now! To run across the full code for your complete program, expand the box beneath.
import random from enum import IntEnum course Activity ( IntEnum ): Rock = 0 Paper = 1 Scissors = ii Lizard = 3 Spock = 4 victories = { Activity . Pair of scissors : [ Action . Cadger , Activity . Newspaper ], Action . Paper : [ Action . Spock , Action . Rock ], Action . Rock : [ Activity . Lizard , Action . Pair of scissors ], Activity . Lizard : [ Action . Spock , Action . Paper ], Action . Spock : [ Activity . Scissors , Action . Rock ] } def get_user_selection (): choices = [ f " { action . name } [ { action . value } ]" for action in Action ] choices_str = ", " . join ( choices ) option = int ( input ( f "Enter a option ( { choices_str } ): " )) action = Action ( pick ) return activeness def get_computer_selection (): selection = random . randint ( 0 , len ( Activity ) - 1 ) action = Action ( selection ) return action def determine_winner ( user_action , computer_action ): defeats = victories [ user_action ] if user_action == computer_action : print ( f "Both players selected { user_action . proper noun } . It'south a tie!" ) elif computer_action in defeats : print ( f " { user_action . name } beats { computer_action . name } ! You win!" ) else : impress ( f " { computer_action . name } beats { user_action . proper name } ! You lose." ) while True : try : user_action = get_user_selection () except ValueError as due east : range_str = f "[0, { len ( Action ) - 1 } ]" print ( f "Invalid selection. Enter a value in range { range_str } " ) go along computer_action = get_computer_selection () determine_winner ( user_action , computer_action ) play_again = input ( "Play again? (y/n): " ) if play_again . lower () != "y" : suspension That's it! You've implemented rock paper scissors cadger Spock in Python lawmaking. Double-check to brand sure you didn't miss anything and give it a playthrough.
Conclusion
Congratulations! You just finished your start Python game! You now know how to create rock newspaper scissors from scratch, and you're able to expand the number of possible actions in your game with minimal effort.
In this tutorial, you learned how to:
- Code your own rock paper scissors game
- Accept in user input with
input() - Play several games in a row using a
whileloop - Clean up your code with
Enumand functions - Describe more circuitous rules with a lexicon
These tools will continue to help you throughout your many programming adventures. If y'all have any questions, and so experience gratis to accomplish out in the comments section below.
Source: https://realpython.com/python-rock-paper-scissors/
0 Response to "Play Again In a While Loop Python"
Post a Comment