První pokus o hru Java Blackjack

Právě jsem dokončil svůj první program pro více tříd, Blackjack, a funguje to! Umožňuje uživateli hrát Blackjack proti jednomu dealerovi bez dalších hráčů u stolu. Zajímalo by mě, když jsem viděl, že je to můj první program pro více tříd, jestli mi můžete pomoci jej optimalizovat a / nebo mi poradit. Chci implementovat pojištění a rozdělení, takže jakákoli rada, která by pomohla připravit kód pro případné přidání těchto funkcí, by byla opravdu užitečná! Nakonec je moje hlavní metoda docela dlouhá – přemýšlel jsem, jestli je to typické pro Java programy, a pokud ne, jak to mohu opravit.

Karta

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; } 

Paluba

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); } 

Dealer

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; } 

Hlavní

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(); } 

Komentáře

Odpověď

Struktura třídy

  • Třída Hand může být užitečná. Může vypočítat a uložit hodnotu ruky. Tím by se také zabránilo duplikaci, kterou aktuálně máte (calcHandValue a Hit).
  • Vaše obsahuje spoustu kódu, který bych tam neumístil. Obsahuje AI dealera (kdy zasáhne dealera?), Kontrolu stavu výhry / ztráty, tisk a počítání. S třídou Hand byste už část z toho oddělili. Také bych odstranil všechny výtisky (ztěžují opětovné použití kódu a vedou ke špatné struktuře kódu) a oddělil logiku AI do vlastní třídy (to by usnadnilo změnu pravidel, protože jsou všechny v jednom místo).
  • Vaše třída Blackjack také dělá příliš mnoho. Tiskne, čte vstup, zpracovává vstup, kontroluje stav vítězství / ztráty (opět duplikace, viz další bod) atd. Je to hráč i hra, která porušuje princip jediné odpovědnosti.
  • Kdykoli zkopírujete / vložíte kód, zkuste vymyslet lepší alternativu. v tomto případě vaše Dealer a vaše Blackjack třída obsahují spoustu duplikací. Hlavně proto, že oba představují hráče blackjacku (dealer i přehrávač). Mohla by být užitečná obecná Player třída, ze které vychází Dealer a HumanPlayer .

Takže pro shrnutí: Přidal bych minimálně Hand, Player a HumanPlayer třídy. Možná také Input / Output rozhraní a ConsoleInput / ConsoleOutput třída (což by usnadnilo přidání grafického uživatelského rozhraní). Můžete vytvořit více tříd, ale to by byl dobrý začátek.

Různé

  • celou vaši shuffle funkci lze nahradit Collections.shuffle(deck);.
  • Proč vaše Dealer třída má hand a aHand? To se zdá být zbytečné a matoucí.
  • máte nějaké problémy se stylem (poloha složené závorky, odsazení, mezery atd.). Vypadá to, že je většinou vnitřně konzistentní (to je důležitá součást), ale neodpovídá tomu, na co je většina programátorů Java zvyklá. Většina IDE, která podporují Javu (např. Netbeans nebo Eclipse), formátuje kód podle výchozího nastavení tak, jak to většina programátorů Java rozpozná .
  • názvy proměnných a metod by měly začínat malými písmeny, aby nedošlo k jejich záměně s třídami.
  • if (cond) return true else return false lze zapsat jako return cond.

Komentáře

  • dobře, zkusím některé z těchto věcí. Moc děkuji . Nerozumím tomu ‚ proč bych přidal vstupní / výstupní rozhraní a co by to přimělo. Vadilo by vám vysvětlit trochu více o tomto bodě?
  • Také, ve které třídě byste mi doporučil spustit hru?
  • @Jared Input by jen shromáždil akci (což by mohlo být enum; hit, split atd.) a výstup by se vydal Hlavním důvodem je to, že odděluje tyto věci od ostatních Díky tomu je váš kód čitelnější a zejména znovu použitelný. Svou hru můžete provozovat ve třídě BlackJackGame, která by měla udržovat herní smyčku (která by volala další třídy, aby rozdaly ruku, získaly vstup, zkontrolovaly konečný stav a použily výsledky, poté rozdává další ruku). Všechno ostatní by se mělo ideálně stát jinde.
  • pokud to není ‚ příliš mnoho problémů, máte nějaký ukázkový kód nebo nějaké odkazy na ukázkový kód hry nebo něco, co byste považovali za dobře strukturované?
  • Velmi pěkně provedené, zasloužené vítězství! +1

Odpověď

V této oblasti je co vylepšovat. Zde je několik tipů pro začátek.

Nadměrné komentáře

Přidávají tyto komentáře něco nového, co již není jasné?

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 

Nepřináší. Ve skutečnosti většina ostatních komentářů v kódu nepřidává žádnou hodnotu. Nejlepší kód nepotřebuje komentáře. Prohlédněte si všechny komentáře v kódu, pokud nejsou potřeba, pak je odstraňte, pokud jsou potřeba, zkuste změnit kód tak, aby komentáře nepotřeboval.

Vytvoření Card nezměnitelného

Bude to mít smysl pro rank, suit a value ke změně v životnosti instance Card? Pravděpodobně ne. Vytvořte tato pole final. Existuje setValue metoda, kterou také nepotřebujete.

Zkontrolujte také ostatní třídy. Dělejte vše, co final nemusí měnit nebo nemá smysl se kdy měnit. Tato praxe vám pomůže najít některé designové chyby.

Odkazy na typy podle rozhraní

Deklarujete několik takových seznamů:

ArrayList<Card> hand; 

Místo toho použijte typ rozhraní:

List<Card> hand; 

Zvažte enum s

Tyto proměnné jsou vhodnými kandidáty pro 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"}; 

Líbí se mi:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Pokud chcete iterovat nad možnými obleky, můžete provést for (Suit suit : Suit.values()) { ... }

Kouzelná čísla

V kódu je příliš mnoho magických čísel. 17, 10, 11, 4, … Bylo by lepší dát je do public static final proměnných s popisnými názvy, aby bylo možné objasnit účel těchto hodnot, mít je společně nahoře kódu pro snazší ovládání a flexibilitu při hraní.

Formátování

Kód nedodržuje běžné formátování generované možností automatického formátování běžných IDE, jako jsou Eclipse a IntelliJ . Navrhuji celou věc přeformátovat, aby kód vypadal známější a lépe čitelný pro většinu kodérů Java. V Eclipse je klávesová zkratka Control-Shift-f

Komentáře

  • Pokud používám automatický formát, je to způsob, jakým jsou programy obvykle formátovány?
  • Ano, ‚ je běžný způsob
  • Přidal jsem celou “ hodnotu “ Card není nutný, pouze funkce getValue (), která ke svému fungování potřebuje pouze hodnost.

Odpověď

Vraťte logickou hodnotu přímo

Následující:

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

by se mělo stát:

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

Totéž platí pro public static boolean hasBlackJack(int handValue) a public static boolean isHitorStand(String hitter) a public static boolean checkBust(int handvalue) pro druhé byste měli přesunout tisk z funkce.

Použít již existující kola

Palubu můžete zamíchat pomocí vestavěného -in:

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

Komentáře

  • zamíchá tímto způsobem zamíchat můj balíček ArrayList, nebo mi dá nový seznam s názvem seznam, který je zamíchán?
  • @Jared in place ..

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *