Script di blackjack in Python
Recentemente ho avuto un test di Python e, sfortunatamente, ho fallito. Ripeterò il test e l'insegnante mi ha dato il consiglio di lavorare in modo più efficiente e pulito. Per fare pratica, circa 2 settimane fa ho realizzato un gioco di blackjack con Python e gliel'ho mandato per controllare. ha ancora risposto e il mio test è la prossima settimana. Qualcuno può dare un'occhiata e magari sottolineare le cose che devono essere migliorate? per favore, voglio davvero superare questo test.
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)
Qualsiasi commento è ben accetto, ma tieni presente che questo è il mio primo linguaggio di programmazione e ho ancora molto da imparare. Grazie!
Risposte
Mi dispiace ma la mia conoscenza dei giochi di carte è arrugginita. Per favore correggimi se qualcosa non va!
Individua sempre input non validi
Supponiamo che l'utente stia per inserire qualcosa, che gli viene richiesto da questa riga di codice
print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))
seleziona l'importo da scommettere:
Ora, cosa succede se l'utente ha immesso accidentalmente E . In questo caso, il programma fallirà poiché si aspetta un input sotto forma di numero intero. Questo è il motivo per cui dovresti sempre rilevare input non validi utilizzando Try and Except in Python
try:
bet = int(input("select amount to be: "))
except Exception:
print("Invalid input! Please enter a number\n")
In questo modo, se l'utente è entrato
seleziona l'importo da essere: mi piace python
Darebbe all'utente
Inserimento non valido! Per favore inserisci un numero
Non uscire dopo un input non valido / errato
Nel tuo programma, se l'utente inserisce una scommessa che è più del denaro che ha, il programma si ferma. Non verrà riprodotto di nuovo, perché dovrebbe accadere?
Dovresti chiedere all'utente di inserire nuovamente un input valido, in modo che qualsiasi errore da parte sua non comporti l'immediata chiusura del programma
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
La cosa migliore da fare ora è spostarlo in una funzione separata chiamata take_input(), in modo che la tua blackjack()funzione possa rimanere pulita e ora prendere l'input è facile
bet = take_input()
Sì, hai scritto qualche altra riga di codice. Ma ora sai che il tuo programma farà la cosa giusta quando si verificano eccezioni.
Semplifica il codice - 1
first_name = str('Jack'+' of '+first_name)
Equivale a
first_name = "Jack of " + first_name
Non è necessario convertire in strcome first_nameè già una stringa.
Lo stesso vale per le seguenti righe che ho estratto dal tuo codice.
first_name = str('Queen'+' of '+first_name)
first_name = str('King'+' of '+first_name)
first_name = str('Ace'+' of '+first_name)
Evita i numeri magici
Prendi questo esempio
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... sono conosciuti come numeri magici . Ho dovuto riflettere per capire cosa stavano facendo qui fino a quando finalmente ho capito che erano carte.
Il modo migliore per affrontare questo problema è usare le enumerazioni di Python .
from enum import Enum
class Card(Enum):
jack = 11
queen = 12
king = 13
....
Correggere i valori se sono sbagliati.
Ora il tuo thread if-else sembra molto più chiaro al lettore
if first_point == Card.jack.value:
...
elif first_point == Card.queen.value:
...
elif first_point = Card.king.value:
....
Un altro vantaggio è che cosa succede se si desidera modificare il valore del re da xa y. Andresti in centinaia di posti per scoprire dove potresti aver usato una costante numerica nel contesto del re?
qui puoi semplicemente impostare king.valuequello che vuoi.
import sleep as s
import sleep as ss(0.5)Anche questo mi aveva confuso all'inizio, dovevo scoprire cosa ssignificava. snon ha alcun significato, confonde solo chiunque legga il tuo codice. Tuttavia, sleepimplica chiaramente che tu voglia ... Dormire! Usa sempre nomi significativi
Suddividi il lavoro in funzioni
Attualmente, la tua blackjack()funzione è ingombra di molte attività che dovrebbero essere spostate nelle loro funzioni. Proprio come abbiamo spostato la procedura di input in una take_input()funzione separata , puoi creare molte funzioni significative come quelle draw_new_card()che possono restituire una nuova carta dal mazzo.
Il tuo codice è DRY o WET
Scusa la mia conoscenza dei giochi di carte
Hai la procedura
- pesca una carta
- controlla se la carta è di
>=11 punti - stampare il punto e il nome
Allora perché ripetere di nuovo la stessa cosa per la seconda carta? Hai scritto la stessa cosa due volte. Una volta per la prima carta e la successiva per la seconda. ti sei ripetuto. Il modo migliore è scomporre la ripetizione in una funzione. Quindi tutto ciò che devi fare è
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)
......
Puoi vedere che l'uso delle funzioni ha aiutato molto.
Convenzioni di denominazione
Solo per rafforzare il punto sollevato da @Aryan Parekh: non usare abbreviazioni prive di significato, ad esempio:
import random as rd
from time import sleep as s
Non ci sono vantaggi, hai reso il codice più difficile da leggere e comprendere. Quindi: utilizzare random.choice(cards)al posto di: rd.choice(cards). random.choice si spiega da sé.
Un buon codice dovrebbe essere intuitivo, che inizia con le convenzioni di denominazione appropriate. Anche se sei pigro dovresti usare nomi più lunghi e descrittivi, il tuo IDE dovrebbe comunque avere il completamento automatico.
Hai variabili come a, cd2, x, y che mi ricordano gli spaghetti Basic degli anni '80. Faccio davvero schifo ai giochi di carte, quindi non posso commentare molto sull'algoritmo ma posso commentare il codice.
Per fortuna hai messo dei commenti.
Consistenza
Usi la funzione di scelta un paio di volte ma con nomi di variabili molto diversi:
a = rd.choice(cards)
x, y = a
e più tardi:
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
Penso che qui sia necessaria una maggiore coerenza . Se riutilizzi alcune affermazioni potresti anche usare gli stessi nomi di variabile altrove o almeno attenersi ad alcuni modelli di denominazione che hanno senso. disegnare è un nome che ha senso. Ma add_number sembra davvero il nome di una funzione, quindi lo chiamerei card_number o qualcosa del genere (anche se stai effettivamente utilizzando quella variabile per incrementare un altro valore).
Ripetizione
C'è ripetizione nel tuo codice, ad esempio:
#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']))
Prima di tutto, alcune affermazioni sono ridondanti:
#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)
Poiché stai concatenando tre elenchi, anche l'oggetto risultante è un oggetto elenco. Quindi, cards = cards1 + cards2 + cards3è sufficiente e produce lo stesso risultato.
carte1 / 2/3 sono esattamente le stesse, quindi stai ripetendo la stessa identica cosa 3 volte di seguito. Questo è ovviamente sbagliato e può essere semplificato. Potresti semplicemente scrivere:
cards2 = cards1
cards3 = cards1
anche se non è elegante ma almeno eviti la ripetizione e il tuo intervallo viene dichiarato una sola volta.
Un modo migliore:
cards = list(itertools.product(range(2, 15), ['spade', 'heart', 'diamond', 'club'])) *3
Pertanto, hai ripetuto la sequenza tre volte e hai creato un nuovo elenco. Dato che stai usando itertools, potresti anche usare itertools.repeat, che ti dà un generatore, mentre * nti dà un elenco, che va bene qui.
Concatenazione
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 è una stringa, quindi puoi concatenare in sicurezza tutti questi elementi. O meglio ancora, usa una stringa F (Python> = 3.6):
full_name = f"Jack of {full_name}"