Jag avslutade precis mitt första multiklassprogram, Blackjack, och det fungerar! Det låter användaren spela Blackjack mot en enda återförsäljare, utan andra spelare vid bordet. Jag undrade, eftersom det är mitt första multiklassprogram, om du kan hjälpa mig att optimera det och / eller ge mig några råd. Jag vill implementera försäkring och delning, så alla råd som hjälper dig att förbereda koden för att så småningom lägga till dessa funktioner skulle vara riktigt bra! Slutligen är min huvudmetod ganska lång – jag undrade om det här är typiskt för Java-program och, om inte, hur jag kan fixa det.
Kort
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; }
Däck
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); }
Återförsäljare
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; }
Huvud
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(); }
Kommentarer
- Uppföljningsfråga
Svar
Klassstruktur
- En
Hand
-klass kan vara användbar. Det kan beräkna och lagra handvärdet. Detta skulle också undvika den dubblering du för närvarande har (calcHandValue
ochHit
). - Din
Dealer
-klassen innehåller mycket kod som jag inte skulle placera där. Den innehåller återförsäljarens AI (när träffar dealern?), Kontroll av vinnande / förlorande tillstånd, utskrift och räkning. Med enHand
-klass skulle du redan skilja ut en del av den. Jag skulle också ta bort alla utskrifter (de försvårar kodåteranvändning och leder till dålig kodstruktur) och separerar AI-logiken till sin egen klass (detta skulle göra det lättare att ändra reglerna, för de är alla i ett plats). - Din
Blackjack
-klass gör också alldeles för mycket. Den skriver ut, den läser inmatning, hanterar inmatningen, den kontrollerar vinnande / förlorande skick (igen en duplicering, se nästa punkt), etc. Det är såväl spelaren som spelet som bryter mot principen om enskilt ansvar. - När du kopierar / klistrar in kod, försök tänka på ett bättre alternativ i det här fallet innehåller din
Dealer
och dinBlackjack
mycket duplicering. Främst eftersom de båda representerar en blackjack-spelare (dealern och spelare). En generiskPlayer
-klass kan vara till hjälp, från vilkenDealer
ochHumanPlayer
sträcker sig .
Så för att sammanfatta: Jag skulle åtminstone lägga till en Hand
, Player
och HumanPlayer
. Eventuellt också ett Input
/ Output
gränssnitt och ConsoleInput
/ ConsoleOutput
-klass (vilket skulle göra det enkelt att lägga till ett GUI). Det finns fler klasser du kan skapa, men det här skulle vara en bra start.
Övrigt
- hela din
shuffle
-funktion kan ersättas medCollections.shuffle(deck);
. - Varför gör din
Dealer
klass harhand
ochaHand
? Detta verkar onödigt och förvirrande. - du har vissa stilproblem (position för lockigt fäste, indrag, mellanslag osv.). Det verkar mestadels internt konsekvent (det är den viktiga delen), men matchar inte riktigt det som de flesta Java-programmerare är vana vid. De flesta IDE: er som stöder Java (t.ex. Netbeans eller Eclipse) formaterar koden per standard på ett sätt som de flesta Java-programmerare känner igen .
- variabel- och metodnamn bör börja små bokstäver, så att de inte förväxlas med klasser.
-
if (cond) return true else return false
kan skrivas somreturn cond
.
Kommentarer
- okej jag ska prova några av dessa saker. Tack så mycket . Jag förstår inte ’ varför jag skulle lägga till ett Input / Output-gränssnitt och vad jag skulle få det att göra. Har du något emot att förklara lite mer om den punkten?
- också, vilken klass skulle du rekommendera att jag kör spelet i?
- @Jared Input skulle bara samla in åtgärden (vilket kan vara ett enum; hit, split, etc), och output skulle mata ut Huvudskälet är att det skiljer dessa saker från resten es din kod mer läsbar och särskilt mer återanvändbar. Du kan köra ditt spel i en
BlackJackGame
-klass, som ska upprätthålla spelslingan (som skulle kalla andra klasser för att ta hand, få input, kontrollera slutvillkor och tillämpa resultat, varefter det handlar om nästa hand). Alla andra borde helst hända någon annanstans. - om det inte är ’ inte för mycket besvär, har du någon exempelkod eller några länkar till ett exempel på ett spel eller något som du anser vara välstrukturerat?
- Mycket snyggt gjort, välförtjänt seger! +1
Svar
Det finns en hel del att förbättra på detta. Här är några tips för att komma igång.
Överdrivna kommentarer
Lägger dessa kommentarer till något nytt som inte redan är klart?
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
De behöver inte. De flesta andra kommentarer i koden tillför faktiskt inte heller något värde. Den bästa koden behöver inte kommentarer. Titta igenom alla kommentarer i din kod, om de inte behövs, ta bort dem, om de behövs, försök sedan ändra koden på ett sätt så att du inte behöver kommentarer.
Gör Card
oföränderlig
Kommer det vettigt för rank
, suit
och value
för att ändra under en Card
livstid? Antagligen inte. Så gör dessa fält final
. Det finns en setValue
-metod som du inte behöver heller.
Granska även de andra klasserna. Gör allt final
som inte behöver ändras eller inte är vettigt att någonsin förändras. Denna övning kan hjälpa dig att upptäcka några designfel.
Se typer med gränssnitt
Du förklarar flera listor så här:
ArrayList<Card> hand;
Använd istället gränssnittstypen:
List<Card> hand;
Tänk på enum
s
Dessa variabler är bra kandidater 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"};
Så här:
enum Suit { Clubs, Diamonds, Hearts, Spades }
Om du vill itera över möjliga kostymer kan du göra for (Suit suit : Suit.values()) { ... }
Magiska siffror
Det finns för många magiska nummer i koden. 17, 10, 11, 4, … Det skulle vara bättre att sätta dessa i public static final
variabler med beskrivande namn, för att klargöra syftet med dessa värden, ha dem tillsammans nära toppen av koden för enklare kontroll och flexibilitet att spela med.
Formatering
Koden följer inte den vanliga formateringen som genereras av det automatiska formatet för vanliga IDE: er som Eclipse och IntelliJ Jag föreslår att du omformaterar hela saken, så att koden ser mer bekant ut och lättare att läsa för de flesta Java-kodare. I Eclipse är kortkommandot Control-Shift-f
Kommentarer
- Är det så som program vanligtvis formateras om jag använder autoformat?
- Ja, att ’ är vanligt sätt
- I ’ d lägger till hela ” värde ” attribut för Card behövs inte, det är bara getValue () -funktionen som bara behöver rangordningen för att fungera.
Svara
Returnera boolean direkt
Följande:
public static boolean isyesorno(String answer) { if(answer.equals("yes") || answer.equals("no")) { return true; } return false; }
ska bli:
public static boolean isyesorno(String answer) { return answer.equals("yes") || answer.equals("no")) }
Samma sak gäller public static boolean hasBlackJack(int handValue)
och public static boolean isHitorStand(String hitter)
och public static boolean checkBust(int handvalue)
för den senare ska du flytta utskriften från funktionen.
Använd redan befintliga hjul
Du kan blanda däcket med hjälp av det inbyggda -in:
List<Cards> list = Arrays.asList(deck); Collections.shuffle(list);
Kommentarer
- blandar på detta sätt blandar mitt ArrayList-däck, eller ger mig en ny lista som heter lista som blandas?
- @Jared på plats ..