เป่ายิ้งฉุบคืออะไร?
คุณอาจเคยเล่นเป่ายิ้งฉุบมาก่อน บางทีอาจจะใช้มันเพื่อตัดสินว่าใครจ่ายค่าอาหารหรือใครจะเป็นคนแรกของเกม
หากไม่คุ้นเคย เป่ายิ้งฉุบเป็นเกมมือสำหรับผู้เล่นสองคนขึ้นไป ผู้เล่นพูดว่า "เป่ายิ้งฉุบ"
- ค้อน >> กำมือ 2.กระดาษ >> เเบมือ 3.กรรไกร >> ชูสองนิ้
กฎมีดังนี้:
- กรรไกรทุบหิน
- กระดาษครอบหิน
- กรรไกรตัดกระดาษ
เมื่อทราบกฏเเล้ว จึงเริ่มคิดว่ากฎเหล่านี้จะแปลเป็น Python ได้อย่างไร
เล่นเกมเป่ายิ้งฉุบเกมเดียวใน Python
คุณสามารถสร้างเกมเป่ายิ้งฉุบได้โดยใช้คำอธิบายและกฎด้านบน ก่อนที่จะเริ่มเล่นเกม คุณจะต้องนำเข้าโมดูลที่คุณจะใช้เพื่อจำลองการเล่นของคอมพิวเตอร์:
import random
รับอินพุตของผู้ใช้
การรับข้อมูลจากผู้ใช้นั้นค่อนข้างตรงไปตรงมาใน Python เป้าหมายในที่นี้คือการถามผู้เล่นว่าต้องการเลือกอะไร(ค้อน กรรไกร กระดาษ) จากนั้นกำหนดตัวเลือกนั้นให้กับตัวแปร:
user_action = input("Enter a choice (rock, paper, scissors): ")
จากรูปที่เเสดงจะแจ้งให้ผู้เล่นป้อนการเลือกและบันทึกลงในตัวแปรเพื่อใช้ในภายหลัง เมื่อผู้เล่นเลือกเเล้ว ต่อไปคอมพิวเตอร์จะประมวลว่าควรเลือกอะไร (ค้อน กรรไกร กระดาษ)
ให้คอมพิวเตอร์เลือก
เกมเป่ายิ้งฉุบที่แข่งขันกันด้วยกลยุทธ์ แทนที่จะพยายามพัฒนาแบบจำลองสำหรับเกมนี้ เพื่อประหยัดเวลาได้ ด้วยการให้คอมพิวเตอร์เลือกการกระทำแบบสุ่ม การเลือกแบบสุ่มเป็นวิธีที่ดีในการใช้คอมพิวเตอร์เลือกค่าสุ่มเทียม
ใช้คำสั่ง Random.choice() เพื่อให้คอมพิวเตอร์สุ่ม:
possible_actions = ["rock", "paper", "scissors"]
computer_action = random.choice(possible_actions)
คำสั่งนี้ทำให้สามารถเลือกองค์ประกอบแบบสุ่มได้จากการที่ ผู้เล่นสามารถพิมพ์ตัวเลือกได้:
print(f"\nYou chose {user_action}, computer chose {computer_action}.\n")
ผลลัพธ์ :
การพิมพ์ตัวเลือกของผู้เล่นและคอมพิวเตอร์จะเป็นประโยชน์กับผู้ใช้ และยังช่วยให้สามารถแก้ไขจุดบกพร่องได้ในภายหลังในกรณีที่มีบางอย่างไม่ถูกต้องกับผลลัพธ์
การกำหนดผู้ชนะ
ตอนนี้ผู้เล่นทั้งสองได้เลือกแล้ว แค่ต้องการวิธีตัดสินว่าใครจะชนะ
โดยการใช้บล็อก 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.")
ผลลัพธ์ :
โดยการเปรียบเทียบการผูกก่อนเงื่อนไข โดยจะกำจัดกรณีเล็กๆ หากไม่ได้ทำจะต้องตรวจสอบการดำเนินการที่เป็นไปได้แต่ละรายการสำหรับ 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.")
เขียนโค้ดเพื่อรับอินพุตจากผู้เล่น เลือกแบบสุ่มสำหรับคอมพิวเตอร์ และตัดสินผู้ชนะ! แต่สามารถเล่นได้เพียงหนึ่งเกมก่อนที่โปรแกรมจะทำงานเสร็จ
เล่นหลายเกมติดต่อกัน
แม้ว่าเกมเป่ายิ้งฉุบเกมเดียวจะสนุก แต่จะดีกว่าไหมถ้าสามารถเล่นหลาย ๆ เกมติดต่อกันได้ การเล่นซ้ำเป็นวิธีที่ดีที่สุด โดยเฉพาะอย่างยิ่ง คุณสามารถใช้การวนซ้ำแบบ 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.")
Highlighted
play_again = input("Play again? (y/n): ")
if play_again.lower() != "y":
break
ผลลัพธ์
สังเกตโค้ดที่ไฮไลต์ด้านบน สิ่งสำคัญคือต้องตรวจสอบว่าผู้ใช้ต้องการเล่นอีกครั้งหรือไม่และหยุดเล่นหากไม่ต้องการ หากไม่มีการตรวจสอบ ผู้เล่นจะถูกบังคับให้เล่นจนกว่าจะยุติคอนโซลโดยใช้ Ctrl+C
การตรวจสอบการเล่นซ้ำเป็นการตรวจสอบสตริง "y" แต่การตรวจสอบสิ่งที่เฉพาะเจาะจงเเบบนี้อาจทำให้ผู้ใช้หยุดเล่นได้ยาก เเล้วถ้าหากผู้ใช้พิมพ์ "yes" หรือ "no" การเปรียบเทียบสตริงมักยุ่งยากเพราะไม่มีทางรู้ว่าผู้เล่นจะป้อนอะไร พวกเขาอาจใช้ตัวพิมพ์เล็กทั้งหมด ตัวพิมพ์ใหญ่ทั้งหมด หรือทั้งสองอย่างผสมกัน
นี่คือผลลัพธ์ของการเปรียบเทียบสตริงที่แตกต่างกัน:
>>> play_again = "yes"
>>> play_again == "n"
False
>>> play_again != "y"
True
เเต่นั่นไม่ใช่สิ่งที่ผู้เล่นต้องการ ผู้เล่นอาจจะไม่พอใจหากป้อน "yes" โดยคาดว่าจะเล่นอีกครั้งแต่ถูกเตะออกจากเกม
อธิบายการดำเนินการด้วย enum.IntEnum
เนื่องจากการเปรียบเทียบสตริงอาจทำให้เกิดปัญหาอย่างที่เห็นด้านบน จึงควรหลีกเลี่ยงหากทำได้ อย่างไรก็ตาม สิ่งแรกที่โปรแกรมของคุณถามคือให้ผู้ใช้ป้อนสตริง! จะเกิดอะไรขึ้นหากผู้ใช้ป้อน "Rock" หรือ "rOck" โดยไม่ได้ตั้งใจ การใช้อักษรตัวพิมพ์ใหญ่มีความสำคัญ ดังนั้นจึงไม่เท่ากัน:
>>> print("rock" == "Rock")
False
เนื่องจากการใช้อักษรตัวพิมพ์ใหญ่มีความสำคัญ "r" และ "R" จึงไม่เท่ากัน วิธีหนึ่งที่เป็นไปได้คือใช้ตัวเลขแทน การกำหนดตัวเลขให้แต่ละการกระทำสามารถช่วยคุณแก้ปัญหาได้:
ROCK_ACTION = 0
PAPER_ACTION = 1
SCISSORS_ACTION = 2
สิ่งนี้ทำให้คุณสามารถอ้างอิงการกระทำต่างๆ ตามหมายเลขที่กำหนด จำนวนเต็มจะไม่เจอปัญหาการเปรียบเทียบเช่นเดียวกับสตริง ดังนั้นวิธีนี้จึงใช้ได้ ตอนนี้สามารถให้ผู้เล่นป้อนตัวเลขและเปรียบเทียบกับค่าได้โดยตรง:
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
เนื่องจาก input() ส่งคืนสตริง ต้องแปลงค่าที่ส่งคืนเป็นจำนวนเต็มโดยใช้ int() จากนั้นสามารถเปรียบเทียบอินพุตกับแต่ละค่าด้านบน วิธีนี้ใช้ได้ดี แต่อาจต้องพึ่งการตั้งชื่อตัวแปรอย่างถูกต้องเพื่อติดตามตัวแปรทั้งหมด วิธีที่ดีกว่าคือการใช้ enum.IntEnum และกำหนดคลาสได้
การใช้ enum.IntEnum ช่วยให้สร้างแอตทริบิวต์และกำหนดค่าให้คล้ายกับที่แสดงด้านบน สิ่งนี้จะช่วยล้างโค้ดของคุณโดยจัดกลุ่มลงในเนมสเปซของตนเอง :
from enum import IntEnum
class Action(IntEnum):
Rock = 0
Paper = 1
Scissors = 2
การดำเนินการนี้จะสร้างการดำเนินการแบบกำหนดเองที่สามารถใช้เพื่ออ้างอิงการดำเนินการประเภทต่างๆ ที่สนับสนุนการทำงานโดยกำหนดแต่ละแอตทริบิวต์ภายในให้เป็นค่าที่คุณระบุ
การเปรียบเทียบยังคงตรงไปตรงมาเเละมีชื่อคลาสที่เป็นประโยชน์ที่เกี่ยวข้อง:
>>> Action.Rock == Action.Rock
True
เนื่องจากค่าสมาชิกเท่ากัน การเปรียบเทียบจึงเท่ากัน ชื่อคลาสยังทำให้ชัดเจนขึ้นว่าต้องการเปรียบเทียบสองการกระทำ
Note: To learn more about enum, check out the Build Enumerations of Constants With Python’s Enum.
สามารถสร้าง Action จาก int:
>>> Action.Rock == Action(0)
True
>>> Action(0)
<Action.Rock: 0>
การดำเนินการจะพิจารณาค่าที่ส่งผ่านและส่งคืนการดำเนินการที่เหมาะสม สิ่งนี้มีประโยชน์เพราะสามารถรับอินพุตของผู้เล่นเป็น int และสร้างการดำเนินการจากมันได้ ไม่ต้องกังวลกับการสะกดอีกต่อไป
แยกโค้ดออกเป็นฟังก์ชัน
ตอนนี้ได้สรุปโฟลว์ของโปรแกรมของคุณโดยใช้ผังงานแล้ว สามารถลองจัดระเบียบโค้ดของเพื่อให้คล้ายกับขั้นตอนที่คุณระบุมากขึ้น วิธีหนึ่งในการทำเช่นนี้คือการสร้างฟังก์ชันสำหรับแต่ละขั้นตอนในผังงาน ฟังก์ชันเป็นวิธีที่ยอดเยี่ยมในการแยกโค้ดขนาดใหญ่ออกเป็นส่วนย่อยๆ ที่สามารถจัดการได้มากขึ้น
คุณไม่จำเป็นต้องสร้างฟังก์ชันสำหรับการตรวจสอบเงื่อนไขเพื่อเล่นอีกครั้ง แต่คุณสามารถทำได้หากต้องการสามารถเริ่มต้นด้วยการนำเข้าแบบสุ่มหากยังไม่ได้ทำ และกำหนดคลาส Action :
import random
from enum import IntEnum
class Action(IntEnum):
Rock = 0
Paper = 1
Scissors = 2
ต่อไปนี้เป็นโค้ดสำหรับ 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
สังเกตว่าใช้อินพุตของผู้เล่นเป็น 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
การทดสอบนี้ จะเห็นวิธีที่โค้ดแจ้งผู้ใช้และส่งคืนการดำเนินการที่เกี่ยวข้องกับค่าอินพุตของผู้เล่น:
>>> get_user_selection()
Enter a choice (rock[0], paper[1], scissors[2]): 0
<Action.Rock: 0>
ตอนนี้ต้องการฟังก์ชันสำหรับรับคำสั่งของคอมพิวเตอร์ เช่นเดียวกับ 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
เนื่องจากค่า Action เริ่มนับจาก 0 และ len() เริ่มนับจาก 1 จึงเป็นสิ่งสำคัญที่ต้องทำ len(Action) - 1
เมื่อทดสอบสิ่งนี้ จะไม่มีการแจ้ง มันจะส่งคืนการกระทำที่เกี่ยวข้องกับตัวเลขสุ่ม:
>>> get_computer_selection()
<Action.Scissors: 2>
ต่อไป คุณต้องหาวิธีตัดสินผู้ชนะ ฟังก์ชันนี้จะรับอาร์กิวเมนต์สองรายการ ได้แก่ การกระทำของผู้ใช้และการกระทำของคอมพิวเตอร์ ไม่จำเป็นต้องส่งคืนสิ่งใดเนื่องจากจะแสดงผลไปยังคอนโซล:
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.")
สิ่งนี้ค่อนข้างคล้ายกับการเปรียบเทียบครั้งแรกที่ใช้ในการตัดสินผู้ชนะ ตอนนี้สามารถเปรียบเทียบประเภทการกระทำได้โดยตรงโดยไม่ต้องกังวลกับสตริง
ยังสามารถทดสอบได้โดยส่งตัวเลือกต่างๆ เพื่อตรวจสอบว่าจะพิมพ์ออกมาอย่างไร:
>>> determine_winner(Action.Rock, Action.Scissors)
Rock smashes scissors! You win!
เนื่องจากกำลังสร้างการดำเนินการจากตัวเลข จะเกิดอะไรขึ้นหากผู้ใช้ของคุณพยายามสร้างการดำเนินการจาก 3 โปรดจำไว้ว่าจำนวนสูงสุดที่คุณกำหนดไว้คือ 2:
>>> Action(3)
ValueError: 3 is not a valid Action
อ๊ะ! คุณไม่ต้องการให้เกิดขึ้น สามารถเพิ่มตรรกะที่ใดในผังงานเพื่อให้แน่ใจว่าผู้เล่นป้อนตัวเลือกที่ถูกต้อง
ควรรวมเช็คทันทีหลังจากที่ผู้เล่นเลือก:
หากผู้ใช้ป้อนค่าที่ไม่ถูกต้อง ให้ทำซ้ำขั้นตอนเพื่อรับตัวเลือกของผู้เล่น ข้อกำหนดที่แท้จริงเพียงอย่างเดียวสำหรับการเลือกผู้เล่นคือต้องมีค่าระหว่าง 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
สังเกตว่าหากผู้เล่นไม่สามารถเลือกช่วงที่ถูกต้องได้ จะใช้การดำเนินการต่อแทนการแบ่ง สิ่งนี้ทำให้รหัสดำเนินการต่อไปยังการวนซ้ำถัดไปแทนที่จะแยกออกจากกัน
สรุปได้ว่า
การสร้างเกม เป่ายิ้งฉุบ โดยใช้การรับอินพุตจากผู้เล่น เขียนโค้ดเพื่อให้คอมพิวเตอร์สุ่มค่าในเกมเพื่อเเทนผู้เล่นอีกคน ในการกำหนดผู้ชนะจะใช้เงื่อนไข if … elif … else มาตัดสินผู้ชนะในเกม ส่วนในการสร้างเงื่อนไขนั้นมีหากหลายรูปเเบบ เช่น การเล่นเกมเเบบตาเดียว , การเล่นซ้ำๆ จนกว่าผู้เล่นจะออกจากเกม ในส่วนของการรับค่านั้น หากผู้ใช้กรอกอักษรพิมพ์เล็กหรือพิมพ์ใหญ่ จะเเก้ปัญหาโดยการรับค่าเเบบ enum.IntEnum โดยการเปลี่ยนจากการรับค่าเป็นสตริงเป็นการเเทนตัวเเปรโดยใช้ตัวเลขเเทน
Reference : (https://realpython.com/python-rock-paper-scissors/
Top comments (0)