สคริปต์แบล็คแจ็คใน Python
เมื่อเร็ว ๆ นี้ฉันมีการทดสอบ python และน่าเสียดายที่ฉันล้มเหลว ฉันกำลังจะทำแบบทดสอบอีกครั้งและอาจารย์ก็ให้คำแนะนำในการทำงานให้มีประสิทธิภาพและสะอาดมากขึ้น เพื่อฝึกฝนสิ่งนี้ฉันทำเกมแบล็คแจ็คเมื่อประมาณ 2 สัปดาห์ที่แล้วด้วย python และส่งไปให้เขาตรวจสอบ เขายังตอบกลับและการทดสอบของฉันคือสัปดาห์หน้า ใครช่วยดูและอาจชี้ให้เห็นสิ่งที่ต้องปรับปรุง? ได้โปรดฉันอยากจะผ่านการทดสอบนี้จริงๆ
import itertools
import random as rd
from time import sleep as s
#making 3 decks with playing cards and assign them 2 to 14
cards1 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards2 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards3 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)
#shuffle deck
rd.shuffle(cards)
def blackjack(cards):
money = 10
while True:
print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))
if money < bet:
print('you dont have that much money....')
else:
playing = True
#draw first card and remove it from the deck
fcard = rd.choice(cards)
cards.remove(fcard)
first_point, first_name = fcard
#check if first card is 11 points or more (to change back to 10 points unless it's ace)
if first_point == 11:
first_point = 10
first_name = str('Jack'+' of '+first_name)
elif first_point == 12:
first_point = 10
first_name = str('Queen'+' of '+first_name)
elif first_point == 13:
first_point = 10
first_name = str('King'+' of '+first_name)
elif first_point == 14:
first_point = 11
first_name = str('Ace'+' of '+first_name)
#show the first drawn card
print(first_point, first_name)
s(0.7)
#draw second card and remove it from the deck
scard = rd.choice(cards)
cards.remove(scard)
second_point, second_name = scard
#checking second card for the same
if second_point == 11:
second_point = 10
second_name = str('Jack'+' of '+second_name)
elif second_point == 12:
second_point = 10
second_name = str('Queen'+' of '+second_name)
elif second_point == 13:
second_point = 10
second_name = str('King'+' of '+second_name)
elif second_point == 14:
second_point = 11
second_name = str('Ace'+' of '+second_name)
#show second card
print(second_point, second_name)
s(0.7)
points = first_point + second_point
#check if first 2 cards make a blackjack
if points == 21:
print('Blackjack!')
bet *= 2
print('you won', bet, 'money')
money += bet
playing = False
print(points, 'points out of 21')
if money == 0:
print('you are broke!')
exit()
#after the first 2 cards i need to determine if the player wants more cards
while playing:
card = input('press enter to draw a card or type x to stop')
if card != 'x':
a = rd.choice(cards)
x, y = a
#going through the same checking system as the first 2 cards
if x == 11:
y = str('Jack'+' of '+second_name)
x = 10
elif x == 12:
y = str('Queen'+' of '+second_name)
x = 10
elif x == 13:
y = str('King'+' of '+second_name)
x = 10
elif x == 14:
y = str('Ace'+' of '+second_name)
x = 11
print(x, y)
s(0.7)
cards.remove(a)
points += x
if points > 21:
print('BUST')
points = 0
playing = False
#if the player has x as input the player stops drawing
elif card == 'x':
playing = False
print(points, 'points')
#let the dealer do the same card drawing
result = dealer_draw(cards)
print('you scored: ', points, '\n', 'the bank scored: ', result)
s(0.7)
#compare obtained points with the dealer's points
if points > result:
print('you win!')
money += bet
elif points == result:
print('draw')
elif points < result:
print('you lose')
money -= bet
elif points == 0 and result == 0:
print('you lose')
money -= bet
def dealer_draw(cards):
#2 empty prints to maintain clear overview
print()
print()
a = 0
#first 2 cards (same as for the player until.....)
cd1 = rd.choice(cards)
cards.remove(cd1)
points_first, name_first = cd1
if points_first == 11:
name_first = str('Jack'+' of '+name_first)
points_first = 10
elif points_first == 12:
name_first = str('Queen'+' of '+name_first)
points_first = 10
elif points_first == 13:
name_first = str('King'+' of '+name_first)
points_first = 10
elif points_first == 14:
name_first = str('Jack'+' of '+name_first)
points_first = 11
print(points_first, name_first)
s(0.7)
cd2 = rd.choice(cards)
cards.remove(cd2)
points_second, name_second = cd2
if points_second == 11:
name_second = str('Jack'+' of '+name_second)
points_second = 10
elif points_second == 12:
name_second = str('Queen'+' of '+name_second)
points_second = 10
elif points_second == 13:
name_second = str('King'+' of '+name_second)
points_second = 10
elif points_second == 14:
name_second = str('Ace'+' of '+name_second)
points_second = 11
print(points_second, name_second)
s(0.7)
#..... here (scroll up)
full_points = points_first + points_second
a += full_points
#have the minimal bank draw set at 16
while a < 16:
print("bank's total = ", a)
s(0.7)
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
if add_number == 11:
full_name = str('Jack'+' of '+full_name)
add_number = 10
elif add_number == 12:
full_name = str('Queen'+' of '+full_name)
add_number = 10
elif add_number == 13:
full_name = str('King'+' of '+full_name)
add_number = 10
elif add_number == 14:
full_name = str('Ace'+' of '+full_name)
add_number = 11
print(add_number, full_name)
s(0.7)
a += add_number
print("bank's total = ", a)
s(0.7)
#check if bank scored more than 21 and if so, return 0
if a > 21:
return 0
else:
return a
blackjack(cards)
ยินดีต้อนรับความคิดเห็นใด ๆ แต่โปรดทราบว่านี่เป็นภาษาโปรแกรมแรกของฉันและฉันยังมีอะไรให้เรียนรู้อีกมาก ขอบคุณ!
คำตอบ
ฉันขอโทษ แต่ความรู้ในเกมไพ่ของฉันเป็นสนิม โปรดแก้ไขฉันหากมีบางอย่างผิดปกติ!
ตรวจจับข้อมูลที่ไม่ถูกต้องเสมอ
สมมติว่าผู้ใช้กำลังจะป้อนบางสิ่งซึ่งจะถูกแจ้งให้เขาทราบจากบรรทัดของรหัสนี้
print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))
เลือกจำนวนเงินที่จะเดิมพัน:
ตอนนี้สิ่งที่หากผู้ใช้ป้อนตั้งใจE ในกรณีนี้โปรแกรมของคุณจะล้มเหลวเนื่องจากคาดว่าอินพุตจะอยู่ในรูปของจำนวนเต็ม นี่คือเหตุผลที่คุณควรตรวจจับอินพุตที่ไม่ถูกต้องโดยใช้ลองและยกเว้นใน Python
try:
bet = int(input("select amount to be: "))
except Exception:
print("Invalid input! Please enter a number\n")
วิธีนี้หากผู้ใช้ป้อน
เลือกจำนวนที่จะเป็น: ฉันชอบ python
ก็จะให้ผู้ใช้
ใส่ไม่ถูกต้อง! โปรดป้อนหมายเลข
อย่าออกหลังจากป้อนข้อมูลไม่ถูกต้อง / ไม่ถูกต้อง
ในโปรแกรมของคุณหากผู้ใช้เข้าสู่การเดิมพันที่มากกว่าเงินที่เขามีโปรแกรมจะหยุดลง มันจะไม่เล่นอีกทำไมสิ่งนี้ถึงเกิดขึ้น?
คุณควรขอให้ผู้ใช้ป้อนข้อมูลที่ถูกต้องอีกครั้งเพื่อไม่ให้เกิดความผิดพลาดใด ๆ ในการยุติโปรแกรมทันที
while True:
try:
bet = int(input("select amount to be: "))
except Exception:
print("Invalid input! Please enter a number\n")
continue
if bet > money:
print("Bet placed higher than balance!")
continue
break
สิ่งที่ดีที่สุดที่ต้องทำตอนนี้คือย้ายสิ่งนี้ไปยังฟังก์ชันแยกต่างหากที่เรียกว่าฟังก์ชันtake_input()ของคุณblackjack()จะยังคงสะอาดอยู่และตอนนี้การป้อนข้อมูลทำได้ง่าย
bet = take_input()
ใช่คุณได้เขียนโค้ดเพิ่มอีกสองสามบรรทัด แต่ตอนนี้คุณรู้แล้วว่าโปรแกรมของคุณจะทำสิ่งที่ถูกต้องเมื่อมีข้อยกเว้นเกิดขึ้น
ลดความซับซ้อนของรหัส - 1
first_name = str('Jack'+' of '+first_name)
ก็เหมือนกับ
first_name = "Jack of " + first_name
คุณไม่จำเป็นต้องแปลงstrเป็นfirst_nameสตริง
เช่นเดียวกับบรรทัดต่อไปนี้ที่ฉันได้ดึงข้อมูลจากโค้ดของคุณ
first_name = str('Queen'+' of '+first_name)
first_name = str('King'+' of '+first_name)
first_name = str('Ace'+' of '+first_name)
หลีกเลี่ยงMagic Numbers
ใช้ตัวอย่างนี้
if first_point == 11:
first_point = 10
first_name = str('Jack'+' of '+first_name)
elif first_point == 12:
first_point = 10
first_name = str('Queen'+' of '+first_name)
elif first_point == 13:
first_point = 10
first_name = str('King'+' of '+first_name)
elif first_point == 14:
first_point = 11
first_name = str('Ace'+' of '+first_name)
10, 11, 12... เป็นที่รู้จักกันเป็นหมายเลขมายากล ฉันต้องคิดในขณะที่จะเข้าใจว่าพวกเขามาทำอะไรที่นี่จนในที่สุดฉันก็เข้าใจว่าพวกเขาเป็นไพ่
วิธีที่ดีที่จะรับมือกับเรื่องนี้คือการใช้ ธenums
from enum import Enum
class Card(Enum):
jack = 11
queen = 12
king = 13
....
แก้ไขค่าหากผิด
ตอนนี้เธรด if-else ของคุณดูชัดเจนยิ่งขึ้นสำหรับผู้อ่าน
if first_point == Card.jack.value:
...
elif first_point == Card.queen.value:
...
elif first_point = Card.king.value:
....
อีกจุดบวกคือสิ่งที่ถ้าคุณต้องการที่จะเปลี่ยนค่าของกษัตริย์จากการx yคุณจะไปที่สถานที่หลายร้อยแห่งเพื่อหาที่ที่คุณอาจใช้ค่าคงที่ตัวเลขในบริบทของราชาหรือไม่?
ที่นี่คุณสามารถตั้งค่าking.valueอะไรก็ได้ที่คุณต้องการ
import sleep as s
import sleep as ss(0.5)สิ่งนี้ทำให้ฉันสับสนในตอนแรกฉันต้องหาsความหมาย sไม่มีความหมายเลยเพียง แต่ทำให้ทุกคนสับสนที่อ่านรหัสของคุณ อย่างไรก็ตามsleepบอกเป็นนัยอย่างชัดเจนว่าคุณต้องการ ... นอน! ใช้ชื่อที่มีความหมายเสมอ
แยกงานออกเป็นฟังก์ชั่น
ขณะนี้blackjack()ฟังก์ชันของคุณรกไปด้วยงานจำนวนมากที่ควรย้ายไปยังฟังก์ชันของตนเอง เช่นเดียวกับที่เราย้ายขั้นตอนการป้อนข้อมูลไปยังtake_input()ฟังก์ชันแยกต่างหากคุณสามารถสร้างฟังก์ชันที่มีความหมายได้มากมายเช่นdraw_new_card()นี้สามารถส่งคืนการ์ดใหม่จากเด็คได้
รหัสของคุณแห้งหรือเปียก
ขอโทษที่ฉันรู้เรื่องเกมไพ่
คุณมีขั้นตอน
- จั่วการ์ด
- ตรวจสอบว่าการ์ดมี
>=11 คะแนนหรือไม่ - พิมพ์จุดและชื่อ
แล้วทำไมต้องทำซ้ำอีกครั้งสำหรับไพ่ใบที่สอง? คุณเขียนสิ่งเดียวกันสองครั้ง หนึ่งครั้งสำหรับไพ่ใบแรกและถัดไปสำหรับไพ่ใบที่สอง คุณทำซ้ำตัวเอง วิธีที่ดีที่สุดคือแยกตัวประกอบการทำซ้ำออกเป็นฟังก์ชัน ดังนั้นสิ่งที่คุณต้องทำก็คือ
def new_card():
card = draw_new_card()
point, name = card
process_card(point, name)
return point, name
# in the blackjack function #
first_point, first_name = new_card()
print(first_point, first_name)
sleep(0.5)
second_point, second_name = new_card()
print(second_point, second_name)
......
จะเห็นได้ว่าการใช้ฟังก์ชั่นช่วยได้มาก
หลักการตั้งชื่อ
เพียงเพื่อเสริมสร้างจุดที่ทำโดย @Aryan Parekh: อย่าใช้คำย่อที่ไม่มีความหมายเช่น:
import random as rd
from time import sleep as s
ไม่มีประโยชน์คุณได้ทำให้โค้ดอ่านและเข้าใจยากขึ้น ดังนั้น: ใช้random.choice(cards)แทน: rd.choice(cards). random.choice เป็นตัวอธิบาย
รหัสที่ดีควรใช้งานง่ายซึ่งเริ่มต้นด้วยหลักการตั้งชื่อที่เหมาะสม แม้ว่าคุณจะขี้เกียจ แต่ก็ควรใช้ชื่อที่ยาวและสื่อความหมายมากกว่านี้ แต่ IDE ของคุณก็ควรมีการเติมข้อความอัตโนมัติอยู่ดี
คุณมีตัวแปรเช่น a, cd2, x, y ที่ทำให้ฉันนึกถึงสปาเก็ตตี้เบสิกจากยุค 80 ฉันดูดเกมไพ่โดยสิ้นเชิงดังนั้นฉันจึงไม่สามารถแสดงความคิดเห็นเกี่ยวกับอัลโกได้มากนัก แต่ฉันสามารถแสดงความคิดเห็นเกี่ยวกับรหัสได้
โชคดีที่คุณแสดงความคิดเห็น
ความสม่ำเสมอ
คุณใช้ฟังก์ชันตัวเลือกสองสามครั้ง แต่มีชื่อตัวแปรที่แตกต่างกันมาก:
a = rd.choice(cards)
x, y = a
และหลังจากนั้น:
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
ฉันคิดว่าที่นี่มีความสม่ำเสมอมากกว่า หากคุณนำคำสั่งบางส่วนมาใช้ซ้ำคุณอาจใช้ชื่อตัวแปรเดียวกันที่อื่นด้วยหรืออย่างน้อยก็ยึดติดกับรูปแบบการตั้งชื่อที่เหมาะสม วาดเป็นชื่อที่สมเหตุสมผล แต่ add_number ดูเหมือนชื่อฟังก์ชันจริงๆดังนั้นฉันจะเรียกมันว่า card_number หรืออะไรทำนองนั้น (แม้ว่าคุณจะใช้ตัวแปรนั้นอย่างมีประสิทธิภาพเพื่อเพิ่มค่าอื่น)
การทำซ้ำ
มีการทำซ้ำในรหัสของคุณเช่น:
#making 3 decks with playing cards and assign them 2 to 14
cards1 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards2 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
cards3 = list(itertools.product(range(2, 15),['spade', 'heart', 'diamond', 'club']))
ก่อนอื่นข้อความบางส่วนซ้ำซ้อน:
#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)
เนื่องจากคุณกำลังเชื่อมสามรายการวัตถุผลลัพธ์จึงเป็นวัตถุรายการด้วย จึงcards = cards1 + cards2 + cards3เพียงพอและให้ผลลัพธ์เดียวกัน
ไพ่ 1/2/3 เหมือนกันทุกประการดังนั้นคุณกำลังทำสิ่งเดียวกันซ้ำ 3 ครั้งติดต่อกัน เห็นได้ชัดว่าผิดและสามารถทำให้ง่ายขึ้นได้ คุณสามารถเขียน:
cards2 = cards1
cards3 = cards1
แม้ว่าสิ่งนั้นจะไม่สวยหรู แต่อย่างน้อยคุณก็หลีกเลี่ยงการทำซ้ำและมีการประกาศช่วงของคุณเพียงครั้งเดียว
วิธีที่ดีกว่า:
cards = list(itertools.product(range(2, 15), ['spade', 'heart', 'diamond', 'club'])) *3
ดังนั้นคุณได้ทำลำดับของคุณซ้ำสามครั้งและสร้างรายการใหม่ เนื่องจากคุณใช้ itertools คุณสามารถใช้ itertools.repeat ซึ่งให้เครื่องกำเนิดไฟฟ้า* nแก่คุณได้ในขณะที่ให้รายการซึ่งเป็นประโยชน์ที่นี่
การเชื่อมต่อ
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
if add_number == 11:
full_name = str('Jack'+' of '+full_name)
add_number = 10
full_name เป็นสตริงดังนั้นคุณสามารถเชื่อมต่อรายการเหล่านี้ทั้งหมดได้อย่างปลอดภัย หรือดีกว่านั้นให้ใช้F-string (Python> = 3.6):
full_name = f"Jack of {full_name}"