DEV Community

Cover image for สร้างเกม เป่ายิ้งฉุบ! โดย Python
Pattarawan-012
Pattarawan-012

Posted on

สร้างเกม เป่ายิ้งฉุบ! โดย Python

เป่ายิ้งฉุบคืออะไร?
คุณอาจเคยเล่นเป่ายิ้งฉุบมาก่อน บางทีอาจจะใช้มันเพื่อตัดสินว่าใครจ่ายค่าอาหารหรือใครจะเป็นคนแรกของเกม

หากไม่คุ้นเคย เป่ายิ้งฉุบเป็นเกมมือสำหรับผู้เล่นสองคนขึ้นไป ผู้เล่นพูดว่า "เป่ายิ้งฉุบ"

  1. ค้อน >> กำมือ 2.กระดาษ >> เเบมือ 3.กรรไกร >> ชูสองนิ้

กฎมีดังนี้:

  • กรรไกรทุบหิน
  • กระดาษครอบหิน
  • กรรไกรตัดกระดาษ

เมื่อทราบกฏเเล้ว จึงเริ่มคิดว่ากฎเหล่านี้จะแปลเป็น Python ได้อย่างไร

เล่นเกมเป่ายิ้งฉุบเกมเดียวใน Python
คุณสามารถสร้างเกมเป่ายิ้งฉุบได้โดยใช้คำอธิบายและกฎด้านบน ก่อนที่จะเริ่มเล่นเกม คุณจะต้องนำเข้าโมดูลที่คุณจะใช้เพื่อจำลองการเล่นของคอมพิวเตอร์:

import random
Enter fullscreen mode Exit fullscreen mode

รับอินพุตของผู้ใช้
การรับข้อมูลจากผู้ใช้นั้นค่อนข้างตรงไปตรงมาใน Python เป้าหมายในที่นี้คือการถามผู้เล่นว่าต้องการเลือกอะไร(ค้อน กรรไกร กระดาษ) จากนั้นกำหนดตัวเลือกนั้นให้กับตัวแปร:

user_action = input("Enter a choice (rock, paper, scissors): ")
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ :
Image description
จำลองการเล่น :

Image description
จากรูปที่เเสดงจะแจ้งให้ผู้เล่นป้อนการเลือกและบันทึกลงในตัวแปรเพื่อใช้ในภายหลัง เมื่อผู้เล่นเลือกเเล้ว ต่อไปคอมพิวเตอร์จะประมวลว่าควรเลือกอะไร (ค้อน กรรไกร กระดาษ)

ให้คอมพิวเตอร์เลือก
เกมเป่ายิ้งฉุบที่แข่งขันกันด้วยกลยุทธ์ แทนที่จะพยายามพัฒนาแบบจำลองสำหรับเกมนี้ เพื่อประหยัดเวลาได้ ด้วยการให้คอมพิวเตอร์เลือกการกระทำแบบสุ่ม การเลือกแบบสุ่มเป็นวิธีที่ดีในการใช้คอมพิวเตอร์เลือกค่าสุ่มเทียม

ใช้คำสั่ง Random.choice() เพื่อให้คอมพิวเตอร์สุ่ม:

possible_actions = ["rock", "paper", "scissors"]
computer_action = random.choice(possible_actions)
Enter fullscreen mode Exit fullscreen mode

คำสั่งนี้ทำให้สามารถเลือกองค์ประกอบแบบสุ่มได้จากการที่ ผู้เล่นสามารถพิมพ์ตัวเลือกได้:

print(f"\nYou chose {user_action}, computer chose {computer_action}.\n")
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ :

Image description

การพิมพ์ตัวเลือกของผู้เล่นและคอมพิวเตอร์จะเป็นประโยชน์กับผู้ใช้ และยังช่วยให้สามารถแก้ไขจุดบกพร่องได้ในภายหลังในกรณีที่มีบางอย่างไม่ถูกต้องกับผลลัพธ์

การกำหนดผู้ชนะ
ตอนนี้ผู้เล่นทั้งสองได้เลือกแล้ว แค่ต้องการวิธีตัดสินว่าใครจะชนะ
โดยการใช้บล็อก if … elif … else สามารถเปรียบเทียบตัวเลือกของผู้เล่นและตัดสินผู้ชนะได้ โดยใช้คำสั่งดังต่อไปนี้:

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 win!")
    else:
        print("Paper covers rock! You lose.")
elif user_action == "paper":
    if computer_action == "rock":
        print("Paper covers rock! You win!")
    else:
        print("Scissors cuts paper! You lose.")
elif user_action == "scissors":
    if computer_action == "paper":
        print("Scissors cuts paper! You win!")
    else:
        print("Rock smashes scissors! You lose.")
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ :

Image description

โดยการเปรียบเทียบการผูกก่อนเงื่อนไข โดยจะกำจัดกรณีเล็กๆ หากไม่ได้ทำจะต้องตรวจสอบการดำเนินการที่เป็นไปได้แต่ละรายการสำหรับ user_action และเปรียบเทียบกับการดำเนินการที่เป็นไปได้สำหรับ computer_action โดยการตรวจสอบเงื่อนไขการเสมอกันก่อน คจะสามารถทราบได้ว่าคอมพิวเตอร์เลือกอะไรด้วยการตรวจสอบเงื่อนไขเพียงสองครั้งของ computer_action

*เมื่อเขียนโค้ดรวมกันทั้งหมดจะเเสดงได้ดังนี้ :
*

import random

user_action = input("Enter a choice (rock, paper, scissors): ")
possible_actions = ["rock", "paper", "scissors"]
computer_action = random.choice(possible_actions)
print(f"\nYou 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 win!")
    else:
        print("Paper covers rock! You lose.")
elif user_action == "paper":
    if computer_action == "rock":
        print("Paper covers rock! You win!")
    else:
        print("Scissors cuts paper! You lose.")
elif user_action == "scissors":
    if computer_action == "paper":
        print("Scissors cuts paper! You win!")
    else:
        print("Rock smashes scissors! You lose.")
Enter fullscreen mode Exit fullscreen mode

เขียนโค้ดเพื่อรับอินพุตจากผู้เล่น เลือกแบบสุ่มสำหรับคอมพิวเตอร์ และตัดสินผู้ชนะ! แต่สามารถเล่นได้เพียงหนึ่งเกมก่อนที่โปรแกรมจะทำงานเสร็จ

เล่นหลายเกมติดต่อกัน
แม้ว่าเกมเป่ายิ้งฉุบเกมเดียวจะสนุก แต่จะดีกว่าไหมถ้าสามารถเล่นหลาย ๆ เกมติดต่อกันได้ การเล่นซ้ำเป็นวิธีที่ดีที่สุด โดยเฉพาะอย่างยิ่ง คุณสามารถใช้การวนซ้ำแบบ while เพื่อเล่นแบบไม่มีกำหนด:

import random

while True:
    user_action = input("Enter a choice (rock, paper, scissors): ")
    possible_actions = ["rock", "paper", "scissors"]
    computer_action = random.choice(possible_actions)
    print(f"\nYou 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 win!")
        else:
            print("Paper covers rock! You lose.")
    elif user_action == "paper":
        if computer_action == "rock":
            print("Paper covers rock! You win!")
        else:
            print("Scissors cuts paper! You lose.")
    elif user_action == "scissors":
        if computer_action == "paper":
            print("Scissors cuts paper! You win!")
        else:
            print("Rock smashes scissors! You lose.")
Enter fullscreen mode Exit fullscreen mode

Highlighted
play_again = input("Play again? (y/n): ")
if play_again.lower() != "y":
break

ผลลัพธ์

Image description

สังเกตโค้ดที่ไฮไลต์ด้านบน สิ่งสำคัญคือต้องตรวจสอบว่าผู้ใช้ต้องการเล่นอีกครั้งหรือไม่และหยุดเล่นหากไม่ต้องการ หากไม่มีการตรวจสอบ ผู้เล่นจะถูกบังคับให้เล่นจนกว่าจะยุติคอนโซลโดยใช้ Ctrl+C

การตรวจสอบการเล่นซ้ำเป็นการตรวจสอบสตริง "y" แต่การตรวจสอบสิ่งที่เฉพาะเจาะจงเเบบนี้อาจทำให้ผู้ใช้หยุดเล่นได้ยาก เเล้วถ้าหากผู้ใช้พิมพ์ "yes" หรือ "no" การเปรียบเทียบสตริงมักยุ่งยากเพราะไม่มีทางรู้ว่าผู้เล่นจะป้อนอะไร พวกเขาอาจใช้ตัวพิมพ์เล็กทั้งหมด ตัวพิมพ์ใหญ่ทั้งหมด หรือทั้งสองอย่างผสมกัน

นี่คือผลลัพธ์ของการเปรียบเทียบสตริงที่แตกต่างกัน:

>>> play_again = "yes"
>>> play_again == "n"
False
>>> play_again != "y"
True
Enter fullscreen mode Exit fullscreen mode

เเต่นั่นไม่ใช่สิ่งที่ผู้เล่นต้องการ ผู้เล่นอาจจะไม่พอใจหากป้อน "yes" โดยคาดว่าจะเล่นอีกครั้งแต่ถูกเตะออกจากเกม

อธิบายการดำเนินการด้วย enum.IntEnum
เนื่องจากการเปรียบเทียบสตริงอาจทำให้เกิดปัญหาอย่างที่เห็นด้านบน จึงควรหลีกเลี่ยงหากทำได้ อย่างไรก็ตาม สิ่งแรกที่โปรแกรมของคุณถามคือให้ผู้ใช้ป้อนสตริง! จะเกิดอะไรขึ้นหากผู้ใช้ป้อน "Rock" หรือ "rOck" โดยไม่ได้ตั้งใจ การใช้อักษรตัวพิมพ์ใหญ่มีความสำคัญ ดังนั้นจึงไม่เท่ากัน:

>>> print("rock" == "Rock")
False
Enter fullscreen mode Exit fullscreen mode

เนื่องจากการใช้อักษรตัวพิมพ์ใหญ่มีความสำคัญ "r" และ "R" จึงไม่เท่ากัน วิธีหนึ่งที่เป็นไปได้คือใช้ตัวเลขแทน การกำหนดตัวเลขให้แต่ละการกระทำสามารถช่วยคุณแก้ปัญหาได้:

ROCK_ACTION = 0
PAPER_ACTION = 1
SCISSORS_ACTION = 2
Enter fullscreen mode Exit fullscreen mode

สิ่งนี้ทำให้คุณสามารถอ้างอิงการกระทำต่างๆ ตามหมายเลขที่กำหนด จำนวนเต็มจะไม่เจอปัญหาการเปรียบเทียบเช่นเดียวกับสตริง ดังนั้นวิธีนี้จึงใช้ได้ ตอนนี้สามารถให้ผู้เล่นป้อนตัวเลขและเปรียบเทียบกับค่าได้โดยตรง:

user_input = input("Enter a choice (rock[0], paper[1], scissors[2]): ")
user_action = int(user_input)
if user_action == ROCK_ACTION:
    # Handle ROCK_ACTION
Enter fullscreen mode Exit fullscreen mode

เนื่องจาก input() ส่งคืนสตริง ต้องแปลงค่าที่ส่งคืนเป็นจำนวนเต็มโดยใช้ int() จากนั้นสามารถเปรียบเทียบอินพุตกับแต่ละค่าด้านบน วิธีนี้ใช้ได้ดี แต่อาจต้องพึ่งการตั้งชื่อตัวแปรอย่างถูกต้องเพื่อติดตามตัวแปรทั้งหมด วิธีที่ดีกว่าคือการใช้ enum.IntEnum และกำหนดคลาสได้

การใช้ enum.IntEnum ช่วยให้สร้างแอตทริบิวต์และกำหนดค่าให้คล้ายกับที่แสดงด้านบน สิ่งนี้จะช่วยล้างโค้ดของคุณโดยจัดกลุ่มลงในเนมสเปซของตนเอง :

from enum import IntEnum

class Action(IntEnum):
    Rock = 0
    Paper = 1
    Scissors = 2
Enter fullscreen mode Exit fullscreen mode

การดำเนินการนี้จะสร้างการดำเนินการแบบกำหนดเองที่สามารถใช้เพื่ออ้างอิงการดำเนินการประเภทต่างๆ ที่สนับสนุนการทำงานโดยกำหนดแต่ละแอตทริบิวต์ภายในให้เป็นค่าที่คุณระบุ

การเปรียบเทียบยังคงตรงไปตรงมาเเละมีชื่อคลาสที่เป็นประโยชน์ที่เกี่ยวข้อง:

>>> Action.Rock == Action.Rock
True
Enter fullscreen mode Exit fullscreen mode

เนื่องจากค่าสมาชิกเท่ากัน การเปรียบเทียบจึงเท่ากัน ชื่อคลาสยังทำให้ชัดเจนขึ้นว่าต้องการเปรียบเทียบสองการกระทำ

Note: To learn more about enum, check out the Build Enumerations of Constants With Python’s Enum.
Enter fullscreen mode Exit fullscreen mode

สามารถสร้าง Action จาก int:

>>> Action.Rock == Action(0)
True
>>> Action(0)
<Action.Rock: 0>
Enter fullscreen mode Exit fullscreen mode

การดำเนินการจะพิจารณาค่าที่ส่งผ่านและส่งคืนการดำเนินการที่เหมาะสม สิ่งนี้มีประโยชน์เพราะสามารถรับอินพุตของผู้เล่นเป็น int และสร้างการดำเนินการจากมันได้ ไม่ต้องกังวลกับการสะกดอีกต่อไป

แยกโค้ดออกเป็นฟังก์ชัน
ตอนนี้ได้สรุปโฟลว์ของโปรแกรมของคุณโดยใช้ผังงานแล้ว สามารถลองจัดระเบียบโค้ดของเพื่อให้คล้ายกับขั้นตอนที่คุณระบุมากขึ้น วิธีหนึ่งในการทำเช่นนี้คือการสร้างฟังก์ชันสำหรับแต่ละขั้นตอนในผังงาน ฟังก์ชันเป็นวิธีที่ยอดเยี่ยมในการแยกโค้ดขนาดใหญ่ออกเป็นส่วนย่อยๆ ที่สามารถจัดการได้มากขึ้น

คุณไม่จำเป็นต้องสร้างฟังก์ชันสำหรับการตรวจสอบเงื่อนไขเพื่อเล่นอีกครั้ง แต่คุณสามารถทำได้หากต้องการสามารถเริ่มต้นด้วยการนำเข้าแบบสุ่มหากยังไม่ได้ทำ และกำหนดคลาส Action :

import random
from enum import IntEnum

class Action(IntEnum):
    Rock = 0
    Paper = 1
    Scissors = 2
Enter fullscreen mode Exit fullscreen mode

ต่อไปนี้เป็นโค้ดสำหรับ get_user_selection() ซึ่งไม่ใช้อาร์กิวเมนต์ใดๆ และคืนค่า Action:

def get_user_selection():
    user_input = input("Enter a choice (rock[0], paper[1], scissors[2]): ")
    selection = int(user_input)
    action = Action(selection)
    return action
Enter fullscreen mode Exit fullscreen mode

สังเกตว่าใช้อินพุตของผู้เล่นเป็น int และรับกลับเป็น Action อย่างไร ข้อความที่ยาวสำหรับผู้เล่นนั้นค่อนข้างยุ่งยาก จะเกิดอะไรขึ้นถ้าต้องการเพิ่มการดำเนินการอื่นๆ ต้องเพิ่มข้อความเพิ่มเติมในพรอมต์

สามารถใช้รายการความเข้าใจเพื่อสร้างส่วนของอินพุตแทน:

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
Enter fullscreen mode Exit fullscreen mode

การทดสอบนี้ จะเห็นวิธีที่โค้ดแจ้งผู้ใช้และส่งคืนการดำเนินการที่เกี่ยวข้องกับค่าอินพุตของผู้เล่น:

>>> get_user_selection()
Enter a choice (rock[0], paper[1], scissors[2]): 0
<Action.Rock: 0>
Enter fullscreen mode Exit fullscreen mode

ตอนนี้ต้องการฟังก์ชันสำหรับรับคำสั่งของคอมพิวเตอร์ เช่นเดียวกับ get_user_selection() ฟังก์ชันนี้ไม่ควรใช้อาร์กิวเมนต์และส่งคืนการดำเนินการ เนื่องจากค่าสำหรับ Action มีตั้งแต่ 0 ถึง 2 คุณจึงต้องการสร้างตัวเลขสุ่มภายในช่วงนั้น Random.randint() สามารถช่วยได้

Random.randint() ส่งกลับค่าสุ่มระหว่างค่าต่ำสุดและค่าสูงสุดที่ระบุ (รวม)สามารถใช้ len() เพื่อช่วยหาขอบเขตบนที่ควรจะเป็นในโค้ด:

def get_computer_selection():
    selection = random.randint(0, len(Action) - 1)
    action = Action(selection)
    return action
Enter fullscreen mode Exit fullscreen mode

เนื่องจากค่า Action เริ่มนับจาก 0 และ len() เริ่มนับจาก 1 จึงเป็นสิ่งสำคัญที่ต้องทำ len(Action) - 1

เมื่อทดสอบสิ่งนี้ จะไม่มีการแจ้ง มันจะส่งคืนการกระทำที่เกี่ยวข้องกับตัวเลขสุ่ม:

>>> get_computer_selection()
<Action.Scissors: 2>
Enter fullscreen mode Exit fullscreen mode

ต่อไป คุณต้องหาวิธีตัดสินผู้ชนะ ฟังก์ชันนี้จะรับอาร์กิวเมนต์สองรายการ ได้แก่ การกระทำของผู้ใช้และการกระทำของคอมพิวเตอร์ ไม่จำเป็นต้องส่งคืนสิ่งใดเนื่องจากจะแสดงผลไปยังคอนโซล:

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 paper! You lose.")
    elif user_action == Action.Scissors:
        if computer_action == Action.Paper:
            print("Scissors cuts paper! You win!")
        else:
            print("Rock smashes scissors! You lose.")

Enter fullscreen mode Exit fullscreen mode

สิ่งนี้ค่อนข้างคล้ายกับการเปรียบเทียบครั้งแรกที่ใช้ในการตัดสินผู้ชนะ ตอนนี้สามารถเปรียบเทียบประเภทการกระทำได้โดยตรงโดยไม่ต้องกังวลกับสตริง

ยังสามารถทดสอบได้โดยส่งตัวเลือกต่างๆ เพื่อตรวจสอบว่าจะพิมพ์ออกมาอย่างไร:

>>> determine_winner(Action.Rock, Action.Scissors)
Rock smashes scissors! You win!
Enter fullscreen mode Exit fullscreen mode

เนื่องจากกำลังสร้างการดำเนินการจากตัวเลข จะเกิดอะไรขึ้นหากผู้ใช้ของคุณพยายามสร้างการดำเนินการจาก 3 โปรดจำไว้ว่าจำนวนสูงสุดที่คุณกำหนดไว้คือ 2:

>>> Action(3)
ValueError: 3 is not a valid Action
Enter fullscreen mode Exit fullscreen mode

อ๊ะ! คุณไม่ต้องการให้เกิดขึ้น สามารถเพิ่มตรรกะที่ใดในผังงานเพื่อให้แน่ใจว่าผู้เล่นป้อนตัวเลือกที่ถูกต้อง

ควรรวมเช็คทันทีหลังจากที่ผู้เล่นเลือก:

Image description

หากผู้ใช้ป้อนค่าที่ไม่ถูกต้อง ให้ทำซ้ำขั้นตอนเพื่อรับตัวเลือกของผู้เล่น ข้อกำหนดที่แท้จริงเพียงอย่างเดียวสำหรับการเลือกผู้เล่นคือต้องมีค่าระหว่าง 0 ถึง 2 หากอินพุตของผู้เล่นอยู่นอกช่วงนี้ ข้อยกเว้น ValueError จะเพิ่มขึ้น เพื่อหลีกเลี่ยงการแสดงข้อความแสดงข้อผิดพลาดเริ่มต้นแก่ผู้เล่นสามารถจัดการข้อยกเว้นได้

ตอนนี้ได้กำหนดฟังก์ชันบางอย่างที่สะท้อนถึงขั้นตอนในแผนผังลำดับงานแล้ว ตรรกะของเกมเป็นระเบียบและกะทัดรัดมากขึ้น นี่คือสิ่งที่ต้องวนซ้ำในขณะที่:

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
Enter fullscreen mode Exit fullscreen mode

สังเกตว่าหากผู้เล่นไม่สามารถเลือกช่วงที่ถูกต้องได้ จะใช้การดำเนินการต่อแทนการแบ่ง สิ่งนี้ทำให้รหัสดำเนินการต่อไปยังการวนซ้ำถัดไปแทนที่จะแยกออกจากกัน

สรุปได้ว่า
การสร้างเกม เป่ายิ้งฉุบ โดยใช้การรับอินพุตจากผู้เล่น เขียนโค้ดเพื่อให้คอมพิวเตอร์สุ่มค่าในเกมเพื่อเเทนผู้เล่นอีกคน ในการกำหนดผู้ชนะจะใช้เงื่อนไข if … elif … else มาตัดสินผู้ชนะในเกม ส่วนในการสร้างเงื่อนไขนั้นมีหากหลายรูปเเบบ เช่น การเล่นเกมเเบบตาเดียว , การเล่นซ้ำๆ จนกว่าผู้เล่นจะออกจากเกม ในส่วนของการรับค่านั้น หากผู้ใช้กรอกอักษรพิมพ์เล็กหรือพิมพ์ใหญ่ จะเเก้ปัญหาโดยการรับค่าเเบบ enum.IntEnum โดยการเปลี่ยนจากการรับค่าเป็นสตริงเป็นการเเทนตัวเเปรโดยใช้ตัวเลขเเทน

Reference : (https://realpython.com/python-rock-paper-scissors/

Top comments (0)