Prototipo de blackjack C#
Me gustaría recibir comentarios sobre mi código, soy nuevo en la codificación con C# pero tengo algunos conocimientos sobre Lua y Python. ¿Hay algo que deba cambiar/limpiar para simplificarlo más?
using System;
using System.Linq;
class MainClass {
public static void Main () {
int[] cards = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
Console.WriteLine("Welcome to Blackjack. Here are your draws.");
Random drawCard = new Random();
int draw1 = drawCard.Next(cards.Min(), cards.Max());
int draw2 = drawCard.Next(cards.Min(), cards.Max());
Console.WriteLine("You recieved a " + draw1 + " card!");
Console.WriteLine("You recieved a " + draw2 + " card!");
int sum1 = draw1 + draw2;
if (sum1 == 21) //Blackjack Ending
{
Console.WriteLine("Congratulations! You got " + sum1 + "!");
}
else if (sum1 >= 11) //Choice of 3rd draw
{
Console.WriteLine("Is " + sum1 + " enough?");
bool cont1 = false;
drawChoice(cont1); //Call the draw choice function
if (cont1 == true)
{
int draw3 = drawCard.Next(cards.Min(), cards.Max());
Console.WriteLine("You drawed a " + draw3 + " card!");
int sum2 = draw3 + sum1;
Console.WriteLine("You have a total of " + sum2 + ".");
if (sum2 > 21) Console.WriteLine("Game Over!");
}
else //NPC's turn starts
{
}
}
else //Player has less than 11 cards, auto draw
{
Console.WriteLine("You have a total of " + sum1 + ".");
Console.WriteLine("You will be forced to draw another card.");
int draw3 = drawCard.Next(cards.Min(), cards.Max());
Console.WriteLine("You drawed a " + draw3 + " card!");
int sum2 = draw3 + sum1;
Console.WriteLine("You have a total of " + sum2 + ".");
}
}
static void drawChoice(bool contChoice) //Function for player to choose whether to draw
{
Console.WriteLine("Would you like to draw another card? Y/N");
string choice1 = Console.ReadLine();
if (choice1 == "Y" || choice1 == "y")
{
contChoice = true;
Console.WriteLine(contChoice);
}
else if (choice1 == "N" || choice1 == "n")
{
contChoice = false;
Console.WriteLine(contChoice);
}
}
}
Respuestas
De hecho, yo mismo hice un proyecto similar, ¡es muy divertido!
1. Hacer un seguimiento de las puntuaciones
Lo primero que noté es que haces un seguimiento de la suma de los valores para el jugador y presumiblemente también para el crupier, pero la puntuación de una mano puede cambiar dramáticamente mientras juegas.
1.1. Totales blandos en blackjack
El blackjack tiene este concepto llamado totales blandos , lo que significa que la suma total puede tener un valor diferente dependiendo de si hay un as o no. Por ejemplo, si un jugador tiene un as (1) y un 7, en realidad cuenta como 18 (11 + 7). Pero si ese mismo jugador saca otros 7, su total será 15 (1 + 7 + 7). El valor del as cambia a medida que sacas más cartas, por lo que te resultará más fácil llevar la puntuación si de alguna manera mantienes las cartas separadas entre sí. Esto se puede hacer usando colecciones.
1.2. Colecciones
Las colecciones son cosas como arreglos (que ya ha usado), listas y diccionarios. Una lista de números enteros es un buen candidato para representar la colección actual de cartas de un jugador (o del crupier), porque pueden cambiar de tamaño sin quejarse. Además, las listas tienen funciones integradas para obtener la suma de todos los números dentro de ellas, los valores mínimo y máximo de la lista y mucho más. Puede usar esas funciones integradas a su favor, así como el hecho de que siempre conoce los números dentro de la lista para determinar si el total de alguien es blando o no.
2. Bucle de juego
El juego de blackjack se juega con un número finito de cartas en la vida real, pero por supuesto en el código no tienes que preocuparte por eso. Si un jugador (sin)afortunado sigue sacando ases, eventualmente obtendrá 21 y terminará la ronda. Sin embargo, dado que no puede predecir cuándo un jugador (o el crupier) perderá, puede usar algo llamado bucle de juego. El ciclo del juego para el blackjack comienza a ejecutar toda la lógica del juego una vez que un jugador o el crupier confirman que quieren sacar una carta, y una vez que termina de ejecutarse, pedirá que se repita si es necesario.
2.1. Condiciones para elegir otra tarjeta
Notarás que el jugador tiene mucha libertad en el blackjack, puede seguir sacando cartas hasta que obtiene 21 o pasa, momento en el cual la ronda termina para él. El distribuidor, sin embargo, no tiene esa libertad. Puede encontrar más información al respecto en línea.
De cualquier manera, si lo piensas bien, tanto el jugador como el crupier en algún momento toman la decisión de sacar o no sacar otra carta. Haces una verificación para "Y"
o "N"
cuando se te da una entrada, lo cual tiene sentido.
2.2. Traducir entrada de texto a true
ofalse
Tu DrawChoice
método altera bool
dependiendo de la entrada del jugador, pero también podrías refactorizar ese método para que reciba un string
y devuelva un bool
. De esa forma, puede traducir directamente la entrada del usuario a true
(sí, dame otra tarjeta) o false
(no, no quiero otra tarjeta). Podría verse algo como esto:
// One option
public static bool DrawChoice(string input)
{
if (input == "Y" || input == "y") // You could also use input.ToLower() == "y"
{
return true;
}
else // If it's not "Y" or "y", it's gonna be "N" or "n"
{
return false;
}
// else if (input == "N" || input == "n")
// {
// return false;
// }
}
// Alternative one-liner
public static bool DrawChoice2(string input) => input.ToLower() == "y";
Volviendo a la idea de un bucle de juego, ahora tiene una condición que dicta si el bucle de juego continúa o no. Una posible implementación sería esta:
string choice = Console.ReadLine();
while (DrawChoice(choice)) // No need to write "== true" or "== false"
{
// Stuff that happens if a player or the dealer draws another card
choice = Console.ReadLine() // Ask again once the game logic has executed
}
// Stuff that happens when the loop ends
2.3. tarjetas de dibujo
El blackjack es un juego de cartas, por lo tanto, sacarás muchas cartas, ya sea para un jugador o para el crupier. Si algo sucede con frecuencia en el juego, generalmente es una buena idea convertirlo en un método para que no tengas que escribir la misma lógica en diferentes lugares.
Su implementación actual extrae un valor aleatorio entre el mínimo y el máximo de su conjunto de cartas. De la documentación, aprendemos lo siguiente:
Next(Int32 minValue, Int32 maxValue)
Un entero de 32 bits con signo mayor o igual que
minValue
y menor quemaxValue
; es decir, el rango de valores devueltos incluyeminValue
pero nomaxValue
. SiminValue
es igualmaxValue
,minValue
se devuelve.
Entonces, cuando escribe Next(1, 10)
(desde el mínimo y el máximo), como máximo obtendrá un 9. Otro problema es que incluso si arregla la implementación en Next(1, 11)
, tendrá las mismas probabilidades de obtener cualquier valor del 1 al 10. Pero como hay varias tarjetas en el mazo que tiene el valor de 10, deberían aparecer con más frecuencia que las cartas que no son 10.
Afortunadamente, su matriz ya tiene la distribución correcta de cartas, por lo que podría generar una posición aleatoria válida para obtener el valor correspondiente de su matriz.
Al final del día, lo que obtendrá al final se verá así:
public static int DrawCard()
{
int[] cards = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 };
int card;
// Implement random draw here
return card;
}
Y luego podrías incluso hacer algo como esto para robar cartas repetidamente:
// You could also use a list, which is more flexible
public static int[] DrawCard(int count)
{
int[] drawn = new int[count];
for (int i = 0; i < count; i++)
{
drawn[i] = DrawCard();
}
return drawn;
}
¡Espero que esto ayude! ¡Buena suerte y diviertete!
Solo algunas notas para que puedas mejorar tu código:
int sum1 = draw1 + draw2; if (sum1 == 21) //Blackjack Ending { Console.WriteLine("Congratulations! You got " + sum1 + "!"); }
Esto nunca será verdad, porque
- no tienes en ninguna parte de las cartas un as que signifique tener un valor posible de once.
- el
maxValue
in Random.Next(int minValue, int maxValue)es el límite superior exclusivo del número aleatorio devuelto.
En void drawChoice(bool contChoice)
el método, el argumento contChoice
es un tipo de valor. No puedes modificarlo como crees. Después de abandonar el método, independientemente de si el usuario escribió y o n, el valor de cont1
sigue siendo false
. Debe cambiar la firma del método para que no tenga argumentos pero devuelva un archivo bool
.
if (cont1 == true)
porque cont1
ya es un bool, no necesitarás compararlo con un bool. Simplemente puede usarlo como condición if (cont1)
y si necesita verificar si usaría una variable false
booleana if (!cont1)
.
No estoy seguro de lo útil que puedo ser aquí, pero en mi humilde opinión, necesita tener una revisión completa del código con alguien que le explique el código. Hay un montón de "incorrectos" aquí, pero habiendo dicho eso, me pregunto cuál es su objetivo con C #: ¿está simplemente escribiendo algo rápido para aprender la sintaxis, o desea comprender mejor cómo diseñar cosas en C #?
Si alguien viniera a mí con esto en un entorno profesional, lo primero que les diría: "Tienes que poder probar esto". Luego hablaría sobre TDD y realmente trataría de señalar cómo este código está estructurado para hacer demasiado. No hay abstracciones, y todo es muy procedimental. Cada clase debe hacer 1 cosa. Estoy seguro de que la gente discutirá conmigo sobre este punto. De cualquier manera, el hecho de que solo tengas 1 clase es malo.
Más allá de eso, solo para "consejos rápidos de C # de 2 minutos". Usaría enumeraciones para las cartas, así que en lugar de 10, 10, 10, tendría 10, Jota, Reina, As. Utilice var en su lugar. if (cont1 == true)
es lo mismo que if(cont1)
. Use variables mejor nombradas: solo mirando cont1 no tengo idea de lo que eso significa.
JansthcirlU también mencionó las colecciones. Mirando este código, no parece que los entienda, así que realmente me enfocaría aquí también.
Sigue codificando :)