Ensimmäinen yritys Java Blackjack -peliin

Suoritin juuri ensimmäisen moniluokkaohjelmani Blackjackin, ja se toimii! Sen avulla käyttäjä voi pelata Blackjackia yhtä jälleenmyyjää vastaan ilman muita pelaajia pöydässä. Mietin, koska se on ensimmäinen moniluokkainen ohjelmani, voisitko auttaa minua optimoimaan sen ja / tai antaa minulle neuvoja. Haluan toteuttaa vakuutuksen ja jakamisen, joten kaikki neuvot koodin valmistelussa näiden ominaisuuksien lisäämiseksi ovat todella hyödyllisiä! Lopuksi päämetodini on melko pitkä – mietin, onko tämä tyypillistä Java-ohjelmille, ja jos ei, kuinka voin korjata sen.

Kortti

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

Kansi

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

Jälleenmyyjä

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

Main

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

kommentit

vastaus

luokan rakenne

  • Hand -luokka voi olla hyödyllinen. Se voi laskea ja tallentaa käden arvon. Tämä välttäisi myös nykyisen päällekkäisyyden (calcHandValue ja Hit).
  • Dealer -luokka sisältää paljon koodia, jota en sijoittaisi sinne. Se sisältää jälleenmyyjän tekoälyn (milloin jälleenmyyjä lyö?), Kunnon tarkistuksen voittamisen / häviämisen, tulostamisen ja laskemisen. Hand -luokan avulla jo erottaisit osan siitä. Poistaisin myös kaikki tulosteet (ne vaikeuttavat koodin uudelleenkäyttöä ja johtavat huonoon koodirakenteeseen) ja erottavat tekoälylogiikan omaan luokkaansa (tämä helpottaisi sääntöjen muuttamista, koska ne ovat kaikki yhdessä
  • Blackjack -luokkasi tekee myös liikaa. Se tulostaa, lukee syötteen, käsittelee syötteen, tarkistaa voiton / häviön ehdon (jälleen, päällekkäisyys, katso seuraava kohta) jne. Pelaaja ja peli rikkovat yhden vastuun periaatetta.
  • Aina kun kopioit / liität koodia, yritä miettiä parempaa vaihtoehtoa. tässä tapauksessa Dealer ja Blackjack -luokkasi sisältävät paljon päällekkäisyyksiä. Lähinnä siksi, että ne molemmat edustavat blackjack-pelaajaa (jakajaa ja Yleinen Player -luokka voi olla hyödyllinen, josta Dealer ja HumanPlayer ulottuu .

Yhteenvetona: Lisään ainakin Hand, Player ja HumanPlayer -luokka. Mahdollisesti myös Input / Output -liittymä ja ConsoleInput / ConsoleOutput -luokka (mikä helpottaa graafisen käyttöliittymän lisäämistä). Voit luoda lisää luokkia, mutta tämä olisi hyvä alku.

Muu

  • koko shuffle -funktio voidaan korvata Collections.shuffle(deck);.
  • miksi Dealer -luokassa on hand ja aHand? Tämä tuntuu tarpeettomalta ja hämmentävältä.
  • sinulla on joitain tyyliongelmia (kiharaisen sulun sijainti, sisennys, välilyönnit jne.) Se näyttää enimmäkseen sisäisesti johdonmukaiselta (se on tärkeä osa), mutta ei todellakaan vastaa sitä, mihin useimmat Java-ohjelmoijat ovat tottuneet. Useimmat Java-tukea tukevat IDE: t (esim. Netbeans tai Eclipse) muotoilevat koodin oletuksena tavalla, jollainen Java-ohjelmoija tunnistaa .
  • muuttujien ja menetelmien nimien tulisi olla pieniä, joten niitä ei pidä sekoittaa luokkiin.
  • if (cond) return true else return false voidaan kirjoittaa nimellä return cond.

kommentit

  • ok, kokeilen joitain näistä asioista. Kiitos paljon . En ’ ymmärrä oikein, miksi lisääisin Input / Output-käyttöliittymän ja mitä tekisin sen tekevän. Haluatko selittää hieman enemmän tästä kohdasta?
  • myös, missä luokassa suosittelisit pelin suorittamista?
  • @Jared Input vain keräisi toiminnon (mikä voi olla enum; osuma, jako jne.), ja tulos tuottaisi Tärkein syy on, että se erottaa nuo asiat muusta es koodisi helpommin luettavissa, ja erityisesti uudelleenkäytettävissä. Voit ajaa peliäsi BlackJackGame luokassa, jonka tulisi ylläpitää pelisilmukkaa (joka kutsisi muita luokkia jakamaan kättä, saamaan panosta, tarkistamaan loppuehdot ja soveltamaan tuloksia, minkä jälkeen se käsittelee seuraavan käden). Kaikkien muiden pitäisi ihannetapauksessa tapahtua muualla.
  • jos se ei ole ’ liian paljon vaivaa, onko sinulla esimerkkikoodia tai linkkejä pelin esimerkkikoodiin tai mihin tahansa, mitä pidät hyvin jäsenneltyinä?
  • Erittäin hienosti tehty, ansaittu voitto! +1

Vastaa

Tässä on aika paljon parannettavaa. Tässä on muutama vinkki päästäksesi alkuun.

Liialliset kommentit

Lisävätkö nämä kommentit uutta, jota ei ole vielä tyhjennetty?

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 

Ne eivät t. Itse asiassa suurin osa koodin muista kommenteista ei myöskään lisää arvoa. Paras koodi ei tarvitse kommentteja. Katso kaikki koodissasi olevat kommentit, jos niitä ei tarvita, poista ne, jos niitä tarvitaan, yritä sitten vaihtaa koodi tavalla, joka ei tarvitse kommentteja.

Card muuttumattomaksi muuttaminen

Onko järkevää käyttää rank, suit ja value muuttaaksesi Card -esiintymän elinaikaa? Luultavasti ei. Tee siis näistä kentistä final. On olemassa setValue -menetelmä, jota et myöskään tarvitse.

Tarkista myös muut luokat. Tee kaikki final, jota ei tarvitse muuttaa tai jolla ei ole järkeä koskaan muuttua. Tämä käytäntö voi auttaa sinua havaitsemaan joitain suunnitteluvirheitä.

Viittaus tyyppeihin käyttöliittymittäin

Ilmoitat useita luetteloita tällä tavoin:

ArrayList<Card> hand; 

Käytä sen sijaan liitäntätyyppiä:

List<Card> hand; 

Harkitse enum s

Nämä muuttujat ovat hyviä ehdokkaita 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"}; 

Näin:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Jos haluat toistaa mahdolliset puvut, voit tehdä for (Suit suit : Suit.values()) { ... }

taianumerot

Koodissa on liian monta maagista numeroa. 17, 10, 11, 4, … Olisi parempi laittaa nämä public static final -muuttujiin kuvailevilla nimillä näiden arvojen tarkoituksen selventämiseksi, pitämällä ne yhdessä yläosan lähellä koodin helpompaa hallintaa ja pelaamista varten.

Muotoilu

Koodi ei noudata yleisten muotoilutoimintojen luomaa yleisten IDE-tiedostojen, kuten Eclipse ja IntelliJ, automaattista muotoilua. . Ehdotan muotoilla koko asia uudelleen, jotta koodi näyttää tutummalta ja helpommin luettavalta useimmille Java-koodereille. Eclipse-näppäimistön pikanäppäin on Control-Shift-f

Kommentit

  • Jos käytän automaattista muotoilua, onko ohjelmat yleensä muotoiltu tällä tavalla?
  • Kyllä, että ’ s yleinen tapa
  • I ’ d lisätään koko ” arvo ” -määritettä ei tarvita, vain funktio getValue (), joka tarvitsee vain arvon toimiakseen.

Vastaa

Palauta looginen arvo suoraan

Seuraava:

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

pitäisi olla:

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

Sama koskee public static boolean hasBlackJack(int handValue) ja public static boolean isHitorStand(String hitter) ja public static boolean checkBust(int handvalue) jälkimmäisen kohdalla sinun tulisi siirtää tulostus pois toiminnosta.

Käytä jo olemassa olevia pyöriä

Voit sekoittaa kannen käyttämällä sisäänrakennettua -in:

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

kommentit

  • sekoittaa tällä tavalla sekoittaa ArrayList-kannet tai antaa minulle uusi luettelo nimeltä luettelo, joka on sekoitettu?
  • @Jared paikallaan ..

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *