Eerste poging tot een Java Blackjack-spel

Ik heb zojuist mijn eerste multi-class programma, Blackjack, voltooid en het werkt! Het stelt de gebruiker in staat om Blackjack te spelen tegen een enkele dealer, zonder dat er andere spelers aan tafel zitten. Ik vroeg me af, aangezien het mijn eerste multi-class programma is, of je me kon helpen het te optimaliseren en / of mij advies zou kunnen geven. Ik wil verzekeringen en splitsing implementeren, dus elk advies om de code voor te bereiden om deze functies uiteindelijk toe te voegen, zou erg nuttig zijn! Ten slotte is mijn belangrijkste methode vrij lang – ik vroeg me af of dit typisch is voor Java-programmas en, zo niet, hoe ik dat kan oplossen.

Kaart

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

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

Hoofd

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

Reacties

Antwoord

Klassenstructuur

  • Een Hand klasse kan nuttig zijn. Het kan de handwaarde berekenen en opslaan. Dit zou ook de duplicatie vermijden die u momenteel heeft (calcHandValue en Hit).
  • Uw Dealer class bevat veel code die ik daar niet zou plaatsen. Het bevat de dealer AI (wanneer slaat de dealer?), Winnen / verliezen conditiecontrole, afdrukken en tellen. Met een Hand -klasse, zou je er al een deel van scheiden. Ik zou ook alle afdrukken verwijderen (ze maken het hergebruiken van code moeilijk, en leiden tot een slechte codestructuur), en de AI-logica scheiden van zijn eigen klasse (dit zou het gemakkelijker maken om de regels te wijzigen, omdat ze allemaal in één place).
  • Je Blackjack class doet ook veel te veel. Het print, het leest input, het verwerkt input, het controleert de winnen / verliezende conditie (nogmaals, een duplicatie, zie volgende punt), enz. Het zijn zowel de speler als het spel die het beginsel van enkele verantwoordelijkheid schenden.
  • Probeer altijd een beter alternatief te bedenken wanneer je code kopieert / plakt. in dit geval bevatten je Dealer en je Blackjack klasse veel duplicatie. Vooral omdat ze allebei een blackjackspeler vertegenwoordigen (de dealer en de speler). Een generieke Player klasse kan nuttig zijn, waarvan Dealer en HumanPlayer uitbreiden .

Dus om samen te vatten: ik zou minimaal een Hand, Player en HumanPlayer klasse. Mogelijk ook een Input / Output interface en ConsoleInput / ConsoleOutput class (wat het gemakkelijk zou maken om een GUI toe te voegen). Er zijn meer klassen die u zou kunnen maken, maar dit zou een goed begin zijn.

Diversen

  • je hele shuffle functie kan worden vervangen door Collections.shuffle(deck);.
  • Waarom Dealer klasse hebben hand en aHand? Dit lijkt onnodig en verwarrend.
  • je hebt een aantal stijlproblemen (positie van accolade, inspringing, spaties, enz.). Het lijkt grotendeels intern consistent (dat is het belangrijkste deel), maar komt niet echt overeen met wat de meeste Java-programmeurs gewend zijn. De meeste IDEs die Java ondersteunen (bijv. Netbeans of Eclipse) formatteren de code standaard op een manier die de meeste Java-programmeurs herkennen .
  • namen van variabelen en methoden moeten met kleine letters beginnen, zodat ze niet worden verward met klassen.
  • if (cond) return true else return false kan worden geschreven als return cond.

Reacties

  • oké, ik zal een aantal van deze dingen proberen. Heel erg bedankt . Ik ‘ begrijp niet helemaal waarom ik een Input / Output-interface zou toevoegen en wat ik ervoor zou laten doen. Vind je het erg om wat meer over dat punt uit te leggen?
  • ook, in welke klasse zou je aanraden om het spel te spelen?
  • @Jared Input zou gewoon de actie verzamelen (wat een opsomming zou kunnen zijn; hit, split, enz.), en de output zou uitvoeren alles. De belangrijkste reden is dat het die dingen van de rest scheidt. Het maakt es uw code beter leesbaar, en vooral beter herbruikbaar. Je kunt je game spelen in een BlackJackGame -klasse, die de game-lus zou moeten behouden (die andere klassen zou oproepen om een hand te delen, input te krijgen, de eindvoorwaarde te controleren en resultaten toe te passen, waarna het deelt de volgende hand). Al de rest zou idealiter ergens anders moeten gebeuren.
  • als het niet ‘ t teveel moeite is, heb je dan een voorbeeldcode of links naar voorbeeldcode van een spel of iets dat je goed gestructureerd zou vinden?
  • Heel mooi gedaan, welverdiende overwinning! +1

Antwoord

Er valt nogal wat te verbeteren. Hier zijn een paar tips om aan de slag te gaan.

Overmatige reacties

Voegen deze opmerkingen iets nieuws toe dat nog niet “al duidelijk is?

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 

Dat doen ze niet. In feite voegen de meeste andere commentaren in de code ook geen waarde toe. De beste code heeft geen commentaar nodig. Bekijk alle commentaren in je code, als ze niet nodig zijn, verwijder ze dan, als ze nodig zijn, en probeer dan de code zo te veranderen dat je geen commentaar nodig hebt.

Card onveranderlijk maken

Is het logisch voor rank, suit en value om de levensduur van een Card -instantie te veranderen? Waarschijnlijk niet. Maak deze velden dus final. Er is een setValue -methode, die je ook niet nodig hebt.

Bekijk ook de andere klassen. Zorg dat alles final dat “niet hoeft te veranderen” of niet logisch is om ooit te veranderen. Deze oefening kan je helpen bij het opsporen van enkele ontwerpfouten.

Verwijs naar typen via interfaces

Je declareert verschillende lijsten zoals deze:

ArrayList<Card> hand; 

Gebruik in plaats daarvan het interfacetype:

List<Card> hand; 

Overweeg enum s

Deze variabelen zijn goede kandidaten voor 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"}; 

Zoals dit:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Als je de mogelijke kleuren wilt herhalen, kun je for (Suit suit : Suit.values()) { ... }

Magische getallen

Er zijn te veel magische getallen in de code. 17, 10, 11, 4, … Het zou beter zijn om deze in public static final variabelen met beschrijvende namen te plaatsen, om het doel van deze waarden te verduidelijken, plaats ze samen bovenaan van de code voor eenvoudigere controle en flexibiliteit om mee te spelen.

Formatteren

De code volgt niet de gebruikelijke opmaak die wordt gegenereerd door de automatische opmaakoptie van veelgebruikte IDEs zoals Eclipse en IntelliJ . Ik stel voor om het hele ding opnieuw te formatteren, zodat de code er vertrouwder en gemakkelijker leesbaar uitziet voor de meeste Java-codeerders. In Eclipse is de sneltoets Control-Shift-f

Opmerkingen

  • Als ik automatisch formaat gebruik, is dit dan de manier waarop programmas gewoonlijk worden opgemaakt?
  • Ja, dat ‘ is de gebruikelijke manier
  • Ik ‘ voeg de hele ” waarde ” attribuut van Card is niet nodig, alleen de getValue () functie is, die alleen de rang nodig heeft om te werken.

Antwoord

Retourneer de boolean direct

Het volgende:

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

zou moeten worden:

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

Hetzelfde geldt voor public static boolean hasBlackJack(int handValue) en public static boolean isHitorStand(String hitter) en public static boolean checkBust(int handvalue) voor de laatste moet u het afdrukken uit de functie verwijderen.

Gebruik reeds bestaande wielen

Je kunt het kaartspel in willekeurige volgorde afspelen door de ingebouwde -in:

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

Reacties

  • zal op deze manier mijn ArrayList-kaart in willekeurige volgorde afspelen, of een nieuwe lijst met de naam lijst die wordt geschud?
  • @Jared op zijn plaats ..

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *