Skrip Blackjack dengan Python

Oct 23 2020

Baru-baru ini saya melakukan tes python dan, sayangnya, saya gagal. Saya akan mengulangi tes saya dan guru memberi saya tip untuk bekerja lebih efisien dan bersih. Untuk latihan ini saya membuat game blackjack sekitar 2 minggu yang lalu dengan python dan mengirimkannya untuk diperiksa. dia belum menjawab dan ujian saya minggu depan. Adakah yang bisa melihat dan mungkin menunjukkan hal-hal yang perlu perbaikan? tolong, saya sangat ingin lulus tes ini.

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)        

Setiap komentar dipersilakan tetapi harap diingat bahwa ini adalah bahasa pemrograman pertama saya dan saya masih harus banyak belajar. Terima kasih!

Jawaban

5 AryanParekh Oct 25 2020 at 03:39

Maaf, tapi pengetahuan saya tentang permainan kartu sudah berkarat. Harap perbaiki saya jika ada yang salah!

Selalu tangkap masukan yang tidak valid

Asumsikan bahwa pengguna akan memasukkan sesuatu, yang diminta dari baris kode ini

print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))

pilih jumlah untuk bertaruh:

Sekarang, bagaimana jika pengguna tidak sengaja masuk E . Dalam hal ini, program Anda akan gagal karena mengharapkan input dalam bentuk integer. Inilah sebabnya mengapa Anda harus selalu menangkap masukan yang tidak valid menggunakan Coba dan Kecuali dengan Python

try: 
    bet = int(input("select amount to be: ")) 
except Exception: 
    print("Invalid input! Please enter a number\n")

Dengan cara ini, jika pengguna masuk

pilih jumlah menjadi: Saya suka python

Ini akan memberi pengguna

Masukan tidak valid! Harap masukkan nomor

Jangan keluar setelah masukan tidak valid / buruk

Dalam program Anda, jika pengguna memasukkan taruhan yang melebihi uang yang dimilikinya, program akan berhenti begitu saja. Itu tidak akan diputar lagi, mengapa ini harus terjadi?

Anda harus meminta pengguna untuk memasukkan input yang valid lagi, sehingga kesalahan apa pun yang dia lakukan tidak akan mengakibatkan penghentian langsung program

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

Hal terbaik yang harus dilakukan sekarang adalah memindahkan ini ke fungsi terpisah yang disebut take_input(), sehingga blackjack()fungsi Anda dapat tetap bersih, dan sekarang mengambil masukan menjadi mudah.

bet = take_input()

Ya, Anda telah menulis beberapa baris kode lagi. Tetapi sekarang Anda tahu bahwa program Anda akan melakukan hal yang benar ketika Pengecualian terjadi.

Sederhanakan kode - 1

first_name = str('Jack'+' of '+first_name)

Sama dengan

first_name = "Jack of " + first_name

Anda tidak perlu mengonversi menjadi strkarena first_namesudah menjadi string.

Hal yang sama berlaku untuk baris berikut yang telah saya ekstrak dari kode Anda.

first_name = str('Queen'+' of '+first_name)
first_name = str('King'+' of '+first_name)
first_name = str('Ace'+' of '+first_name)

Hindari Nomor Ajaib

Ambil contoh ini

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... yang dikenal sebagai angka ajaib . Saya harus berpikir sejenak untuk memahami apa yang mereka lakukan di sini sampai akhirnya saya mengerti bahwa itu adalah kartu.

Cara yang baik untuk mengatasinya adalah dengan menggunakan enum Python .

from enum import Enum

class Card(Enum):
    jack = 11
    queen = 12
    king = 13
    ....

Perbaiki nilainya jika salah.

Sekarang utas if-else Anda terlihat jauh lebih jelas bagi pembaca

if first_point == Card.jack.value:
    ...

elif first_point == Card.queen.value:
    ...

elif first_point = Card.king.value:
   ....

Poin plus lainnya adalah bagaimana jika Anda ingin mengubah nilai raja dari xmenjadi y. Apakah Anda akan pergi ke ratusan tempat untuk menemukan di mana Anda mungkin telah menggunakan konstanta numerik dalam konteks raja?

di sini Anda dapat mengatur king.valueapa pun yang Anda inginkan.

import sleep as s

s(0.5)Hal ini juga sempat membuat saya bingung pada awalnya, saya harus mencari tahu apa smaksudnya. stidak berarti sama sekali, itu hanya membingungkan siapa pun yang membaca kode Anda. Namun, sleepjelas menyiratkan bahwa Anda ingin ... Tidur! Selalu gunakan nama yang bermakna

Pisahkan pekerjaan menjadi beberapa fungsi

Saat ini, blackjack()fungsi Anda penuh dengan banyak tugas yang harus dipindahkan ke fungsinya sendiri. Sama seperti kami memindahkan prosedur input ke take_input()fungsi terpisah , Anda dapat membuat banyak fungsi yang berarti seperti draw_new_card()itu dapat mengembalikan kartu baru dari tumpukan.

Apakah kode Anda KERING atau BASAH

Maafkan pengetahuan saya tentang permainan kartu

Anda memiliki prosedurnya

  1. menggambar sebuah kartu
  2. periksa apakah kartunya >=11 poin
  3. cetak poin dan nama

Lalu kenapa mengulang hal yang sama lagi untuk kartu kedua? Anda telah menulis hal yang sama dua kali. Sekali untuk kartu pertama, dan selanjutnya untuk kartu kedua. Anda telah mengulangi diri Anda sendiri. Cara terbaik adalah dengan memfaktorkan pengulangan menjadi suatu fungsi. Sehingga yang perlu Anda lakukan hanyalah

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)

......

Anda dapat melihat bahwa menggunakan fungsi telah banyak membantu.

4 Anonymous Oct 25 2020 at 05:43

Konvensi penamaan

Sekadar memperkuat poin yang dibuat oleh @Aryan Parekh: Jangan gunakan singkatan yang tidak berarti misalnya:

import random as rd
from time import sleep as s

Tidak ada manfaatnya, Anda telah membuat kode lebih sulit untuk dibaca dan dipahami. Jadi: menggunakan random.choice(cards)bukan: rd.choice(cards). random.choice sudah cukup jelas.

Kode yang baik harus intuitif, yang dimulai dengan konvensi penamaan yang tepat. Meskipun Anda malas, Anda harus menggunakan nama yang lebih panjang dan deskriptif, IDE Anda tetap harus dilengkapi otomatis.

Anda memiliki variabel seperti a, cd2, x, y yang mengingatkan saya pada spaghetti Basic dari tahun 80-an. Saya benar-benar payah di permainan kartu jadi saya tidak bisa berkomentar banyak tentang algo tapi saya bisa mengomentari kodenya.

Untungnya, Anda memberikan beberapa komentar.

Konsistensi

Anda menggunakan fungsi pilihan beberapa kali tetapi dengan nama variabel yang sangat berbeda:

a = rd.choice(cards)
x, y = a

dan nanti:

draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw

Saya pikir lebih banyak konsistensi dibutuhkan di sini. Jika Anda menggunakan kembali beberapa pernyataan Anda mungkin juga menggunakan nama variabel yang sama di tempat lain atau setidaknya tetap berpegang pada beberapa pola penamaan yang masuk akal. menggambar adalah nama yang masuk akal. Tetapi add_number benar-benar terlihat seperti nama fungsi, jadi saya akan menyebutnya card_number atau sesuatu seperti itu (meskipun Anda secara efektif menggunakan variabel itu untuk menambah nilai lain).

Pengulangan

Ada pengulangan dalam kode Anda misalnya:

#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']))

Pertama, beberapa pernyataan berlebihan:

#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)

Karena Anda menggabungkan tiga daftar, objek yang dihasilkan juga merupakan objek daftar. Jadi, cards = cards1 + cards2 + cards3cukup dan membuahkan hasil yang sama.

kartu1 / 2/3 persis sama, jadi Anda mengulangi hal yang persis sama sebanyak 3 kali berturut-turut. Ini jelas salah dan bisa disederhanakan. Anda cukup menulis:

cards2 = cards1
cards3 = cards1

Meskipun itu tidak elegan tetapi setidaknya Anda menghindari pengulangan dan jangkauan Anda dinyatakan hanya sekali.

Cara yang lebih baik:

cards = list(itertools.product(range(2, 15), ['spade', 'heart', 'diamond', 'club'])) *3

Jadi, Anda telah mengulangi urutan Anda tiga kali dan membuat daftar baru. Karena Anda menggunakan itertools, Anda juga bisa menggunakan itertools.repeat, yang memberi Anda generator, sedangkan * nmemberi Anda daftar, yang baik-baik saja di sini.

Rangkaian

    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 adalah string, jadi Anda bisa menggabungkan semua item ini dengan aman. Atau lebih baik lagi, gunakan F-string (Python> = 3.6):

full_name = f"Jack of {full_name}"