Première tentative de jeu de Blackjack Java

Je viens de terminer mon premier programme multi-classes, le Blackjack, et ça marche! Il permet à lutilisateur de jouer au Blackjack contre un seul croupier, sans aucun autre joueur à la table. Je me demandais, vu quil sagit de mon premier programme multi-classes, si vous pouviez maider à loptimiser et / ou me donner des conseils. Je veux mettre en œuvre une assurance et un fractionnement, donc tout conseil pour aider à préparer le code pour éventuellement ajouter ces fonctionnalités serait vraiment utile! Enfin, ma méthode principale est assez longue – je me demandais si cétait typique des programmes Java et, sinon, comment je pouvais y remédier.

Carte

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

Concessionnaire

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

Principal

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

Commentaires

Réponse

Structure de classe

  • Une classe Hand peut être utile. Il peut calculer et stocker la valeur de la main. Cela éviterait également la duplication que vous avez actuellement (calcHandValue et Hit).
  • Votre contient beaucoup de code que je ne placerais pas là. Il contient lIA du croupier (quand le croupier frappe-t-il?), La vérification des conditions gagnantes / perdantes, limpression et le comptage. Avec une classe Hand, vous en sépareriez déjà une partie. Je supprimerais également toutes les impressions (elles rendraient la réutilisation du code difficile et conduiraient à une mauvaise structure de code), et séparerais la logique de lIA en sa propre classe (cela faciliterait la modification des règles, car elles sont toutes en un place).
  • Votre classe Blackjack en fait aussi beaucoup trop. Elle imprime, elle lit les entrées, elle gère les entrées, elle vérifie les conditions gagnantes / perdantes (encore une fois, une duplication, voir point suivant), etc. Cest le joueur ainsi que le jeu qui viole le principe de responsabilité unique.
  • Chaque fois que vous copiez / collez du code, essayez de penser à une meilleure alternative. dans ce cas, votre classe Dealer et votre classe Blackjack contiennent beaucoup de duplication. Principalement parce quils représentent tous deux un joueur de blackjack (le croupier et le player). Une classe Player générique peut être utile, à partir de laquelle Dealer et HumanPlayer sétendent .

Donc pour résumer: jajouterais au minimum un Hand, Player et HumanPlayer. Éventuellement également une interface Input / Output et ConsoleInput / ConsoleOutput class (ce qui faciliterait lajout dune interface graphique). Vous pouvez créer dautres classes, mais ce serait un bon début.

Misc

  • toute votre fonction shuffle peut être remplacée par Collections.shuffle(deck);.
  • Pourquoi votre Dealer la classe a hand et aHand? Cela semble inutile et déroutant.
  • vous avez des problèmes de style (position des accolades, indentation, espaces, etc.). Il semble généralement cohérent en interne (cest la partie importante), mais ne correspond pas vraiment à ce à quoi la plupart des programmeurs Java sont habitués. La plupart des IDE qui prennent en charge Java (par exemple Netbeans ou Eclipse) formate le code par défaut comme la plupart des programmeurs Java le reconnaissent. .
  • les noms de variables et de méthodes doivent commencer en minuscules, pour ne pas être confondus avec les classes.
  • if (cond) return true else return false peut être écrit comme return cond.

Commentaires

  • daccord, je vais essayer certaines de ces choses. Merci beaucoup . Je ne ‘ pas très bien comprendre pourquoi jajouterais une interface dentrée / sortie et ce que je lui ferais faire. Cela vous dérange-t-il dexpliquer un peu plus sur ce point?
  • également, dans quelle classe recommanderiez-vous que je lance le jeu?
  • @Jared Input rassemblerait simplement laction (qui pourrait être une énumération; hit, split, etc.), et la sortie produirait tout. La raison principale est que cela sépare ces choses du reste. es votre code plus lisible, et surtout plus réutilisable. Vous pouvez exécuter votre jeu dans une classe BlackJackGame, qui devrait maintenir la boucle de jeu (qui appellerait dautres classes pour donner une main, obtenir une entrée, vérifier la condition de fin et appliquer les résultats, après quoi il traite la main suivante). Tout le reste devrait idéalement se produire ailleurs.
  • si ce nest ‘ t trop de problèmes, avez-vous un exemple de code ou des liens vers un exemple de code dun jeu ou tout ce que vous considérez bien structuré?
  • Très bien fait, victoire bien méritée! +1

Réponse

Il ya « beaucoup à améliorer à ce sujet. Voici quelques conseils pour commencer.

Commentaires excessifs

Ces commentaires ajoutent-ils quelque chose de nouveau qui nest pas déjà clair?

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 

Ils ne « t. En fait, la plupart des autres commentaires dans le code najoutent pas non plus de valeur. Le meilleur code na pas besoin de commentaires. Regardez tous les commentaires de votre code, sils ne sont pas nécessaires, puis supprimez-les, sils sont nécessaires, puis essayez de changer le code de manière à ne pas avoir besoin de commentaires.

Rendre Card immuable

Cela aura-t-il un sens pour rank, suit et value pour changer la durée de vie dune instance Card? Probablement pas. Donc, indiquez ces champs final. Il existe une méthode setValue, dont vous navez pas besoin non plus.

Examinez également les autres classes. Rendez tout final qui na pas besoin de changer ou qui na pas de sens pour jamais changer. Cette pratique peut vous aider à repérer certains bogues de conception.

Faire référence aux types par interfaces

Vous déclarez plusieurs listes comme celle-ci:

ArrayList<Card> hand; 

Utilisez plutôt le type dinterface:

List<Card> hand; 

Considérez enum s

Ces variables sont de bons candidats pour les 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"}; 

Comme ceci:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Si vous voulez parcourir les combinaisons possibles, vous pouvez faire for (Suit suit : Suit.values()) { ... }

Numéros magiques

Il y a trop de nombres magiques dans le code. 17, 10, 11, 4, … Il serait préférable de les mettre dans des variables public static final avec des noms descriptifs, pour clarifier le but de ces valeurs, regroupez-les vers le haut du code pour un contrôle plus facile et une flexibilité de jeu.

Formatage

Le code ne suit pas le formatage commun généré par loption de formatage automatique des IDE courants comme Eclipse et IntelliJ . Je suggère de reformater le tout, pour rendre le code plus familier et plus facile à lire pour la majorité des codeurs Java. Dans Eclipse, le raccourci clavier est Control-Shift-f

Commentaires

  • Si jutilise le format automatique, est-ce ainsi que les programmes sont généralement formatés?
  • Oui, cest ‘ méthode courante
  • Je ‘ d ajouter la  » valeur  » de Card nest pas nécessaire, seule la fonction getValue () lest, qui na besoin que du rang pour fonctionner.

Réponse

Renvoie le booléen directement

Ce qui suit:

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

devrait devenir:

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

Il en va de même pour public static boolean hasBlackJack(int handValue) et public static boolean isHitorStand(String hitter) et public static boolean checkBust(int handvalue) pour ce dernier, vous devez déplacer limpression hors de la fonction.

Utiliser des roues déjà existantes

Vous pouvez mélanger le jeu en utilisant le -in:

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

Commentaires

  • va mélanger de cette façon mon deck ArrayList, ou me donner une nouvelle liste appelée liste qui est mélangée?
  • @Jared en place ..

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *