Erster Versuch eines Java Blackjack-Spiels

Ich habe gerade mein erstes Mehrklassenprogramm, Blackjack, abgeschlossen und es funktioniert! Es ermöglicht dem Benutzer, Blackjack gegen einen einzelnen Dealer zu spielen, ohne dass andere Spieler am Tisch sitzen. Ich habe mich gefragt, ob Sie mir helfen könnten, es zu optimieren und / oder mir einen Rat zu geben, da es mein erstes Mehrklassenprogramm ist. Ich möchte Versicherungen und Aufteilungen implementieren, daher wäre jeder Ratschlag zur Vorbereitung des Codes für das eventuelle Hinzufügen dieser Funktionen sehr hilfreich! Schließlich ist meine Hauptmethode ziemlich lang – ich habe mich gefragt, ob dies typisch für Java-Programme ist und wenn nicht, wie ich das beheben kann.

Karte

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

Händler

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

Haupt

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

Kommentare

Antwort

Klassenstruktur

  • Eine Hand -Klasse kann nützlich sein. Es kann den Handwert berechnen und speichern. Dies würde auch die Duplizierung vermeiden, die Sie derzeit haben (calcHandValue und Hit).
  • Ihre enthält viel Code, den ich dort nicht platzieren würde. Es enthält die Dealer-KI (wann trifft der Dealer?), Die Zustandsprüfung, das Drucken und das Zählen. Mit einer Hand -Klasse würden Sie bereits einige davon trennen. Ich würde auch alle Ausdrucke entfernen (sie erschweren die Wiederverwendung von Code und führen zu einer schlechten Codestruktur) und die KI-Logik von der eigenen Klasse trennen (dies würde es einfacher machen, die Regeln zu ändern, da sie alle in einer sind place).
  • Ihre Blackjack -Klasse macht auch viel zu viel. Sie druckt, liest Eingaben, verarbeitet Eingaben und überprüft die Gewinn- / Verlustbedingung (erneut) eine Vervielfältigung, siehe nächster Punkt) usw. Es ist sowohl der Spieler als auch das Spiel, das gegen das Prinzip der Einzelverantwortung verstößt.
  • Wenn Sie Code kopieren / einfügen, versuchen Sie, eine bessere Alternative zu finden In diesem Fall enthalten Ihre Dealer und Ihre Blackjack -Klasse viele Duplikate. Hauptsächlich, weil beide einen Blackjack-Spieler darstellen (der Dealer und der Spieler). Eine generische Player -Klasse kann hilfreich sein, aus der Dealer und HumanPlayer erweitert werden .

Um es zusammenzufassen: Ich würde mindestens ein Hand, Player und HumanPlayer Klasse. Möglicherweise auch eine Input / Output -Schnittstelle und ConsoleInput / ConsoleOutput -Klasse (was das Hinzufügen einer GUI erleichtern würde). Es gibt weitere Klassen, die Sie erstellen könnten, aber dies wäre ein guter Anfang.

Verschiedenes

  • Ihre gesamte shuffle -Funktion kann durch Collections.shuffle(deck); ersetzt werden.
  • Warum funktioniert Ihre Dealer Klasse haben hand und aHand? Dies erscheint unnötig und verwirrend.
  • Sie haben einige Stilprobleme (Position der geschweiften Klammer, Einrückung, Leerzeichen usw.). Es scheint größtenteils intern konsistent zu sein (das ist der wichtige Teil), entspricht aber nicht wirklich dem, was die meisten Java-Programmierer gewohnt sind. Die meisten IDEs, die Java unterstützen (z. B. Netbeans oder Eclipse), formatieren den Code standardmäßig so, wie es die meisten Java-Programmierer erkennen
  • Variablen- und Methodennamen sollten in Kleinbuchstaben beginnen, damit sie nicht mit Klassen verwechselt werden.
  • if (cond) return true else return false kann als return cond.

Kommentare

  • Okay, ich werde einige dieser Dinge ausprobieren. Vielen Dank Ich verstehe ‚ nicht ganz, warum ich eine Eingabe- / Ausgabeschnittstelle hinzufügen würde und was ich damit machen würde. Stört es Sie, etwas mehr über diesen Punkt zu erklären?
  • Außerdem, in welcher Klasse würdest du empfehlen, dass ich das Spiel starte?
  • @Jared Input würde nur die Aktion sammeln (was eine Aufzählung sein könnte; Treffer, Teilung usw.) und die Ausgabe würde ausgegeben Alles. Der Hauptgrund ist, dass es diese Dinge vom Rest trennt. Es macht Ihr Code ist lesbarer und vor allem wiederverwendbarer. Sie können Ihr Spiel in einer BlackJackGame -Klasse ausführen, die die Spielschleife beibehalten soll (die andere Klassen aufruft, um eine Hand zu geben, Eingaben zu erhalten, die Endbedingung zu überprüfen und Ergebnisse anzuwenden. Danach es geht um die nächste Hand). Der Rest sollte idealerweise woanders stattfinden.
  • Wenn es nicht ‚ zu viel Ärger gibt, haben Sie einen Beispielcode oder Links zum Beispielcode eines Spiels oder etwas, das Sie für gut strukturiert halten?
  • Sehr gut gemacht, wohlverdienter Sieg! +1

Antwort

Es gibt eine Menge zu verbessern. Hier einige Tipps

Übermäßige Kommentare

Fügen diese Kommentare etwas Neues hinzu, das noch nicht klar ist?

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 

Sie tun dies nicht. Tatsächlich bieten die meisten anderen Kommentare im Code auch keinen Mehrwert. Der beste Code benötigt keine Kommentare. Durchsuchen Sie alle Kommentare in Ihrem Code, wenn sie nicht benötigt werden, entfernen Sie sie, wenn sie benötigt werden, und versuchen Sie dann, den Code so zu ändern, dass keine Kommentare benötigt werden. P. >

Card unveränderlich machen

Ist es sinnvoll für rank, suit und value, um die Lebensdauer einer Card -Instanz zu ändern? Wahrscheinlich nicht. Machen Sie diese Felder also zu final. Es gibt eine setValue -Methode, die Sie auch nicht benötigen.

Überprüfen Sie auch die anderen Klassen. Machen Sie alles final, was sich nicht ändern muss oder keinen Sinn ergibt, um sich jemals zu ändern. Diese Vorgehensweise kann Ihnen dabei helfen, einige Designfehler zu erkennen.

Beziehen Sie sich auf Typen nach Schnittstellen

Sie deklarieren mehrere Listen wie folgt:

ArrayList<Card> hand; 

Verwenden Sie stattdessen den Schnittstellentyp:

List<Card> hand; 

Betrachten Sie enum s

Diese Variablen sind gute Kandidaten für 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"}; 

So:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Wenn Sie die möglichen Anzüge durchlaufen möchten, können Sie for (Suit suit : Suit.values()) { ... }

Magische Zahlen

Der Code enthält zu viele magische Zahlen. 17, 10, 11, 4, … Es ist besser, diese in public static final -Variablen mit beschreibenden Namen einzufügen, um den Zweck dieser Werte zu verdeutlichen, und sie oben zusammenzufassen des Codes für eine einfachere Steuerung und Flexibilität beim Spielen.

Formatierung

Der Code folgt nicht der allgemeinen Formatierung, die durch die automatische Formatierungsoption gängiger IDEs wie Eclipse und IntelliJ generiert wird Ich schlage vor, das Ganze neu zu formatieren, damit der Code für die meisten Java-Codierer vertrauter und leichter lesbar erscheint. In Eclipse lautet die Tastenkombination Control-Shift-f

Kommentare

  • Wenn ich das automatische Format verwende, werden Programme normalerweise so formatiert?
  • Ja, das ist ‚ das üblicher Weg
  • Ich ‚ würde den gesamten “ Wert “ -Attribut von Card wird nicht benötigt, sondern nur die Funktion getValue (), für deren Funktion nur der Rang erforderlich ist.

Antwort

Geben Sie den Booleschen Wert direkt zurück.

Folgendes:

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

sollte werden:

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

Gleiches gilt für public static boolean hasBlackJack(int handValue) und public static boolean isHitorStand(String hitter) und public static boolean checkBust(int handvalue) für letztere sollten Sie das Drucken aus der Funktion heraus verschieben.

Verwenden Sie bereits vorhandene Räder

Sie können das Deck mithilfe des gebauten mischen -in:

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

Kommentare

  • mischt auf diese Weise mein ArrayList-Deck oder gibt es mir Eine neue Liste namens Liste, die gemischt wird?
  • @Jared in place ..

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.