Prototipo di blackjack in C#
Vorrei un feedback sul mio codice, sono nuovo nella programmazione con C # ma ho una certa conoscenza di Lua e Python. C'è qualcosa che devo cambiare/ripulire per renderlo più semplificato?
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);
}
}
}
Risposte
A dire il vero ho realizzato anch'io un progetto simile, è davvero divertente!
1. Tenere traccia dei punteggi
La prima cosa che ho notato è che tieni traccia della somma dei valori per il giocatore e presumibilmente anche per il banco, ma il punteggio di una mano può effettivamente cambiare drasticamente durante il gioco.
1.1. Totali soft nel blackjack
Il Blackjack ha questo concetto chiamato soft totali, il che significa che la somma totale può avere un valore diverso a seconda che ci sia o meno un asso. Ad esempio, se un giocatore ha un asso (1) e un 7, conta effettivamente come 18 (11 + 7). Ma se lo stesso giocatore pesca altri 7, il loro totale sarà 15 (1 + 7 + 7). Il valore dell'asso cambia man mano che peschi più carte, quindi ti sarà più facile tenere i punteggi se in qualche modo tieni le carte separate l'una dall'altra. Questo può essere fatto usando le raccolte.
1.2. Collezioni
Le raccolte sono cose come array (che hai già usato), liste e dizionari. Un elenco di numeri interi è un buon candidato per rappresentare l'attuale collezione di carte di un giocatore (o del mazziere), perché possono cambiare dimensione senza lamentarsi. Inoltre, le liste hanno funzioni integrate per ottenere la somma di tutti i numeri al loro interno, i valori minimo e massimo della lista e molto altro. Puoi utilizzare queste funzioni integrate a tuo vantaggio, oltre al fatto che conosci sempre i numeri all'interno dell'elenco per determinare se il totale di qualcuno è morbido o meno.
2. Ciclo di gioco
Il gioco del blackjack si gioca con un numero finito di carte nella vita reale, ma ovviamente nel codice non devi preoccuparti di questo. Se un giocatore (s)fortunato continua a disegnare assi, alla fine otterrà comunque 21 e terminerà il round. Tuttavia, poiché non puoi prevedere quando un giocatore (o il croupier) perderà, puoi usare qualcosa chiamato loop di gioco. Il ciclo di gioco per il blackjack inizia a eseguire tutta la logica del gioco una volta che un giocatore o il croupier conferma di voler pescare una carta e, una volta terminata l'esecuzione, chiederà di ripetere se necessario.
2.1. Condizioni per la scelta di un'altra carta
Noterai che il giocatore ha molta libertà nel blackjack, può continuare a pescare carte fino a quando non ottiene 21 o va oltre, a quel punto il round finisce per loro. Il commerciante, tuttavia, non ha questa libertà. Puoi trovare maggiori informazioni in merito online.
Ad ogni modo, se ci pensi, sia il giocatore che il banco ad un certo punto prendono la decisione di pescare o meno un'altra carta. Fai un controllo per "Y"
o "N"
quando ti viene dato un input, il che ha senso.
2.2. Traduzione dell'input di testo in true
ofalse
Il tuo DrawChoice
metodo altera a bool
in base all'input del giocatore, ma puoi anche eseguire il refactoring di quel metodo in modo che riceva a string
e restituisca a bool
. In questo modo, puoi tradurre direttamente l'input dell'utente in true
(sì, dammi un'altra carta) o false
(no, non voglio un'altra carta). Potrebbe assomigliare a questo:
// 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";
Tornando all'idea di un loop di gioco, ora hai una condizione che determina se il loop di gioco continua o meno. Una possibile implementazione sarebbe questa:
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. Carte da disegno
Il Blackjack è un gioco di carte, quindi pescherai molte carte, sia per un giocatore che per il banco. Se qualcosa accade spesso nel gioco, è generalmente una buona idea trasformarlo in un metodo in modo da non dover scrivere la stessa logica in posti diversi.
La tua attuale implementazione disegna un valore casuale tra il minimo e il massimo del tuo array di carte. Dalla documentazione apprendiamo quanto segue:
Next(Int32 minValue, Int32 maxValue)
Un numero intero con segno a 32 bit maggiore o uguale a
minValue
e minore dimaxValue
; ovvero, l'intervallo di valori restituiti includeminValue
ma nonmaxValue
. SeminValue
uguale amaxValue
,minValue
viene restituito.
Quindi quando scrivi Next(1, 10)
(da min e max), otterrai al massimo un 9. Un altro problema è che anche se correggi l'implementazione a Next(1, 11)
, avrai uguali probabilità di ottenere qualsiasi valore da 1 a 10. Ma poiché ci sono più carte nel mazzo che ha il valore di 10, dovrebbero apparire più spesso delle carte diverse da 10.
Fortunatamente, il tuo array ha già la corretta distribuzione delle carte, quindi potresti invece generare una posizione casuale valida per ottenere il valore corrispondente dal tuo array.
Alla fine della giornata, ciò che otterrai sarà simile a questo:
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;
}
E poi potresti anche fare qualcosa del genere per pescare ripetutamente carte:
// 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;
}
Spero che sia di aiuto! Buona fortuna e buon divertimento!
Solo alcune note in modo da poter migliorare il tuo codice:
int sum1 = draw1 + draw2; if (sum1 == 21) //Blackjack Ending { Console.WriteLine("Congratulations! You got " + sum1 + "!"); }
Questo non sarà mai vero, perché
- non hai da nessuna parte nelle carte un asso che significa avere un possibile valore di undici.
maxValue
in è il Random.Next(int minValue, int maxValue)limite superiore esclusivo del numero casuale restituito.
Nel void drawChoice(bool contChoice)
metodo l'argomento contChoice
è un tipo di valore. Non puoi modificarlo come pensi. Dopo aver lasciato il metodo, indipendentemente dal fatto che l'utente abbia digitato y o n, il valore di cont1
is still false
. È necessario modificare la firma del metodo in modo che non abbia argomenti ma restituisca un file bool
.
if (cont1 == true)
perché cont1
già è un bool non avrai bisogno di confrontarlo con un bool. Puoi semplicemente usarlo come condizione come if (cont1)
e se avessi bisogno di verificare se una variabile bool è false
che useresti if (!cont1)
.
Non sono sicuro di quanto posso essere utile qui, ma IMHO devi avere una revisione completa del codice con qualcuno che ti parli attraverso il codice. C'è un mucchio di "sbagliato" qui, ma detto questo mi chiedo quale sia il tuo obiettivo con C #: stai solo scrivendo qualcosa di veloce per imparare la sintassi o vuoi capire meglio come progettare le cose in C #.
Se qualcuno venisse da me con questo in un contesto professionale, la prima cosa che gli direi: "Devi essere in grado di testarlo". Vorrei quindi parlare di TDD e provare davvero a sottolineare come questo codice è strutturato per fare troppo. Non ci sono astrazioni e tutto è molto procedurale. Ogni classe dovrebbe fare 1 cosa. Sono sicuro che le persone discuteranno con me su questo punto. Ad ogni modo, il fatto che tu abbia solo 1 lezione è negativo.
Oltre a ciò, solo per "suggerimenti C # rapidi di 2 minuti". Userei le enumerazioni per le carte, quindi invece di 10, 10, 10, avrei 10, Jack, Regina, Asso. Usa invece var. if (cont1 == true)
è uguale a if(cont1)
. Usa variabili con un nome migliore: solo guardando cont1 non ho idea di cosa significhi.
Anche JansthcirlU ha presentato le collezioni. Guardando questo codice, non sembra che tu li capisca, quindi mi concentrerei davvero anche qui.
Continua a codificare :)