程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

[Python] my first Python game: stone, scissors, paper

編輯:Python
Recently, a fan friend chatted with yundojun Python Do a stone scissors paper game . I think about it , It's fun . In fact, game programming is a good way to learn how to program , It uses many of the tools we see in the real world , You can also play a game to test our programming results ! As Python Introduction to game programming : Rock-paper-scissors , Let's play together today .

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

What is stone, scissors, paper ?

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 .

stay Python Play a single stone scissors paper game

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 .

Receive 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 .

Computer selection

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 .

Judgement of winning or losing

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 .

Play several games in a row

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 .

enum.IntEnum Describe the action

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 !

Program flow ( chart )

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 !

Split the code and encapsulate the function

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 .

Rock Paper Scissors … Lizard Spock

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 .

summary

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 .

Reference material

[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 


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved