Jeg fullførte nettopp mitt første multiklasseprogram, Blackjack, og det fungerer! Det lar brukeren spille Blackjack mot en enkelt forhandler, uten andre spillere ved bordet. Jeg lurte på, da det er mitt første multiklasseprogram, om du kan hjelpe meg med å optimalisere det og / eller gi meg noen råd. Jeg ønsker å implementere forsikring og splitting, så noen råd for å forberede koden for til slutt å legge til disse funksjonene vil være veldig nyttige! Til slutt er hovedmetoden min ganske lang – jeg lurte på om dette er typisk for Java-programmer, og hvis ikke, hvordan jeg kan fikse 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; }
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); }
Forhandler
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; }
Hoved
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
- Oppfølgingsspørsmål
Svar
Klassestruktur
- En
Hand
-klasse kan være nyttig. Den kan beregne og lagre håndverdien. Dette vil også unngå duplisering du har (calcHandValue
ogHit
). - Din
Dealer
-klassen inneholder mye kode som jeg ikke ville plassert der. Den inneholder forhandlerens AI (når treffer forhandleren?), Vinner / mister tilstandskontroll, utskrift og telling. Med enHand
-klasse, vil du allerede skille ut noe av det. Jeg vil også fjerne alle utskriftene (de gjør at kodebruk blir vanskelig, og fører til dårlig kodestruktur), og skiller AI-logikken til sin egen klasse (dette vil gjøre det lettere å endre reglene, fordi de alle er i ett sted). - Din
Blackjack
-klasse gjør også alt for mye. Den skriver ut, den leser input, den håndterer input, den sjekker vinnende / tapende tilstand (igjen, en duplisering, se neste punkt) osv. Det er spilleren så vel som spillet som bryter med prinsippet om enkeltansvar. - Når du kopierer / limer inn kode, kan du prøve å tenke på et bedre alternativ. i dette tilfellet inneholder
Dealer
ogBlackjack
mye duplisering. Hovedsakelig fordi de begge representerer en blackjack-spiller (giveren og spiller). En generiskPlayer
-klasse kan være nyttig, somDealer
ogHumanPlayer
strekker seg fra. .
Så for å oppsummere: Jeg vil i det minste legge til en Hand
, Player
og HumanPlayer
klasse. Muligens også et Input
/ Output
grensesnitt og ConsoleInput
/ ConsoleOutput
klasse (som vil gjøre det enkelt å legge til en GUI). Det er flere klasser du kan lage, men dette vil være en god start.
Diverse
- hele
shuffle
-funksjonen kan erstattes avCollections.shuffle(deck);
. - Hvorfor gjør din
Dealer
klasse harhand
ogaHand
? Dette virker unødvendig og forvirrende. - du har noen stilproblemer (posisjon av krøllete parentes, innrykk, mellomrom osv.). Det virker for det meste internt konsistent (det er den viktige delen), men samsvarer egentlig ikke med det de fleste Java-programmerere er vant til. De fleste IDEer som støtter Java (f.eks. Netbeans eller Eclipse) formaterer koden per standard på en måte som de fleste Java-programmerere gjenkjenner. .
- navn på variabler og metoder skal starte små bokstaver, slik at de ikke forveksles med klasser.
-
if (cond) return true else return false
kan skrives somreturn cond
.
Kommentarer
- ok jeg vil prøve noen av disse tingene. Tusen takk .Jeg forstår ikke ‘ hvorfor jeg vil legge til et inngangs- / utgangsgrensesnitt og hva jeg vil få det til å gjøre. Har du noe imot å forklare litt mer om det punktet?
- også, hvilken klasse vil du anbefale at jeg kjører spillet i?
- @Jared Input ville bare samle handlingen (som kan være en enum; hit, split, etc), og output ville output alt. Hovedårsaken er at den skiller disse tingene fra resten es koden din mer lesbar, og spesielt mer gjenbrukbar. Du kan kjøre spillet ditt i en
BlackJackGame
-klasse, som skal opprettholde spillløkken (som vil ringe andre klasser til å håndtere, få innspill, sjekke slutttilstanden og bruke resultatene, hvoretter den gir neste hånd). Resten av det skal ideelt sett skje andre steder. - hvis det ikke er ‘ t for mye trøbbel, har du noen eksempelkoder eller noen lenker til eksempelkoder for et spill eller noe du vil anser som godt strukturert?
- Veldig pent gjort, velfortjent seier! +1
Svar
Det er ganske mye å forbedre på dette. Her er et par tips for å komme i gang.
Overdrevne kommentarer
Legg til disse kommentarene noe nytt som ikke allerede er 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 trenger ikke. De fleste andre kommentarer i koden gir faktisk ikke verdi. Den beste koden trenger ikke kommentarer. Se gjennom alle kommentarene i koden din, hvis de ikke er nødvendige, fjern dem, hvis de er nødvendige, og prøv å endre koden på en måte slik at den ikke trenger kommentarer.
Gjør Card
uforanderlig
Vil det være fornuftig for rank
, suit
og value
for å endre seg i løpet av en Card
forekomst? Sannsynligvis ikke. Så lag disse feltene final
. Det er en setValue
-metode, som du heller ikke trenger.
Gjennomgå også de andre klassene. Gjør alt final
som ikke trenger å endres eller ikke gir mening å endre seg. Denne praksisen kan hjelpe deg med å oppdage noen designfeil.
Henvis til typer med grensesnitt
Du erklærer flere lister som dette:
ArrayList<Card> hand;
Bruk grensesnitttypen i stedet:
List<Card> hand;
Vurder enum
s
Disse variablene er gode kandidater for 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"};
Slik:
enum Suit { Clubs, Diamonds, Hearts, Spades }
Hvis du vil gjenta de mulige dressene, kan du gjøre for (Suit suit : Suit.values()) { ... }
Magiske tall
Det er for mange magiske tall i koden. 17, 10, 11, 4, … Det ville være bedre å sette disse i public static final
variabler med beskrivende navn, for å klargjøre formålet med disse verdiene, ha dem sammen nær toppen av koden for enklere kontroll og fleksibilitet å leke med.
Formatering
Koden følger ikke den vanlige formateringen som genereres av alternativet automatisk format for vanlige IDEer som Eclipse og IntelliJ Jeg foreslår at du reformaterer hele saken, slik at koden ser mer kjent og lettere å lese ut for de fleste Java-kodere. I Eclipse er hurtigtasten Control-Shift-f
Kommentarer
- Hvis jeg bruker automatisk format, er det slik programmene vanligvis er formatert?
- Ja, at ‘ er vanlig måte
- I ‘ d legger til hele » verdi » attributt til Card er ikke nødvendig, bare getValue () -funksjonen er, som bare trenger rangering for å fungere.
Svar
Returner boolean direkte
Følgende:
public static boolean isyesorno(String answer) { if(answer.equals("yes") || answer.equals("no")) { return true; } return false; }
skal bli:
public static boolean isyesorno(String answer) { return answer.equals("yes") || answer.equals("no")) }
Det samme gjelder public static boolean hasBlackJack(int handValue)
og public static boolean isHitorStand(String hitter)
og public static boolean checkBust(int handvalue)
for sistnevnte bør du flytte utskrift ut av funksjonen.
Bruk allerede eksisterende hjul
Du kan blande dekk ved å bruke det innebygde -in:
List<Cards> list = Arrays.asList(deck); Collections.shuffle(list);
Kommentarer
- vil stokke på denne måten blande ArrayList-dekk, eller gi meg en ny liste kalt liste som er blandet?
- @Jared på plass ..