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
- Domanda di follow-up
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
eHit
). - 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 classeHand
, 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 classeBlackjack
contengono molti duplicati. Principalmente perché entrambi rappresentano un giocatore di blackjack (il banco e il player). Potrebbe essere utile una classePlayer
generica, dalla qualeDealer
eHumanPlayer
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 daCollections.shuffle(deck);
. - Perché il tuo
Dealer
classe hahand
eaHand
? 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 comereturn 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 ..