Első kísérlet egy Java Blackjack játékra

Most fejeztem be az első többosztályos programomat, a Blackjack-ot, és ez működik! Lehetővé teszi a felhasználó számára, hogy Blackjack-et egyetlen kereskedővel játsszon, és nincs más játékos az asztalnál. Arra gondoltam, hogy ez az első több osztályos programom, tudna-e segíteni abban, hogy optimalizáljam és / vagy tanácsot adjon nekem. Biztosítást és felosztást szeretnék megvalósítani, ezért minden olyan tanács, amely segít előkészíteni a kódot a funkciók hozzáadásához, valóban hasznos lehet! Végül a fő módszerem elég hosszú – arra gondoltam, hogy ez jellemző-e a Java programokra, és ha nem, hogyan tudom ezt kijavítani.

Kártya

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

Fedélzet

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

Kereskedő

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

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

megjegyzések

Válasz

Osztálystruktúra

  • Hasznos lehet egy Hand osztály. Kiszámíthatja és tárolhatja a kézértéket. Ezzel elkerülhető lenne a jelenleg meglévő duplikáció (calcHandValue és Hit).
  • osztály sok olyan kódot tartalmaz, amelyet nem helyeznék el oda. Ez tartalmazza a kereskedő AI-jét (mikor üti meg a kereskedő?), Az állapotellenőrzés megnyerését / elvesztését, a nyomtatást és a számlálást. Egy Hand osztállyal már elkülönítené belőle. Eltávolítanám az összes nyomatot is (ezek megnehezítik a kód újrafelhasználását, és rossz kódstruktúrához vezetnek), és az AI logikát elválasztanám a saját osztályához (ez megkönnyítené a szabályok megváltoztatását, mert mind egyben vannak) hely).
  • A Blackjack osztályod is túl sokat tesz. Kinyomtatja, beolvassa a bemenetet, kezeli az inputot, ellenőrzi a nyerési / vesztési feltételeket (újra, másolat, lásd a következő pontot), stb. Ez a játékos és a játék is megsérti az egyetlen felelősség elvét.
  • Amikor másol / beilleszt kódot, próbáljon meg találni egy jobb alternatívát. ebben az esetben a Dealer és a Blackjack osztályod sok duplikációt tartalmaz. Főleg azért, mert mindketten egy blackjack játékost képviselnek (a kereskedő és a Hasznos lehet egy általános Player osztály, amelyből Dealer és HumanPlayer kiterjed .

Összefoglalva: hozzáadnék legalább egy Hand, Player és HumanPlayer osztály. Esetleg egy Input / Output felület és ConsoleInput / osztály (ami megkönnyítené a GUI hozzáadását). Több osztály is létrehozható, de ez jó kezdet lenne.

Egyéb

  • az egész shuffle függvény helyettesíthető a következővel: Collections.shuffle(deck);.
  • Miért Dealer osztály rendelkezik hand és aHand? Ez feleslegesnek és zavarónak tűnik.
  • van néhány stílusproblémád (göndör zárójel, mélyedés, szóköz stb. Helyzete). Leginkább belülről tűnik következetesnek (ez a fontos rész), de nem igazán egyezik meg azzal, amit a legtöbb Java programozó szokott. A Java-t támogató legtöbb IDE (pl. Netbeans vagy Eclipse) alapértelmezés szerint formázza a kódot úgy, ahogy a legtöbb Java programozó felismeri .
  • A változó és a metódus nevének kisbetűvel kell kezdődnie, így nem tévesztendő össze az osztályokkal.
  • if (cond) return true else return false return cond.

Megjegyzések

  • oké, kipróbálom ezeket a dolgokat. Nagyon köszönöm szépen . Nem értem, hogy ‘ miért értem hozzá az Input / Output felületet, és mit csinálnék vele. Nem szívesen elmagyarázna egy kicsit többet erről a kérdésről?
  • azt is, hogy melyik osztályban javasolnád, hogy futtassam a játékot?
  • A @Jared Input csak összegyűjtené a műveletet (ami lehet enum; hit, split, stb.), és a output kimenetet hozna létre A fő ok az, hogy elválasztja ezeket a dolgokat a többitől A kódod olvashatóbb és különösen újrafelhasználhatóbb. Futtathatja a játékát egy BlackJackGame osztályban, amelynek karbantartania kell a játék ciklust (amely más osztályokat hívna meg, hogy leosztjanak, bemenetet kapjanak, ellenőrizzék a végállapotot és alkalmazzák az eredményeket, majd ezt követően a következő leosztást adja). Az összes többi ideális esetben máshol történjen.
  • ha ez nem ‘ túl sok gond, van-e valamilyen példakód vagy link egy játék példakódjához, vagy bármi, amit jól strukturáltnak tartana?
  • Nagyon szépen sikerült, megérdemelt győzelem! +1

Válasz

Ezen elég sokat lehet javítani. Íme néhány tipp a kezdéshez.

Túl sok megjegyzés

Hozzátesznek ezek a megjegyzések valami újat, ami még nincs tisztázva?

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 

Nem teszik. Valójában a kódban szereplő többi megjegyzés sem ad értéket. A legjobb kódhoz nincs szükség megjegyzésekre. Ha nincs szükség rájuk, nézze át a kód összes megjegyzését, majd távolítsa el őket, ha szükséges, majd próbálja meg megváltoztatni a kódot úgy, hogy ne legyen szükség megjegyzésekre. >

Card megváltoztathatatlanná tétele

Van értelme a rank, és value megváltoztatni egy Card példány élettartamát? Valószínűleg nem. Tehát ezeket a mezőket final. Van egy setValue módszer, amelyre szintén nincs szüksége.

Tekintse át a többi osztályt is. Készítsen mindent final, aminek nem kell megváltoznia, vagy nincs értelme valaha változni. Ez a gyakorlat segíthet néhány tervezési hiba észlelésében.

Hivatkozás típusokra interfészenként

Több ilyen listát is deklarál:

ArrayList<Card> hand; 

Használja inkább az interfész típust:

List<Card> hand; 

Fontolja meg a enum s

Ezek a változók jó jelöltek a enum seknél:

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

Így:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Ha meg akarja ismételni a lehetséges öltönyöket, megteheti a for (Suit suit : Suit.values()) { ... }

varázsszámokat

Túl sok mágikus szám van a kódban. 17, 10, 11, 4, … Jobb lenne ezeket beilleszteni a leíró nevű public static final változókba, hogy tisztázzuk ezeknek az értékeknek a célját, ha a tetejük közelében vannak. A kód egyszerűbb kezelése és rugalmassága.

Formázás

A kód nem követi a közös formázást, amelyet a közös IDE-k automatikus formázási opciója generál, például az Eclipse és az IntelliJ. . Azt javaslom, hogy formázza át az egészet, hogy a kód ismertebbé és könnyebben olvashatóvá váljon a Java-kódolók többsége számára. Az Eclipse-ben a billentyűparancs a Control-Shift-f

megjegyzések

  • Ha automatikus formátumot használok, általában így formázzák a programokat?
  • Igen, hogy ‘ általános módszer
  • I ‘ d hozzáadom a teljes ” értéket ” attribútumára nincs szükség, csak a getValue () függvényre van szükség, amelynek működéséhez csak a rangra van szükség.

Válasz

A logikai érték közvetlen visszaadása

A következő:

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

a következő legyen:

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

Ugyanez vonatkozik a public static boolean hasBlackJack(int handValue) és public static boolean isHitorStand(String hitter) és public static boolean checkBust(int handvalue) utóbbiakhoz helyezze át a nyomtatást a függvényből.

Már meglévő kerekek használata

A beépítettet megkeverheti a beépített -in:

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

Megjegyzések

  • ilyen módon keverik az ArrayList paklimat, vagy megadják egy új listának nevezett lista, amelyet megkevernek?
  • @Jared a helyén ..

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük