Blackjack-Skript in Python

Oct 23 2020

Vor kurzem hatte ich einen Python-Test und bin leider gescheitert. Ich werde meinen Test wiederholen und der Lehrer gab mir den Tipp, effizienter und sauberer zu arbeiten. Um dies zu üben, habe ich vor ungefähr 2 Wochen ein Blackjack-Spiel mit Python gemacht und es ihm geschickt, um es zu überprüfen. Er hat noch geantwortet und mein Test ist nächste Woche. Kann jemand einen Blick darauf werfen und vielleicht auf Dinge hinweisen, die verbessert werden müssen? Bitte, ich möchte diesen Test wirklich bestehen.

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)        

Kommentare sind willkommen, aber bitte denken Sie daran, dass dies meine erste Programmiersprache ist und ich noch viel zu lernen habe. Vielen Dank!

Antworten

5 AryanParekh Oct 25 2020 at 03:39

Es tut mir leid, aber mein Wissen in Kartenspielen ist verrostet. Bitte korrigieren Sie mich, wenn etwas nicht stimmt!

Fangen Sie immer ungültige Eingaben ab

Angenommen, der Benutzer gibt etwas ein, das er über diese Codezeile erhält

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

Wählen Sie den zu wettenden Betrag:

Nun, was passiert , wenn der Benutzer versehentlich eingegeben E . In diesem Fall schlägt Ihr Programm fehl, da es eine Eingabe in Form einer Ganzzahl erwartet. Aus diesem Grund sollten Sie ungültige Eingaben immer mit Try and Except in Python abfangen

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

Auf diese Weise, wenn der Benutzer eingegeben hat

Wählen Sie den Betrag aus, der sein soll: Ich mag Python

Es würde dem Benutzer geben

Ungültige Eingabe! Bitte gebe eine Nummer ein

Beenden Sie nicht nach ungültiger / schlechter Eingabe

Wenn der Benutzer in Ihrem Programm eine Wette eingibt, die höher ist als das Geld, das er hat, stoppt das Programm einfach. Es wird nicht wieder abgespielt, warum sollte das passieren?

Sie sollten den Benutzer auffordern, erneut eine gültige Eingabe einzugeben, damit ein Fehler von ihm nicht zur sofortigen Beendigung des Programms führt

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

Das Beste, was Sie jetzt tun können, ist, dies in eine separate Funktion zu verschieben, die aufgerufen wird take_input(), damit Ihre blackjack()Funktion sauber bleibt und die Eingabe jetzt einfach ist

bet = take_input()

Ja, Sie haben noch ein paar Codezeilen geschrieben. Aber jetzt wissen Sie, dass Ihr Programm das Richtige tut, wenn Ausnahmen auftreten.

Code vereinfachen - 1

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

Ist das gleiche wie

first_name = "Jack of " + first_name

Sie müssen nicht konvertieren, strda dies first_namebereits eine Zeichenfolge ist.

Gleiches gilt für die folgenden Zeilen, die ich aus Ihrem Code extrahiert habe.

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

Vermeiden Sie magische Zahlen

Nehmen Sie dieses Beispiel

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... sind bekannt als magische Zahlen . Ich musste nachdenken, um zu verstehen, was sie hier taten, bis ich endlich verstand, dass es sich um Karten handelte.

Der gute Weg, um damit umzugehen, ist die Verwendung von Pythons Enums .

from enum import Enum

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

Korrigieren Sie die Werte, wenn sie falsch sind.

Jetzt sieht Ihr if-else-Thread für den Leser so viel klarer aus

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

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

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

Ein weiterer Pluspunkt ist, was ist, wenn Sie den Wert des Königs von xauf ändern möchten y. Würden Sie zu Hunderten von Orten gehen, um herauszufinden, wo Sie im Zusammenhang mit dem König eine numerische Konstante verwendet haben könnten?

Hier können Sie einfach einstellen king.value, was Sie wollen.

import sleep as s

s(0.5)Das hatte mich am Anfang auch verwirrt, ich musste herausfinden was sbedeutete. sist überhaupt nicht sinnvoll, es verwirrt nur jeden, der Ihren Code liest. Dies sleepimpliziert jedoch eindeutig, dass Sie ... schlafen möchten! Verwenden Sie immer aussagekräftige Namen

Arbeit in Funktionen aufteilen

Derzeit ist Ihre blackjack()Funktion mit vielen Aufgaben überfüllt, die in ihre eigenen Funktionen verschoben werden sollten. So wie wir die Eingabeprozedur in eine separate take_input()Funktion verschoben haben , können Sie viele sinnvolle Funktionen erstellen, mit denen Sie draw_new_card()eine neue Karte aus dem Stapel zurückgeben können.

Ist Ihr Code trocken oder nass?

Entschuldigen Sie meine Kenntnisse über Kartenspiele

Sie haben die Prozedur

  1. ziehe eine Karte
  2. Überprüfen Sie, ob die Karte >=11 Punkte hat
  3. Drucken Sie den Punkt und den Namen

Warum dann dasselbe noch einmal für die zweite Karte wiederholen? Sie haben dasselbe zweimal geschrieben. Einmal für die erste Karte und dann für die zweite. du hast dich wiederholt Der beste Weg ist, Wiederholungen in eine Funktion einzubeziehen. Alles was Sie tun müssen, ist

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)

......

Sie können sehen, dass die Verwendung von Funktionen sehr geholfen hat.

4 Anonymous Oct 25 2020 at 05:43

Regeln der Namensgebung

Nur um den Punkt von @Aryan Parekh zu bekräftigen: Verwenden Sie keine bedeutungslosen Abkürzungen, z.

import random as rd
from time import sleep as s

Es gibt keinen Vorteil, Sie haben das Lesen und Verstehen des Codes erschwert. Also: verwenden random.choice(cards)statt : rd.choice(cards). random.choice ist selbsterklärend.

Guter Code sollte intuitiv sein, das beginnt mit den richtigen Namenskonventionen. Selbst wenn Sie faul sind, sollten Sie längere und aussagekräftigere Namen verwenden. Ihre IDE sollte ohnehin automatisch vervollständigt werden.

Sie haben Variablen wie a, cd2, x, y, die mich an Spaghetti Basic aus den 80ern erinnern. Ich mag Kartenspiele total, deshalb kann ich nicht viel zum Algo sagen, aber ich kann den Code kommentieren.

Zum Glück haben Sie einige Kommentare abgegeben.

Konsistenz

Sie verwenden die Auswahlfunktion einige Male, jedoch mit sehr unterschiedlichen Variablennamen:

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

und später:

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

Ich denke, hier ist mehr Konsistenz gefragt. Wenn Sie einige Anweisungen wiederverwenden, können Sie dieselben Variablennamen auch an anderer Stelle verwenden oder sich zumindest an einige sinnvolle Namensmuster halten. Zeichnen ist ein Name, der Sinn macht. Aber add_number sieht wirklich wie ein Funktionsname aus, also würde ich es card_number oder so ähnlich nennen (obwohl Sie diese Variable effektiv zum Inkrementieren eines anderen Werts verwenden).

Wiederholung

Es ist Wiederholung im Code zB:

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

Zunächst einmal sind einige Aussagen überflüssig:

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

Da Sie drei Listen verketten, ist das resultierende Objekt auch ein Listenobjekt. Ist cards = cards1 + cards2 + cards3also ausreichend und ergibt das gleiche Ergebnis.

Karten 1/2/3 sind genau gleich, also wiederholen Sie genau das gleiche dreimal hintereinander. Dies ist offensichtlich falsch und kann vereinfacht werden. Sie könnten einfach schreiben:

cards2 = cards1
cards3 = cards1

Auch wenn das nicht elegant ist, vermeiden Sie zumindest Wiederholungen und Ihre Reichweite wird nur einmal deklariert.

Ein besserer Weg:

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

Sie haben Ihre Sequenz also dreimal wiederholt und eine neue Liste erstellt. Da Sie itertools verwenden, können Sie auch itertools.repeat verwenden, wodurch Sie einen Generator erhalten, während * nSie eine Liste erhalten, die hier in Ordnung ist.

Verkettung

    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 ist eine Zeichenfolge, sodass Sie alle diese Elemente sicher verketten können. Oder noch besser, verwenden Sie einen F-String (Python> = 3.6):

full_name = f"Jack of {full_name}"