Primeira tentativa de um jogo Java Blackjack

Acabei de concluir meu primeiro programa com várias classes, Blackjack, e funciona! Ele permite ao usuário jogar Blackjack contra um único dealer, sem outros jogadores na mesa. Eu queria saber, visto que é meu primeiro programa de várias classes, se você poderia me ajudar a otimizá-lo e / ou me dar algum conselho. Eu quero implementar seguro e divisão, então qualquer conselho para ajudar a preparar o código para eventualmente adicionar esses recursos seria realmente útil! Finalmente, meu método principal é muito longo – eu queria saber se isso é típico de programas Java e, se não, como posso consertar isso.

Cartão

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

Revendedor

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

Comentários

Resposta

Estrutura da classe

  • Uma classe Hand pode ser útil. Ele pode calcular e armazenar o valor da mão. Isso também evitaria a duplicação que você tem atualmente (calcHandValue e Hit).
  • Seu Dealer classe contém muitos códigos que eu não colocaria lá. Ele contém o dealer AI (quando o dealer bate?), Verificação de condição de vitória / derrota, impressão e contagem. Com uma Hand classe, você já separaria parte dela. Eu também removeria todas as impressões (elas tornam a reutilização do código difícil e levam a uma estrutura de código ruim), e separar a lógica de IA para sua própria classe (isso tornaria mais fácil mudar as regras, porque elas estão todas em uma local).
  • Sua classe Blackjack também faz muito. Ela imprime, lê a entrada, lida com a entrada, verifica a condição de ganhar / perder (de novo, uma duplicação, veja o próximo ponto), etc. É o jogador, assim como o jogo, que viola o princípio da responsabilidade única.
  • Sempre que você copiar / colar código, tente pensar em uma alternativa melhor. neste caso, sua Dealer e sua Blackjack classe contêm muitas duplicações. Principalmente porque ambos representam um jogador de blackjack (o dealer e o player). Uma classe Player genérica pode ser útil, da qual Dealer e HumanPlayer estendem .

Então, para resumir: eu adicionaria no mínimo um Hand, Player e HumanPlayer classe. Possivelmente também uma Input / Output interface e ConsoleInput / ConsoleOutput classe (o que tornaria mais fácil adicionar uma GUI). Existem mais classes que você pode criar, mas este seria um bom começo.

Misc

  • toda a sua função shuffle pode ser substituída por Collections.shuffle(deck);.
  • Por que sua Dealer classe tem hand e aHand? Isso parece desnecessário e confuso.
  • você tem alguns problemas de estilo (posição das chaves, recuo, espaços, etc). Parece mais consistente internamente (essa é a parte importante), mas realmente não corresponde ao que a maioria dos programadores Java está acostumada. A maioria dos IDEs que suportam Java (por exemplo, Netbeans ou Eclipse) formata o código por padrão de uma maneira que a maioria dos programadores Java reconhece .
  • nomes de variáveis e métodos devem começar em minúsculas, para que não sejam confundidos com classes.
  • if (cond) return true else return false pode ser escrito como return cond.

Comentários

  • ok, vou tentar algumas dessas coisas. Muito obrigado . Não ‘ não entendo muito bem por que adicionaria uma interface de entrada / saída e o que faria com que ela fizesse. Você se importa em explicar um pouco mais sobre esse ponto?
  • Além disso, em qual classe você recomendaria para executar o jogo?
  • @Jared Input iria apenas reunir a ação (que poderia ser um enum; hit, split, etc), e a saída seria a saída tudo. O principal motivo é que separa essas coisas do resto. es seu código mais legível e especialmente mais reutilizável. Você pode executar seu jogo em uma classe BlackJackGame, que deve manter o loop do jogo (que chamaria outras classes para dar uma mão, obter dados, verificar a condição final e aplicar os resultados, após o que trata a próxima mão). Todo o resto deve acontecer em outro lugar.
  • se não ‘ t muito problema, você tem algum código de exemplo ou links para código de exemplo de um jogo ou algo que consideraria bem estruturado?
  • Muito bem feito, vitória bem merecida! +1

Resposta

Há muito o que melhorar. Aqui estão algumas dicas para começar.

Comentários excessivos

Esses comentários adicionam algo novo que ainda não está claro?

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 

Eles não. Na verdade, a maioria dos outros comentários no código também não agregam valor. O melhor código não precisa de comentários. Examine todos os comentários em seu código, se não forem necessários, remova-os, se forem necessários, e tente alterar o código de forma que não precise de comentários.

Tornando Card imutável

Isso fará sentido para rank, suit e value para mudar no tempo de vida de uma Card instância? Provavelmente não. Portanto, crie esses campos final. Existe um método setValue, que você também não precisa.

Revise as outras classes também. Faça tudo final que não precisa mudar ou que não faz sentido mudar. Esta prática pode ajudá-lo a identificar alguns bugs de design.

Consulte os tipos por interfaces

Você declara várias listas como esta:

ArrayList<Card> hand; 

Use o tipo de interface:

List<Card> hand; 

Considere enum s

Essas variáveis são boas candidatas para 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"}; 

Assim:

enum Suit { Clubs, Diamonds, Hearts, Spades } 

Se quiser iterar os naipes possíveis, você pode fazer for (Suit suit : Suit.values()) { ... }

Números mágicos

Existem muitos números mágicos no código. 17, 10, 11, 4, … Seria melhor colocá-los em public static final variáveis com nomes descritivos, para esclarecer a finalidade desses valores, junte-os perto do topo do código para um controle mais fácil e flexibilidade para brincar.

Formatação

O código não segue a formatação comum gerada pela opção de formatação automática de IDEs comuns como Eclipse e IntelliJ . Eu sugiro reformatar tudo, para fazer o código parecer mais familiar e fácil de ler para a maioria dos programadores Java. No Eclipse, o atalho de teclado é Control-Shift-f

Comentários

  • Se eu usar o formato automático, é assim que os programas são normalmente formatados?
  • Sim, ‘ é o maneira comum
  • I ‘ d adicionar todo o ” valor ” de Card não é necessário, apenas a função getValue (), que só precisa da classificação para funcionar.

Resposta

Retorne o booleano diretamente

O seguinte:

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

deve se tornar:

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

O mesmo vale para public static boolean hasBlackJack(int handValue) e public static boolean isHitorStand(String hitter) e public static boolean checkBust(int handvalue) para o último, você deve retirar a impressão da função.

Use rodas já existentes

Você pode embaralhar o baralho usando o -in:

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

Comentários

  • embaralhar desta forma embaralhará meu baralho ArrayList ou me dará uma nova lista chamada list que é embaralhada?
  • @Jared in place ..

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *