Secuencia de comandos de blackjack en Python
Recientemente tuve una prueba de Python y, desafortunadamente, fallé. Voy a volver a hacer mi prueba y la maestra me dio el consejo para trabajar de manera más eficiente y limpia. Para practicar esto, hice un juego de blackjack hace unas 2 semanas con Python y se lo envié para que lo comprobara. todavía ha respondido y mi prueba es la semana que viene. ¿Alguien puede echar un vistazo y quizás señalar cosas que necesitan mejorar? por favor, realmente quiero pasar esta prueba.
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)
Cualquier comentario es bienvenido, pero tenga en cuenta que este es mi primer lenguaje de programación y todavía tengo mucho que aprender. ¡Gracias!
Respuestas
Lo siento, pero mis conocimientos sobre juegos de cartas están oxidados. ¡Por favor corríjame si algo anda mal!
Detectar siempre una entrada no válida
Suponga que el usuario va a ingresar algo, que se le solicita desde esta línea de código
print('you have', money, 'money')
bet = int(input('select amount to bet: \n'))
seleccione la cantidad a apostar:
Ahora, lo que si el usuario ha introducido accidentalmente E . En este caso, su programa fallará ya que espera una entrada en forma de entero. Esta es la razón por la que siempre debe detectar la entrada no válida usando Try y Except en Python
try:
bet = int(input("select amount to be: "))
except Exception:
print("Invalid input! Please enter a number\n")
De esta forma, si el usuario ingresó
seleccione la cantidad a ser: me gusta Python
Le daría al usuario
¡Entrada inválida! Por favor, introduzca un número
No salga después de una entrada incorrecta o no válida
En su programa, si el usuario ingresa una apuesta que es más que el dinero que tiene, el programa simplemente se detiene. No se reproducirá de nuevo, ¿por qué debería suceder esto?
Debe pedirle al usuario que ingrese una entrada válida nuevamente, para que cualquier error por su parte no resulte en la terminación inmediata del programa
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
Lo mejor que puede hacer ahora es mover esto a una función separada llamada take_input(), por lo que su blackjack()función puede permanecer limpia, y ahora tomar entradas es fácil
bet = take_input()
Sí, ha escrito algunas líneas más de código. Pero ahora sabe que su programa hará lo correcto cuando ocurran Excepciones.
Simplificar código - 1
first_name = str('Jack'+' of '+first_name)
Es lo mismo que
first_name = "Jack of " + first_name
No es necesario convertir a, strya first_nameque ya es una cadena.
Lo mismo se aplica a las siguientes líneas que extraje de su código.
first_name = str('Queen'+' of '+first_name)
first_name = str('King'+' of '+first_name)
first_name = str('Ace'+' of '+first_name)
Evite los números mágicos
Toma este ejemplo
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... son conocidos como números mágicos . Tuve que pensar un rato para entender qué estaban haciendo aquí hasta que finalmente comprendí que eran cartas.
La buena forma de lidiar con esto es usar las enumeraciones de Python .
from enum import Enum
class Card(Enum):
jack = 11
queen = 12
king = 13
....
Corrija los valores si son incorrectos.
Ahora su hilo if-else parece mucho más claro para el lector
if first_point == Card.jack.value:
...
elif first_point == Card.queen.value:
...
elif first_point = Card.king.value:
....
Otro punto a favor es qué pasa si quieres cambiar el valor del rey de xa y. ¿Irías a los cientos de lugares para encontrar dónde podrías haber usado una constante numérica en contexto para el rey?
aquí puedes configurar king.valuelo que quieras.
import sleep as s
import sleep as ss(0.5)Esto también me confundió al principio, tenía que averiguar qué ssignificaba. sno tiene ningún significado, simplemente confunde a cualquiera que lea su código. Sin embargo, sleepclaramente implica que quieres ... ¡Dormir! Utilice siempre nombres significativos
Dividir el trabajo en funciones
Actualmente, su blackjack()función está abarrotada de muchas tareas que deberían trasladarse a sus propias funciones. Al igual que movimos el procedimiento de entrada a una take_input()función separada , puede crear muchas funciones significativas como draw_new_card()esa para devolver una nueva carta de la baraja.
¿Tu código es SECO o HÚMEDO?
Disculpe mi conocimiento de los juegos de cartas.
Tienes el procedimiento
- dibujar una tarjeta
- comprobar si la tarjeta es de
>=11 puntos - imprimir el punto y el nombre
Entonces, ¿por qué repetir lo mismo de nuevo para la segunda carta? Has escrito lo mismo dos veces. Una vez para la primera carta y la siguiente para la segunda. te has repetido. La mejor manera es factorizar la repetición en una función. Entonces todo lo que necesitas hacer es
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)
......
Puede ver que el uso de funciones ha ayudado mucho.
Convenciones de nombres
Solo para reforzar el punto hecho por @Aryan Parekh: No use abreviaturas sin sentido, por ejemplo:
import random as rd
from time import sleep as s
No hay ningún beneficio, ha hecho que el código sea más difícil de leer y comprender. Por lo tanto: utilizar random.choice(cards)en lugar de: rd.choice(cards). random.choice es autoexplicativo.
Un buen código debe ser intuitivo, que comienza con las convenciones de nomenclatura adecuadas. Incluso si eres perezoso, debes usar nombres más largos y descriptivos, tu IDE debería tener autocompletado de todos modos.
Tienes variables como a, cd2, x, y que me recuerdan al spaghetti Basic de los 80. Apesto totalmente en los juegos de cartas, así que no puedo comentar mucho sobre el algoritmo, pero puedo comentar sobre el código.
Afortunadamente, pones algunos comentarios.
Consistencia
Utiliza la función de elección un par de veces pero con nombres de variables muy diferentes:
a = rd.choice(cards)
x, y = a
y después:
draw = rd.choice(cards)
cards.remove(draw)
add_number, full_name = draw
Creo que aquí se necesita más coherencia . Si reutiliza algunas declaraciones, también podría usar los mismos nombres de variable en otro lugar o al menos ceñirse a algunos patrones de nombres que tengan sentido. dibujar es un nombre que tiene sentido. Pero add_number realmente se parece a un nombre de función, así que lo llamaría card_number o algo así (aunque efectivamente esté usando esa variable para incrementar otro valor).
Repetición
Hay repetición en su código, por ejemplo:
#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']))
En primer lugar, algunas declaraciones son redundantes:
#combine the 3 decks to make 1
cards = list(cards1+cards2+cards3)
Dado que está concatenando tres listas, el objeto resultante también es un objeto de lista. Entonces, cards = cards1 + cards2 + cards3es suficiente y produce el mismo resultado.
cards1 / 2/3 son exactamente iguales, por lo que estás repitiendo exactamente lo mismo 3 veces seguidas. Obviamente, esto es incorrecto y puede simplificarse. Simplemente podría escribir:
cards2 = cards1
cards3 = cards1
aunque eso no es elegante, pero al menos evita la repetición y su rango se declara solo una vez.
Una mejor manera:
cards = list(itertools.product(range(2, 15), ['spade', 'heart', 'diamond', 'club'])) *3
Por lo tanto, ha repetido su secuencia tres veces y ha creado una nueva lista. Como está usando itertools, también puede usar itertools.repeat, que le da un generador, mientras que * nle da una lista, lo cual está bien aquí.
Concatenació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 es una cadena, por lo que puede concatenar todos estos elementos de forma segura. O mejor aún, use una cadena F (Python> = 3.6):
full_name = f"Jack of {full_name}"