In this article, we will learn how to :
by scissors Game code
use input()
Receive user input
Use while
loop Play several games in succession
use Enum
and function Simplify the code
use Dictionaries Define more complex rules
Everyone has played with stone scissors and paper before . Pretend you don't know , Stone scissors paper is a hand game for two or more people to play . Participants say " stone 、 scissors 、 cloth "
, And then at the same time, squeeze their hands into stone ( fist )、 A piece of cloth ( Palm up ) Or a pair of scissors ( Put out two fingers ) The shape of the .
The rules are straightforward :
stone Smash the scissors .
cloth Wrapped in stone .
scissors Cloth cutting .
Now these rules are used , You can start thinking about how to turn them into Python Code .
Use the above description and rules , We can play a game of stone, scissors and paper . First, you need to import the module used to simulate the computer selection .
import random
Now we can use different tools in randomization to randomize the computer's actions in the game . Because our users also need to be able to choose actions , So you need to accept user input .
Get input information from the user in Python Is very direct . The goal here is to ask users what action they want to choose , Then assign this selection to a variable .
user_action = input(" Enter a selection ( stone 、 scissors 、 cloth ):")
This will prompt the user to enter a selection , And save it in a variable for later use . After the user has selected an action , It's the computer's turn to decide what to do .
The competitive game of stone, scissors and paper involves strategy
Someone is also studying and writing an academic paper on the strategy of the stone scissors paper game , Interested partners can view the paper ( Portal :https://arxiv.org/pdf/1404.5199v1.pdf)
Researchers 360 Students are divided into groups of six , Let them play in random pairs 300 Round stone scissors cloth . Students get a small amount of money every time they win a round of competition . As they play the game , The researchers looked at how players rotated among three game options when winning or losing .
They found that ,“ If a player wins a game , Her probability of repeating the same action in the next game is much higher than her probability of changing her action .” If a player loses two or more times , She is likely to change the way she plays , And it's more likely to turn to being able to beat her opponent who just beat her than her opponent who just beat her . for example , If Xiaohong loses by playing scissors with Xiaoming's stone , Xiaohong is most likely to change to paper , This will defeat Xiao Ming's stone . According to the research , This is a reasonable strategy , Because Xiao Ming is likely to continue to play the winning action . The author calls this “ win - leave , transport - shift ” Strategy .
therefore , This is the best way to win on scissors, stone and cloth : If you lose the first round , Switch to the action you just played to defeat your opponent . If you win , Don't continue to do the same , Instead, change to something that beats the action you just played . let me put it another way , Play what your defeated opponent just played . in other words : You won a round of other people's scissors with a stone , They are about to switch to cloth , You should use scissors instead .
According to the above game strategy , Trying to develop a model , It should take a lot of time . For simplicity , We Let the computer choose a random action To save some time . Random selection is to let the computer choose a pseudo-random value .
have access to random.choice()
To let the computer choose randomly among these actions .
possible_actions = [" stone ", " scissors ", " cloth "]
computer_action = random.choice(possible_actions)
This allows you to select a random element from the list . We can also print out user and computer choices .
print(f"\n You chose {user_action},
The computer selected {computer_action}.\n")
Printout users and computer operations are helpful to users , It can also help us in future debugging , In case the result is not right .
Now? , Both players have made a choice , We just need to use if ... elif ... else Code block
Method to decide who wins and who loses , Then compare the players' choices and decide the winner .
if user_action == computer_action:
print(f" Both players have chosen {user_action}. It was a draw !")
elif user_action == " stone ":
if computer_action == " scissors ":
print(" The stone smashes the scissors ! You win !")
else:
print(" The cloth covers the stone ! Did you lose .")
elif user_action == " cloth ":
if computer_action == " stone ":
print(" The cloth covers the stone ! You win !")
else:
print(" Scissors cut rags ! Did you lose .")
elif user_action == " scissors ":
if computer_action == " cloth ":
print(" Scissors cut rags ! You win !")
else:
print(" The stone smashes the scissors ! Did you lose .")
By comparing the draw conditions first , We got rid of quite a few situations . Otherwise we need to check user_action
Every possible action of , And with computer_action
Compare every possible action of . By first checking the draw conditions , We can know what the computer has chosen , Only need to computer_action
Perform two condition checks .
So the complete code should now look like this :
Slide up and down to see more source code
import random
user_action = input(" Enter a selection ( stone 、 scissors 、 cloth ):")
possible_actions = [" stone ", " scissors ", " cloth "]
computer_action = random.choice(possible_actions)
print(f"\n You chose {user_action}, The computer selected {computer_action}.\n")
if user_action == computer_action:
print(f" Both players have chosen {user_action}. It was a draw !")
elif user_action == " stone ":
if computer_action == " scissors ":
print(" The stone smashes the scissors ! You win !")
else:
print(" The cloth covers the stone ! Did you lose .")
elif user_action == " cloth ":
if computer_action == " stone ":
print(" The cloth covers the stone ! You win !")
else:
print(" Scissors cut rags ! Did you lose .")
elif user_action == " scissors ":
if computer_action == " cloth ":
print(" Scissors cut rags ! You win !")
else:
print(" The stone smashes the scissors ! Did you lose .")
Now we have written the code , Can accept user input , And choose a random action for the computer , The final decision ! This rudimentary code can only let us play a game with the computer .
Although the single scissors stone cloth game is more interesting , But if we can play a few games in a row , Isn't it better ? Now we think of loop Is a good way to create recurring events . We can use one while loop To play this game indefinitely .
import random
while True:
# Enclose the complete code
play_again = input("Play again? (y/n): ")
if play_again.lower() != "y":
break
Notice the code we added , Check if the user wants to play again , If they don't want to play, break it , This is important . If you don't have this check , Users will be forced to play , Until they use Ctrl+C
Or other methods to force the termination of the program .
The check for playback again is for the string "y"
The inspection of . however , Checking certain things like this may make it harder for users to stop the game . If user input "yes"
or "no"
What do I do ? String comparisons are often tricky , Because we never know what the user may enter . They might do all the lowercase letters , All capital letters , Even input Chinese .
Here are the results of several different string comparisons .
>>> play_again = "yes"
>>> play_again == "n"
False
>>> play_again != "y"
True
Actually, this is not what we want . If user input "yes"
, Expect to play again , But was kicked out of the game , They may not be too happy .
In the previous schematic code , Defines a Chinese string , But in practice python When developing , Generally, Chinese is not used in the code ( Except for the notes ), Therefore, it is necessary to understand this section .
So we will translate the stone scissors cloth into :"rock", "scissors", "paper"
.
String comparisons can cause problems like the one we saw above , Therefore, it is necessary to avoid . However , The first thing our program requires is for the user to enter a string ! If the user mistakenly enters "Rock " or "rOck " What do I do ? If the user mistakenly enters "Rock " or "rOck " What do I do ? Capital letters are important , So they won't be equal .
>>> print("rock" == "Rock")
False
Because capital letters are important , therefore "r"
and "R"
It's not equal . One possible solution is to replace... With numbers . Assigning a number to each action can save us some trouble .
ROCK_ACTION = 0
SCISSORS_ACTION = 1
PAPER_ACTION = 2
We quote different actions through the assigned numbers , Integers do not have the same comparison problems as strings , So it's possible . Now let the user enter a number , And compare directly with these values .
user_input = input(" Enter your selection ( stone [0], scissors [1], cloth [2]): ")
user_action = int(user_input)
if user_action == ROCK_ACTION:
# Handle ROCK_ACTION
because input()
Returns a string , Need to use int()
Convert the return value to an integer . You can then compare the input value with each of the above actions . Although it works well , But it may depend on the correct naming of variables . Actually, a better way is to use **enum.IntEnum
** Customize action classes .
We use enum.IntEnum
Create attributes and assign them values similar to those shown above , Put actions into their own namespace , Make the code more expressive .
from enum import IntEnum
class Action(IntEnum):
Rock = 0
Scissors = 1
Paper = 2
This creates a custom Action
, It can be used to refer to the different types of Action
. It works by assigning each of these attributes to a value we specify .
The comparison of the two movements is straightforward , Now they have a useful class name associated with it .
>>> Action.Rock == Action.Rock
True
Because the values of members are the same , So the results of the comparison are equal . The name of the class also makes it more obvious that we want to compare the two actions .
Be careful : To learn more about enum Information about , Please check the official documents [1].
We can even start from a int
Create a Action
.
>>> Action.Rock == Action(0)
True
>>> Action(0)
<Action.Rock: 0>
Action View the passed in value and return the appropriate Action. So now you can use the user's input as a int
, And create a Action, Mom doesn't have to worry about spelling anymore !
Although scissors, stone and cloth don't look complicated , But it is very important to carefully consider the steps of playing with scissors, stone and cloth , This ensures that our procedures cover all possible situations . For any project , Even small projects , It is necessary to create a desired behavior flow chart And implement the code around it . We can use a list to achieve a similar effect , But it is more difficult to capture logic such as loops and conditions .
The flowchart does not need to be too complex , You don't even need to use real code . Just describe the desired behavior in advance , It can help us solve problems before they happen
Here's a flow chart , Describes a single scissors stone paper game .
Each player chooses an action , Then identify a winner . This flow chart is accurate for the individual games we code , But it is not necessarily accurate for games in real life . in real life , Players will also choose their actions , Instead of one at a time as suggested in the flowchart .
However , In the encoded version , This is feasible , Because the player's choice is hidden from the computer , The choice of computer is also hidden from players . Two players can make choices at different times without affecting the fairness of the game .
Flow charts can help us find possible errors at an early stage , It also allows us to see if we need to add more functions . For example, this flow chart , Describes how to play the game repeatedly , Until the user decides to stop .
If you don't write code , We can see that there is no way to repeat the first flow chart . We can use this flow chart method to solve similar problems before programming , This will help us code more neatly 、 More manageable code !
Now I have outlined the flow of the program with a flowchart , We can try to organize our code , Bring it closer to the identified steps . One way is to create a function for each step in the flowchart . In fact, function is a good method , You can split large pieces of code into smaller pieces 、 The easier part to manage .
We don't have to create a function for the playback of the condition check , But if we want to , We can . If we haven't , We can start by importing random , And define our Action class .
import random
from enum import IntEnum
class Action(IntEnum):
Rock = 0
Scissors = 1
Paper = 2
So let's define get_user_selection()
Code for , It takes no arguments and returns a Action
.
def get_user_selection():
user_input = input(" Enter your selection ( stone [0], scissors [1], cloth [2]):")
selection = int(user_input)
action = Action(selection)
return action
Notice how the user's input is used as a int
, And then get a Action
. however , The long message to the user is a little troublesome . If we want to add more moves , You have to add more text to the prompt .
We can use a list derivation to generate part of the input .
def get_user_selection():
choices = [f"{action.name}[{action.value}]" for action in Action]
choices_str = ", ".join(choices)
selection = int(input(f" Output your selection ({choices_str}): "))
action = Action(selection)
return action
There is no need to worry about adding or deleting actions in the future ! Let's test it , We can see how the code prompts the user and returns an action related to the user's input value .
>>> get_user_selection()
Enter your selection ( stone [0], scissors [1], cloth [2]): 0
<Action.Rock: 0>
Now we need a function to get the action of the computer . and get_user_selection()
equally , This function should not require arguments , And return a Action
. because Action
The value range of is 0 To 2
, So use random.randint()
Help us generate a random number in this range .
random.randint()
Returns a specified minimum and maximum value ( Include ) The random value between . have access to len()
To help calculate the upper limit in the code .
def get_computer_selection():
selection = random.randint(0, len(Action) - 1)
action = Action(selection)
return action
because Action
From 0 Start calculating , and len()
from 1 Start calculating , So we need to do an extra len(Action)-1
.
Test the function , It simply returns actions related to random numbers .
>>> get_computer_selection()
<Action.Scissors: 2>
It looks good ! Next , You need a function to decide whether to win or lose , This function will take two arguments , User actions and computer actions . It just needs to display the results on the console , Without having to return anything .
def determine_winner(user_action, computer_action):
if user_action == computer_action:
print(f" Both players have chosen {user_action.name}. It was a draw !")
elif user_action == Action.Rock:
if computer_action == Action.Scissors:
print(" The stone smashes the scissors ! You win !")
else:
print(" The cloth covers the stone ! Did you lose .")
elif user_action == Action.Paper:
if computer_action == Action.Rock:
print(" The cloth covers the stone ! You win !")
else:
print(" Scissors cut rags ! Did you lose .")
elif user_action == Action.Scissors:
if computer_action == Action.Paper:
print(" Scissors cut rags ! You win !")
else:
print(" The stone smashes the scissors ! Did you lose .")
The winning or losing script here is very similar to the initial code . Now you can directly compare the types of actions , Don't worry about those annoying strings !
We can even talk to determinal_winner()
Pass different parameters to test the function , See what will print out .
>>> determine_winner(Action.Rock, Action.Scissors)
The stone smashes the scissors ! You win !
Since we want to create an action from a number , If the user wants to use numbers 3 Create an action , What's going to happen ?( The maximum number we define is 2).
>>> Action(3)
ValueError: 3 is not a valid Action
Wrong report ! This is not what we want to happen . Next, you can add some logic to the flowchart , To supplement this bug, To ensure that the user always enters a valid selection .
It makes sense to join the check immediately after the user makes a choice .
If the user enters an invalid value , Then we will repeat this step to get the user's choice . The only real requirement for user choice is that it is in 【0, 1, 2】 A number between . If the user's input exceeds this range , Then there will be one ValueError different often . We can Handle This anomaly , The default error message will not be displayed to the user .
Now we have defined some functions that reflect the steps in the flowchart , Our game logic is more organized and compact . This is our while loop Everything you need to include now .
while True:
try:
user_action = get_user_selection()
except ValueError as e:
range_str = f"[0, {len(Action) - 1}]"
print(f"Invalid selection. Enter a value in range {range_str}")
continue
computer_action = get_computer_selection()
determine_winner(user_action, computer_action)
play_again = input("Play again? (y/n): ")
if play_again.lower() != "y":
break
Does this look much cleaner ? Be careful , If the user fails to select a valid range , Then we use continue
instead of break
. This causes the code to continue to the next iteration of the loop , Instead of jumping out of the loop .
If we've seen 《 The big bang theory 》, Then we may be familiar with the stone scissors cloth Lizard Spock . without , So here is a picture , Describes the game and the rules that determine the outcome .
We can use the same tools we learned above to implement this game . for example , We can do it in Action Add Lizard
and Spock
Value . Then we just need to modify get_user_selection()
and get_computer_selection()
, To include these options . However , to update determinal_winner()
.
Instead of adding a lot of if ... elif ... else
sentence , We can use dictionaries to help show the relationship between actions . The dictionary is showing Key value relationship It's a good way to . under these circumstances , key It can be an action , Like scissors , and value It can be a list of the actions it defeats .
that , For those with only three options determinal_winner()
Come on , What will this look like ? ok , Every Action
Only one other can be defeated Action
, So the list contains only one item . Here is what our 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 tie!")
elif user_action == Action.Rock:
if computer_action == Action.Scissors:
print("Rock smashes scissors! You win!")
else:
print("Paper covers rock! You lose.")
elif user_action == Action.Paper:
if computer_action == Action.Rock:
print("Paper covers rock! You win!")
else:
print("Scissors cuts cpaper! You lose.")
elif user_action == Action.Scissors:
if computer_action == Action.Paper:
print("Scissors cuts cpaper! You win!")
else:
print("Rock smashes scissors! You lose.")
Now? , We can have a dictionary that describes the conditions of victory , Instead of comparing each action .
def determine_winner(user_action, computer_action):
victories = {
Action.Rock: [Action.Scissors], # Rock beats scissors
Action.Paper: [Action.Rock], # Paper beats rock
Action.Scissors: [Action.Paper] # Scissors beats cpaper
}
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.name}! You win!")
else:
print(f"{computer_action.name} beats {user_action.name}! You lose.")
We are still the same as before , First check the draw conditions . But we don't compare every one Action
, Instead, compare the user input Action
And computer input Action
. Since the key value pair is a list , We can use the member operator in
To check whether an element is in it .
Because we no longer use lengthy if ... elif ... else
sentence , Adding checks for these new actions is relatively easy . We can put Lizard
and Spock
Add to Action in .
class Action(IntEnum):
Rock = 0
Scissors = 1
Paper = 2
Lizard = 3
Spock = 4
Next , Add all winning relationships from the graph .
victories = {
Action.Scissors: [Action.Lizard, Action.Paper],
Action.Paper: [Action.Spock, Action.Rock],
Action.Rock: [Action.Lizard, Action.Scissors],
Action.Lizard: [Action.Spock, Action.Paper],
Action.Spock: [Action.Scissors, Action.Rock]
}
Be careful , Now each Action
There is a list of two elements that can be defeated . And in the basic " scissors "
In the implementation , There's only one element .
We wrote get_user_selection()
To adapt to new movements , So there is no need to change anything in the code .get_computer_selection()
The same is true of . because Action
There's been a change in the length of , The range of random numbers will also change .
See how simple the code is now , How easy it is to maintain and manage ! The complete code of the complete program :
Slide up and down to see more source code
import random
from enum import IntEnum
class Action(IntEnum):
Rock = 0
Paper = 1
Scissors = 2
Lizard = 3
Spock = 4
victories = {
Action.Scissors: [Action.Lizard, Action.Paper],
Action.Paper: [Action.Spock, Action.Rock],
Action.Rock: [Action.Lizard, Action.Scissors],
Action.Lizard: [Action.Spock, Action.Paper],
Action.Spock: [Action.Scissors, Action.Rock]
}
def get_user_selection():
choices = [f"{action.name}[{action.value}]" for action in Action]
choices_str = ", ".join(choices)
selection = int(input(f"Enter a choice ({choices_str}): "))
action = Action(selection)
return action
def get_computer_selection():
selection = random.randint(0, len(Action) - 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.name}. It's a tie!")
elif computer_action in defeats:
print(f"{user_action.name} beats {computer_action.name}! You win!")
else:
print(f"{computer_action.name} beats {user_action.name}! You lose.")
while True:
try:
user_action = get_user_selection()
except ValueError as e:
range_str = f"[0, {len(Action) - 1}]"
print(f"Invalid selection. Enter a value in range {range_str}")
continue
computer_action = get_computer_selection()
determine_winner(user_action, computer_action)
play_again = input("Play again? (y/n): ")
if play_again.lower() != "y":
break
So far we have used Python The code implements rock paper scissors lizard Spock
. Then you can check it carefully , Make sure we don't miss anything , Then play a game .
See here , You have to like it , Because we just finished the first Python game . Now? , We learned how to create a scissors, stone and paper game from scratch , And I can expand the number of possible actions in the game at the least cost .
[1]
Official documents : https://docs.python.org/3/library/enum.html
Past highlights
It is suitable for beginners to download the route and materials of artificial intelligence ( Image & Text + video ) Introduction to machine learning series download Chinese University Courses 《 machine learning 》( Huang haiguang keynote speaker ) Print materials such as machine learning and in-depth learning notes 《 Statistical learning method 》 Code reproduction album machine learning communication qq Group 955171419, Please scan the code to join wechat group