Pierwsza próba gry w blackjacka w Javie

Właśnie ukończyłem mój pierwszy wieloklasowy program Blackjack i działa! Pozwala użytkownikowi grać w blackjacka przeciwko jednemu krupierowi, bez innych graczy przy stole. Zastanawiałem się, widząc, że jest to mój pierwszy program wieloklasowy, czy mógłbyś mi pomóc zoptymalizować go i / lub udzielić mi jakiejkolwiek porady. Chcę wdrożyć ubezpieczenie i podział, więc każda rada, która pomoże przygotować kod do ewentualnego dodania tych funkcji, byłaby naprawdę pomocna! Wreszcie moja główna metoda jest dość długa – zastanawiałem się, czy jest to typowe dla programów Java, a jeśli nie, jak mogę to naprawić.

Karta

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

Talia

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

Sprzedawca

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

Główna

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

Komentarze

Odpowiedź

Struktura klas

  • Klasa Hand może być przydatna. Może obliczyć i przechowywać wartość ręki. Pozwoliłoby to również uniknąć duplikowania, które masz obecnie (calcHandValue i Hit).
  • Twój zawiera dużo kodu, którego bym tam nie umieszczał. Zawiera AI krupiera (kiedy krupier trafi?), Sprawdzenie stanu wygranej / przegranej, drukowanie i liczenie. W przypadku klasy Hand można już oddzielić część z nich. Chciałbym również usunąć wszystkie wydruki (utrudniają ponowne użycie kodu i prowadzą do złej struktury kodu) i oddzielić logikę AI do własnej klasy (to ułatwiłoby zmianę reguł, ponieważ wszystkie są w jednym place).
  • Twoja klasa Blackjack też robi o wiele za dużo. Drukuje, czyta dane wejściowe, obsługuje dane wejściowe, sprawdza warunki wygranej / przegranej (znowu powielanie, patrz następny punkt), itd. To gracz oraz gra naruszają zasadę pojedynczej odpowiedzialności.
  • Ilekroć kopiujesz / wklejasz kod, spróbuj wymyślić lepszą alternatywę. W tym przypadku Twoja Dealer i Twoja klasa Blackjack zawierają dużo duplikatów. Głównie dlatego, że obie reprezentują gracza w blackjacka (krupiera i player). Przydatna może być ogólna klasa Player, z której Dealer i HumanPlayer rozszerzają .

Podsumowując: dodałbym co najmniej Hand, Player i HumanPlayer class. Prawdopodobnie także interfejs Input / Output i ConsoleInput / ConsoleOutput (co ułatwiłoby dodanie GUI). Jest więcej klas, które możesz utworzyć, ale to byłby dobry początek.

Różne

  • całą funkcję shuffle można zastąpić Collections.shuffle(deck);.
  • Dlaczego Twoja Dealer ma klasę hand i aHand? Wydaje się to niepotrzebne i zagmatwane.
  • masz pewne problemy ze stylem (pozycja nawiasu klamrowego, wcięcia, spacje itp.). Wydaje się w większości wewnętrznie spójne (to ważna część), ale nie pasuje do tego, do czego przyzwyczaiła się większość programistów Javy. Większość IDE obsługujących Javę (np. Netbeans lub Eclipse) formatuje kod domyślnie w sposób, który większość programistów Javy rozpoznaje .
  • nazwy zmiennych i metod powinny zaczynać się małymi literami, aby nie były mylone z klasami.
  • if (cond) return true else return false można zapisać jako return cond.

Komentarze

  • ok, spróbuję niektórych z tych rzeczy. Dziękuję bardzo . Nie ' nie całkiem rozumiem, dlaczego miałbym dodać interfejs wejścia / wyjścia i co miałbym zrobić. Czy możesz wyjaśnić trochę więcej na ten temat?
  • również, w której klasie poleciłbyś uruchomić grę?
  • @Jared Wejście po prostu zebrałoby akcję (która może być wyliczeniem, trafieniem, podziałem itp.), a wyjście wyświetli wszystko. Głównym powodem jest to, że oddziela te rzeczy od reszty Twój kod jest bardziej czytelny, a zwłaszcza łatwiejszy do ponownego wykorzystania. Możesz uruchomić grę w klasie BlackJackGame, która powinna utrzymywać pętlę gry (która wywoływałaby inne klasy w celu rozdania rozdania, uzyskania danych wejściowych, sprawdzenia warunku końcowego i zastosowania wyników, po czym w następnym rozdaniu). Cała reszta powinna mieć miejsce gdzie indziej.
  • jeśli to nie jest ' to zbyt duży problem, czy masz przykładowy kod lub jakieś linki do przykładowego kodu gry lub czegokolwiek, co uważasz za dobrze zorganizowane?
  • Bardzo dobrze zrobione, zasłużone zwycięstwo! +1

Odpowiedź

Jest jeszcze wiele rzeczy, które trzeba poprawić. Oto kilka wskazówek aby rozpocząć.

Nadmierne komentarze

Czy te komentarze dodają coś nowego, czego jeszcze nie jest jasne?

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 

Nie „t. W rzeczywistości większość innych komentarzy w kodzie również nie dodaje wartości. Najlepszy kod nie potrzebuje komentarzy. Przejrzyj wszystkie komentarze w swoim kodzie, jeśli nie są potrzebne, a następnie usuń je, jeśli są potrzebne, a następnie spróbuj zmienić kod tak, aby nie potrzebować komentarzy.

Uczynienie Card niezmienności

Czy będzie to miało sens w przypadku rank, suit i value, aby zmienić okres istnienia instancji Card? Prawdopodobnie nie. Więc utwórz te pola final. Istnieje metoda setValue, której też nie potrzebujesz.

Przejrzyj także inne klasy. Uczyń wszystko final, co nie musi się zmieniać lub nie ma sensu, aby kiedykolwiek zmieniać. Ta praktyka może pomóc ci dostrzec pewne błędy projektowe.

Odwołaj się do typów według interfejsów

Deklarujesz kilka list w ten sposób:

ArrayList<Card> hand; 

Zamiast tego użyj typu interfejsu:

List<Card> hand; 

Rozważ enum s

Te zmienne są dobrymi kandydatami do 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"}; 

W ten sposób:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Jeśli chcesz iterować po możliwych kolorach, możesz wykonać for (Suit suit : Suit.values()) { ... }

Magiczne liczby

W kodzie jest zbyt wiele magicznych liczb. 17, 10, 11, 4, … Lepiej byłoby umieścić je w public static final zmiennych z opisowymi nazwami, aby wyjaśnić cel tych wartości, umieszczając je razem u góry kodu dla łatwiejszej kontroli i elastyczności do zabawy.

Formatowanie

Kod nie jest zgodny ze standardowym formatowaniem generowanym przez opcję automatycznego formatowania popularnych IDE, takich jak Eclipse i IntelliJ . Proponuję przeformatować całość, aby kod wyglądał bardziej znajomo i łatwiejszy do odczytania dla większości programistów Java. W Eclipse skrót klawiaturowy to Control-Shift-f

Komentarze

  • Jeśli używam formatu automatycznego, czy w ten sposób programy są zwykle formatowane?
  • Tak, ' s powszechny sposób
  • I ' d dodaj całą ” wartość ” atrybut Card nie jest potrzebny, wystarczy funkcja getValue (), która potrzebuje tylko rangi do działania.

Odpowiedź

Zwróć bezpośrednio wartość logiczną

Następujące:

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

powinno wyglądać następująco:

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

To samo dotyczy public static boolean hasBlackJack(int handValue) i public static boolean isHitorStand(String hitter) i public static boolean checkBust(int handvalue) w przypadku tego ostatniego należy przenieść drukowanie z funkcji.

Użyj już istniejących kół

Możesz tasować talię, używając wbudowanego -in:

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

Komentarze

  • tasuje w ten sposób moją talię ArrayList lub daje mi nowa lista o nazwie lista, która jest potasowana?
  • @Jared na miejscu ..

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *