Primo tentativo in un gioco di Java Blackjack

Ho appena completato il mio primo programma multi classe, Blackjack, e funziona! Permette allutente di giocare a Blackjack contro un solo dealer, senza altri giocatori al tavolo. Mi chiedevo, visto che è il mio primo programma multi classe, se puoi aiutarmi a ottimizzarlo e / o darmi qualche consiglio. Voglio implementare lassicurazione e la divisione, quindi qualsiasi consiglio per aiutare a preparare il codice per aggiungere eventualmente queste funzionalità sarebbe davvero utile! Infine, il mio metodo principale è piuttosto lungo: mi chiedevo se questo fosse tipico dei programmi Java e, in caso contrario, come posso risolverlo.

Scheda

package Blackjack; class Card { /* * Creates a playing card. */ private int rank;//represents the rank of a card private int suit;//represents the suit of a card private int value;//represents the value of a card private static String[] ranks = {"Joker","Ace","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Jack","Queen","King"}; private static String[] suits = {"Clubs","Diamonds","Hearts","Spades"}; /* * Created with an integer that represents a spot in the String array ranks and the String array suits. This represents * the rank and suit of an individual card. */ Card(int suit, int values) { this.rank=values; this.suit=suit; } /* * Returns the string version of a card. */ public String toString() { return ranks[rank]+" of "+suits[suit]; } /* * Returns the rank of a card. */ public int getRank() { return rank; } /* * Returns the suit of a card. */ public int getSuit() { return suit; } /* * Returns the value of a card. If a jack, queen, or king the value is ten. Aces are 11 for now. */ public int getValue() { if(rank>10) { value=10; } else if(rank==1) { value=11; } else { value=rank; } return value; } /* * Sets the value of a card. */ public void setValue(int set) { value = set; } 

Deck

package Blackjack; import java.util.ArrayList; import java.util.Random; /* * Creates and shuffles a deck of 52 playing cards. */ class Deck { private ArrayList<Card> deck;//represents a deck of cards Deck() { deck = new ArrayList<Card>(); for(int i=0; i<4; i++) { for(int j=1; j<=13; j++) { deck.add(new Card(i,j)); } } } /* * Shuffles the deck by changing the indexes of 200 random pairs of cards in the deck. */ public void shuffle() { Random random = new Random(); Card temp; for(int i=0; i<200; i++) { int index1 = random.nextInt(deck.size()-1); int index2 = random.nextInt(deck.size()-1); temp = deck.get(index2); deck.set(index2, deck.get(index1)); deck.set(index1, temp); } } /* * Draws a card from the deck. */ public Card drawCard() { return deck.remove(0); } 

Rivenditore

package Blackjack; import java.util.ArrayList; import java.util.Arrays; /* * Creates a dealer that the user plays against. */ class Dealer { ArrayList<Card> hand;//represents the dealer"s hand private int handvalue=0;//value of the dealer"s hand (starts at 0) private Card[] aHand;//used to convert the dealer"s hand to an array private int AceCounter;//counts the aces in the dealer"s hand Dealer(Deck deck) { hand = new ArrayList<>(); aHand = new Card[]{}; int AceCounter=0; for(int i=0; i<2; i++) { hand.add(deck.drawCard()); } aHand = hand.toArray(aHand); for(int i=0; i<aHand.length; i++) { handvalue += aHand[i].getValue(); if(aHand[i].getValue()==11) { AceCounter++; } while(AceCounter>0 && handvalue>21) { handvalue-=10; AceCounter--; } } } /* * Prints the dealer"s first card (the card face up at the beginning of a blackjack game). */ public void showFirstCard() { Card[] firstCard = new Card[]{}; firstCard = hand.toArray(firstCard); System.out.println("["+firstCard[0]+"]"); } /* * Gives the dealer another card and updates the value of his hand. Takes into account the value of aces. */ public void Hit(Deck deck) { hand.add(deck.drawCard()); aHand = hand.toArray(aHand); handvalue = 0; for(int i=0; i<aHand.length; i++) { handvalue += aHand[i].getValue(); if(aHand[i].getValue()==11) { AceCounter++; } while(AceCounter>0 && handvalue>21) { handvalue-=10; AceCounter--; } } } /* * Determines if the dealer wants to hit according to classic Blackjack rules. */ public boolean wantsToHit() { if(handvalue<17) { return true; } return false; } /* * Returns true if the dealer has blackjack. */ public boolean hasBlackJack() { if(hand.size()==2 && handvalue==21) { System.out.println("The dealer has blackjack!"); return true; } return false; } /* * Prints the dealer"s hand. */ public void showHand() { System.out.println(hand); } /* * Returns the value of the dealer"s hand. */ public int getHandValue() { return handvalue; } /* * Determines if a dealer has busted. */ public boolean busted(int handvalue) { if(handvalue>21) { System.out.println("The dealer busted!"); return true; } return false; } /* * Takes the turn for the dealer and returns the value of his hand. */ public int takeTurn(Deck deck) { while(wantsToHit()) { System.out.println("The dealer hits"); Hit(deck); if(busted(handvalue)) { break; } } if(handvalue<=21) { System.out.print("The dealer stands."); } return handvalue; } 

Principale

package Blackjack; import java.util.*; public class Blackjack { private static int cash;//cash the user bets with private static int bet;//how much the user wants to bet private static int AceCounter;//how many aces are in the user"s hand private static ArrayList<Card> hand;//represents the user"s hand private static int handvalue;//the value of the user"s hand private static String name;//name of the user public static void main(String[] args){ System.out.println("Hi! What is your name?"); Scanner scan = new Scanner(System.in); name = scan.nextLine(); System.out.println("Hello, "+name+", lets play some BlackJack!"); System.out.println("How much cash do you want to start with?"); Scanner money = new Scanner(System.in); cash = money.nextInt(); System.out.println("You start with cash: "+cash); while(cash>0){ Deck deck = new Deck();//initialize deck, dealer, hands, and set the bet. deck.shuffle(); AceCounter=0; Dealer dealer = new Dealer(deck); List<Card> hand = new ArrayList<>(); hand.add(deck.drawCard()); hand.add(deck.drawCard()); System.out.println("How much would you like to bet?"); bet=Bet(cash); System.out.println("Cash:"+(cash-bet)); System.out.println("Money on the table:"+bet); System.out.println("Here is your hand: "); System.out.println(hand); int handvalue = calcHandValue(hand); System.out.println("The dealer is showing: "); dealer.showFirstCard(); if(hasBlackJack(handvalue) && dealer.hasBlackJack())//check if both the user and dealer have blackjack. { Push(); } else if(hasBlackJack(handvalue))//check if the user has blackjack. { System.out.println("You have BlackJack!"); System.out.println("You win 2x your money back!"); cash=cash+bet; Win(); } else if(dealer.hasBlackJack())//check if the dealer has blackjack. { System.out.println("Here is the dealer"s hand:"); dealer.showHand(); Lose(); } else { if(2*bet<cash)//check if the user can double down. { System.out.println("Would you like to double down?");//allows the user to double down. Scanner doubledown = new Scanner(System.in); String doubled = doubledown.nextLine(); while(!isyesorno(doubled)) { System.out.println("Please enter yes or no."); doubled = doubledown.nextLine(); } if(doubled.equals("yes")) { System.out.println("You have opted to double down!"); bet=2*bet; System.out.println("Cash:"+(cash-bet)); System.out.println("Money on the table:"+bet); } } System.out.println("Would you like to hit or stand?");//ask if the user will hit or stand Scanner hitorstand = new Scanner(System.in); String hitter = hitorstand.nextLine(); while(!isHitorStand(hitter)) { System.out.println("Please enter "hit" or "stand"."); hitter = hitorstand.nextLine(); } while(hitter.equals("hit"))//hits the user as many times as he or she pleases. { Hit(deck, hand); System.out.println("Your hand is now:"); System.out.println(hand); handvalue = calcHandValue(hand); if(checkBust(handvalue))//checks if the user busted { Lose(); break; } if(handvalue<=21 && hand.size()==5)//checks for a five card trick. { fivecardtrick(); break; } System.out.println("Would you like to hit or stand?"); hitter = hitorstand.nextLine(); } if(hitter.equals("stand"))//lets the user stand. { int dealerhand = dealer.takeTurn(deck);//takes the turn for the dealer. System.out.println(""); System.out.println("Here is the dealer"s hand:"); dealer.showHand(); if(dealerhand>21)//if the dealer busted, user wins. { Win(); } else { int you = 21-handvalue;//check who is closer to 21 and determine winner int deal = 21-dealerhand; if(you==deal) { Push(); } if(you<deal) { Win(); } if(deal<you) { Lose(); } } } } System.out.println("Would you like to play again?");//ask if the user wants to keep going Scanner yesorno = new Scanner(System.in); String answer = yesorno.nextLine(); while(!isyesorno(answer)) { System.out.println("Please answer yes or no."); answer = yesorno.nextLine(); } if(answer.equals("no")) { break; } } System.out.println("Your cash is: "+cash);//if user doesn"t want to play or runs out of cash, either congratulates them on their winnings or lets them know if(cash==0) { System.out.println("You ran out of cash!"); } else { System.out.println("Enjoy your winnings, "+name+"!"); } } /* * Checks if the user has blackjack. */ public static boolean hasBlackJack(int handValue) { if(handValue==21) { return true; } return false; } /* * Calculates the value of a player"s hand. */ public static int calcHandValue(List<Card> hand) { Card[] aHand = new Card[]{}; aHand = hand.toArray(aHand); int handvalue=0; for(int i=0; i<aHand.length; i++) { handvalue += aHand[i].getValue(); if(aHand[i].getValue()==11) { AceCounter++; } while(AceCounter>0 && handvalue>21) { handvalue-=10; AceCounter--; } } return handvalue; } /* * Asks the user how much he or she would like to bet. */ public static int Bet(int cash) { Scanner sc=new Scanner(System.in); int bet=sc.nextInt(); while(bet>cash) { System.out.println("You cannot bet more cash than you have!"); System.out.println("How much would you like to bet?"); bet=sc.nextInt(); } return bet; } /* * Called if the user wins. */ public static void Win() { System.out.println("Congratulations, you win!"); cash=cash+bet; System.out.println("Cash: "+cash); } /* * Called if the user loses. */ public static void Lose() { System.out.println("Sorry, you lose!"); cash=cash-bet; System.out.println("Cash: "+cash); } /* * Called if the user pushes */ public static void Push() { System.out.println("It"s a push!"); System.out.println("You get your money back."); System.out.println("Cash: "+cash); } /* * Adds a card to user"s hand and calculates the value of that hand. Aces are taken into account. */ public static void Hit(Deck deck, List<Card> hand) { hand.add(deck.drawCard()); Card[] aHand = new Card[]{}; aHand = hand.toArray(aHand); handvalue = 0; for(int i=0; i<aHand.length; i++) { handvalue += aHand[i].getValue(); if(aHand[i].getValue()==11) { AceCounter++; } while(AceCounter>0 && handvalue>21) { handvalue-=10; AceCounter--; } } } /* * Determines if a user has input hit or stand. */ public static boolean isHitorStand(String hitter) { if(hitter.equals("hit") || hitter.equals("stand")) { return true; } return false; } /* * Determines if a user has busted. */ public static boolean checkBust(int handvalue) { if(handvalue>21) { System.out.println("You have busted!"); return true; } return false; } /* * Determines if a user has input yes or no. */ public static boolean isyesorno(String answer) { if(answer.equals("yes") || answer.equals("no")) { return true; } return false; } /* * Called if the user has a five card trick. */ public static void fivecardtrick() { System.out.println("You have achieved a five card trick!"); Win(); } 

Commenti

Risposta

Struttura della classe

  • Una classe Hand potrebbe essere utile. Può calcolare e memorizzare il valore della mano. Ciò eviterebbe anche la duplicazione che hai attualmente (calcHandValue e Hit).
  • Il tuo Dealer contiene molto codice che non inserirò lì. Contiene lIA del mazziere (quando colpisce il mazziere?), Il controllo delle condizioni di vincita / sconfitta, stampa e conteggio. Con una classe Hand, ne separeresti già una parte. Vorrei anche rimuovere tutte le stampe (rendono difficile il riutilizzo del codice e portare a una cattiva struttura del codice) e separare la logica dellIA dalla sua classe (questo renderebbe più facile cambiare le regole, perché sono tutte in una place).
  • Anche la tua classe Blackjack fa troppo. Stampa, legge input, gestisce input, controlla le condizioni di vittoria / sconfitta (di nuovo, una duplicazione, vedere il punto successivo), ecc. È il giocatore, oltre che il gioco, che viola il principio di responsabilità unica.
  • Ogni volta che copi / incolli il codice, cerca di pensare a unalternativa migliore. in questo caso, la tua Dealer e la tua classe Blackjack contengono molti duplicati. Principalmente perché entrambi rappresentano un giocatore di blackjack (il banco e il player). Potrebbe essere utile una classe Player generica, dalla quale Dealer e HumanPlayer estendere .

Quindi, per riassumere: aggiungerei almeno un Hand, Player e HumanPlayer. Forse anche uninterfaccia Input / Output e ConsoleInput / ConsoleOutput classe (che renderebbe facile aggiungere una GUI). Ci sono più classi che potresti creare, ma questo sarebbe un buon inizio.

Varie

  • lintera funzione shuffle può essere sostituita da Collections.shuffle(deck);.
  • Perché il tuo Dealer classe ha hand e aHand? Sembra inutile e crea confusione.
  • hai alcuni problemi di stile (posizione della parentesi graffa, rientro, spazi, ecc.). Sembra per lo più internamente coerente (questa è la parte importante), ma non corrisponde realmente a ciò a cui è abituata la maggior parte dei programmatori Java. La maggior parte degli IDE che supportano Java (es. Netbeans o Eclipse) formatta il codice per impostazione predefinita in un modo che la maggior parte dei programmatori Java riconosce .
  • I nomi delle variabili e dei metodi devono iniziare in minuscolo, in modo da non essere confusi con le classi.
  • if (cond) return true else return false possono essere scritti come return cond.

Commenti

  • ok, proverò alcune di queste cose. Grazie mille . Non ‘ capisco bene perché dovrei aggiungere uninterfaccia di input / output e cosa vorrei fargli fare. Ti dispiace spiegare un po di più su questo punto?
  • inoltre, in quale classe consiglieresti di eseguire il gioco?
  • @Jared Input raccoglierebbe semplicemente lazione (che potrebbe essere un enum; hit, split, ecc.) e loutput verrebbe generato tutto. La ragione principale è che separa quelle cose dal resto es il tuo codice più leggibile e soprattutto più riutilizzabile. Puoi eseguire il gioco in una classe BlackJackGame, che dovrebbe mantenere il ciclo di gioco (che chiamerebbe altre classi per distribuire una mano, ricevere input, controllare le condizioni finali e applicare i risultati, dopodiché tratta la mano successiva). Tutto il resto dovrebbe idealmente accadere altrove.
  • se ‘ t troppi problemi, hai qualche codice di esempio o link al codice di esempio di un gioco o qualcosa che considereresti ben strutturato?
  • Molto ben fatto, vittoria meritata! +1

Risposta

Cè “molto da migliorare su questo. Ecco un paio di suggerimenti per iniziare.

Commenti eccessivi

Questi commenti aggiungono qualcosa di nuovo che “non è già chiaro?

private int rank;//represents the rank of a card private int suit;//represents the suit of a card private int value;//represents the value of a card 

Non “t. In effetti la maggior parte degli altri commenti nel codice non aggiunge valore neanche. Il codice migliore non ha bisogno di commenti. Controlla tutti i commenti nel tuo codice, se non sono necessari, quindi rimuovili, se sono necessari, quindi prova a cambiare il codice in modo da non aver bisogno di commenti.

Rendere Card immutabile

avrà senso per rank, suit e value per modificare la durata di unistanza Card? Probabilmente no. Quindi crea questi campi final. Esiste un metodo setValue, di cui non hai bisogno.

Rivedi anche le altre classi. Rendi tutto final che non ha bisogno di cambiare o che non ha senso cambiare mai. Questa pratica può aiutarti a individuare alcuni bug di progettazione.

Fai riferimento ai tipi tramite interfacce

Dichiari diversi elenchi in questo modo:

ArrayList<Card> hand; 

Utilizza invece il tipo di interfaccia:

List<Card> hand; 

Considera enum s

Queste variabili sono buone candidate per enum s:

private static String[] ranks = {"Joker","Ace","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Jack","Queen","King"}; private static String[] suits = {"Clubs","Diamonds","Hearts","Spades"}; 

In questo modo:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Se vuoi scorrere i possibili semi, puoi fare for (Suit suit : Suit.values()) { ... }

Numeri magici

Ci sono troppi numeri magici nel codice. 17, 10, 11, 4, … Sarebbe meglio metterli in public static final variabili con nomi descrittivi, per chiarire lo scopo di questi valori, inserirli insieme in alto del codice per un controllo più facile e flessibilità con cui giocare.

Formattazione

Il codice non segue la formattazione comune generata dallopzione di formattazione automatica di IDE comuni come Eclipse e IntelliJ . Suggerisco di riformattare lintera cosa, per rendere il codice più familiare e più facile da leggere per la maggior parte dei programmatori Java. In Eclipse la scorciatoia da tastiera è Control-Shift-f

Commenti

  • Se utilizzo il formato automatico, è così che i programmi vengono solitamente formattati?
  • Sì, ‘ è il modo comune
  • I ‘ d aggiungo lintero ” valore ” di Card non è necessario, lo è solo la funzione getValue (), che necessita solo del rango per funzionare.

Risposta

Restituisce il valore booleano direttamente

Il seguente:

public static boolean isyesorno(String answer) { if(answer.equals("yes") || answer.equals("no")) { return true; } return false; } 

dovrebbe diventare:

public static boolean isyesorno(String answer) { return answer.equals("yes") || answer.equals("no")) } 

Lo stesso vale per public static boolean hasBlackJack(int handValue) e public static boolean isHitorStand(String hitter) e public static boolean checkBust(int handvalue) per questultimo dovresti spostare la stampa fuori dalla funzione.

Usa ruote già esistenti

Puoi mescolare il mazzo usando il built -in:

List<Cards> list = Arrays.asList(deck); Collections.shuffle(list); 

Commenti

  • mescolando in questo modo mescolerò il mio mazzo ArrayList, o mi darò una nuova lista chiamata lista che viene mescolata?
  • @Jared al suo posto ..

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *