Java Blackjack 게임에 대한 첫 번째 시도

방금 첫 번째 다중 클래스 프로그램 인 Blackjack을 완료했는데 작동합니다! 사용자는 테이블에 다른 플레이어없이 단일 딜러를 상대로 블랙 잭을 플레이 할 수 있습니다. 나는 그것이 나의 첫 번째 다중 클래스 프로그램 인 것을보고, 내가 그것을 최적화하도록 도와 줄 수 있고 / 또는 조언을 줄 수 있는지 궁금했다. 보험 및 분할을 구현하고 싶으므로 결국 이러한 기능을 추가하기 위해 코드를 준비하는 데 도움이되는 조언이 있으면 정말 도움이 될 것입니다! 마지막으로, 저의 주요 방법은 꽤 깁니다. 이것이 일반적인 Java 프로그램인지, 그렇지 않다면 어떻게 고칠 수 있는지 궁금합니다.

카드

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

갑판

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

딜러

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

댓글

답변

클래스 구조

  • Hand 클래스가 유용 할 수 있습니다. 손 값을 계산하고 저장할 수 있습니다. 이렇게하면 현재 가지고있는 중복 (calcHandValueHit)도 피할 수 있습니다.
  • Dealer 클래스에는 여기에 배치하지 않을 많은 코드가 포함되어 있습니다. 여기에는 딜러 AI (딜러가 언제 히트 했습니까?), 승패 상태 확인, 인쇄 및 계산이 포함됩니다. Hand 클래스를 사용하면 이미 일부를 분리했을 것입니다. 또한 모든 인쇄물을 제거하고 (코드 재사용을 어렵게하고 코드 구조를 잘못하게 만듭니다) AI 로직을 자체 클래스로 분리합니다 (이는 모두 하나에 있기 때문에 규칙을 변경하기가 더 쉽습니다.
  • Blackjack 클래스도 너무 많은 작업을 수행합니다. 인쇄하고, 입력을 읽고, 입력을 처리하고, 승패 상태를 확인합니다 (다시, 중복, 다음 요점 참조) 등. 단일 책임 원칙을 위반하는 것은 게임뿐만 아니라 플레이어이기도합니다.
  • 코드를 복사 / 붙여 넣기 할 때마다 더 나은 대안을 생각해보십시오. 이 경우 DealerBlackjack 클래스에는 중복이 많이 포함되어 있습니다. 주로 둘 다 블랙 잭 플레이어 (딜러와 플레이어). 일반 Player 클래스가 도움이 될 수 있습니다. 여기서 DealerHumanPlayer 확장 .

요약하자면 최소한 Hand, PlayerHumanPlayer 클래스. Input / Output 인터페이스 및 ConsoleInput / ConsoleOutput 클래스 (GUI를 쉽게 추가 할 수 있음). 더 많은 클래스를 만들 수 있지만 시작하는 것이 좋습니다.

기타

  • 전체 shuffle 함수는 Collections.shuffle(deck);로 대체 될 수 있습니다.
  • Dealer 클래스에는 handaHand가 있습니까? 불필요하고 혼란스러워 보입니다.
  • 스타일 문제 (중괄호 위치, 들여 쓰기, 공백 등)가 있습니다. 대부분 내부적으로 일관성이있는 것처럼 보이지만 (중요한 부분) 대부분의 Java 프로그래머가 사용하는 것과 실제로는 일치하지 않습니다. Java를 지원하는 대부분의 IDE (예 : Netbeans 또는 Eclipse)는 대부분의 Java 프로그래머가 인식하는 방식으로 기본 코드 형식을 지정합니다. .
  • 변수 및 메소드 이름은 소문자로 시작해야 클래스와 혼동되지 않습니다.
  • if (cond) return true else return false

    .

댓글

  • 알겠습니다. 몇 가지 시도해 보겠습니다. 감사합니다. . ‘ 입력 / 출력 인터페이스를 추가해야하는 이유와이를 수행 할 작업을 잘 모르겠습니다. 그 점에 대해 조금 더 설명해 주시겠습니까?
  • 또한 어떤 클래스에서 게임을 실행하는 것이 좋습니까?
  • @Jared Input은 액션 (열거 형, 적중, 분할 등)을 수집하고 출력은 출력합니다. 주된 이유는 이러한 것들을 나머지와 분리하기 때문입니다. 코드를 더 읽기 쉽고 특히 재사용이 가능합니다. 게임 루프를 유지해야하는 BlackJackGame 클래스에서 게임을 실행할 수 있습니다 (핸드를 처리하고 입력을 받고 종료 조건을 확인하고 결과를 적용하기 위해 다른 클래스를 호출합니다. 다음 핸드를 다룹니다). 나머지는 이상적으로 다른 곳에서 발생해야합니다.
  • ‘ 그다지 문제가되지 않는다면, 예제 코드 나 게임의 예제 코드에 대한 링크 또는 잘 구성되어 있다고 생각하는 것이 있습니까?
  • 아주 잘 했어, 당연한 승리! +1

답변

개선해야 할 사항이 상당히 많습니다. 다음은 몇 가지 도움말입니다. 시작하려면.

과도한 댓글

이 댓글에 “아직 명확하지 않은 새로운 내용이 추가 되나요?

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 

그렇지 않습니다. 실제로 코드에있는 대부분의 다른 주석도 가치를 추가하지 않습니다. 최고의 코드는 주석이 필요하지 않습니다. 필요하지 않은 경우 코드의 모든 주석을 살펴보고 필요하면 제거하고 주석이 필요없는 방식으로 코드를 변경하십시오.

Card 불변으로 만들기

rank, 및 value를 사용하여 Card 인스턴스의 수명을 변경 하시겠습니까? 아마도 그렇지 않을 것입니다. 따라서이 필드를 final. 둘 다 필요하지 않은 setValue 메서드가 있습니다.

다른 클래스도 검토하세요. 변경할 필요가 없거나 변경하는 것이 의미가없는 모든 final를 만드세요. 이 방법은 일부 디자인 버그를 발견하는 데 도움이 될 수 있습니다.

인터페이스 별 유형 참조

다음과 같이 여러 목록을 선언합니다.

ArrayList<Card> hand; 

대신 인터페이스 유형 사용 :

List<Card> hand; 

enum를 고려

다음 변수는 enum에 적합한 후보입니다.

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

예 :

enum Suit { Clubs, Diamonds, Hearts, Spades } 

가능한 한 벌을 반복하려면 for (Suit suit : Suit.values()) { ... }

매직 넘버

코드에 매직 넘버가 너무 많습니다. 17, 10, 11, 4, … 이러한 값의 목적을 명확히하기 위해 설명이 포함 된 public static final 변수에 이러한 값을 넣고 상단 근처에 함께 두는 것이 좋습니다. 더 쉽게 제어하고 유연하게 사용할 수있는 코드입니다.

포맷

코드는 Eclipse 및 IntelliJ와 같은 일반적인 IDE의 자동 포맷 옵션에 의해 생성 된 일반적인 포맷을 따르지 않습니다. . 대부분의 Java 코더가 코드를 더 친숙하고 쉽게 읽을 수 있도록 전체 형식을 다시 지정하는 것이 좋습니다. Eclipse에서 키보드 단축키는 Control-Shift-f

Comments

입니다.

  • 자동 형식을 사용하는 경우 일반적으로 프로그램 형식이이 방식인가요?
  • 예, ‘ 일반적인 방법
  • ‘ 전체 ” 값 ” 속성은 필요하지 않습니다. getValue () 함수 만 있으면 랭크 만 작동하면됩니다.

답변

부울을 직접 반환

다음 :

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

다음이되어야합니다.

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

public static boolean hasBlackJack(int handValue)public static boolean isHitorStand(String hitter)public static boolean checkBust(int handvalue) 후자의 경우 인쇄를 함수 밖으로 이동해야합니다.

이미 기존 바퀴 사용

내장 된 바퀴를 사용하여 데크를 섞을 수 있습니다. -in :

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

댓글

  • 이 방식으로 내 ArrayList 덱을 섞거나 나에게 줄 것입니다. 섞인 목록이라는 새 목록이 있습니까?
  • @Jared 제자리에 ..

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다