สคริปต์แบล็คแจ็คใน Python

Oct 23 2020

เมื่อเร็ว ๆ นี้ฉันมีการทดสอบ 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)        

ยินดีต้อนรับความคิดเห็นใด ๆ แต่โปรดทราบว่านี่เป็นภาษาโปรแกรมแรกของฉันและฉันยังมีอะไรให้เรียนรู้อีกมาก ขอบคุณ!

คำตอบ

5 AryanParekh Oct 25 2020 at 03:39

ฉันขอโทษ แต่ความรู้ในเกมไพ่ของฉันเป็นสนิม โปรดแก้ไขฉันหากมีบางอย่างผิดปกติ!

ตรวจจับข้อมูลที่ไม่ถูกต้องเสมอ

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

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

s(0.5)สิ่งนี้ทำให้ฉันสับสนในตอนแรกฉันต้องหาsความหมาย sไม่มีความหมายเลยเพียง แต่ทำให้ทุกคนสับสนที่อ่านรหัสของคุณ อย่างไรก็ตามsleepบอกเป็นนัยอย่างชัดเจนว่าคุณต้องการ ... นอน! ใช้ชื่อที่มีความหมายเสมอ

แยกงานออกเป็นฟังก์ชั่น

ขณะนี้blackjack()ฟังก์ชันของคุณรกไปด้วยงานจำนวนมากที่ควรย้ายไปยังฟังก์ชันของตนเอง เช่นเดียวกับที่เราย้ายขั้นตอนการป้อนข้อมูลไปยังtake_input()ฟังก์ชันแยกต่างหากคุณสามารถสร้างฟังก์ชันที่มีความหมายได้มากมายเช่นdraw_new_card()นี้สามารถส่งคืนการ์ดใหม่จากเด็คได้

รหัสของคุณแห้งหรือเปียก

ขอโทษที่ฉันรู้เรื่องเกมไพ่

คุณมีขั้นตอน

  1. จั่วการ์ด
  2. ตรวจสอบว่าการ์ดมี>=11 คะแนนหรือไม่
  3. พิมพ์จุดและชื่อ

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

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)

......

จะเห็นได้ว่าการใช้ฟังก์ชั่นช่วยได้มาก

4 Anonymous Oct 25 2020 at 05:43

หลักการตั้งชื่อ

เพียงเพื่อเสริมสร้างจุดที่ทำโดย @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}"