Postscript: @ k73i55no5 commented on a better refactoring proposal. Thank you very much. See comments for details. I'm just refactoring the class member structure (structure). We have not started refactoring the processing code (interior, implementation). (Added up to here)
I saw the source code of "Make Blackjack with Java" posted by @ yuta-yoshinaga. The encapsulation was destroyed by a lot of setters and getters, and some classes weren't working, so I wrote a bit of a bitter comment. It's just a comment, so I refactored it in my own way. There are still some points to review, but I hope you find it helpful.
Add a sequence diagram.
@startuml
participant "BlackJack" as blackjack
@enduml
BlackJack.java
public class BlackJack {
private final Player player;
private final Dealer dealer;
public BlackJack() {
this(new CUIPlayer(), new Dealer());
}
public BlackJack(Player player, Dealer dealer) {
this.player = player;
this.dealer = dealer;
}
public void play() {
player.reset();
dealer.reset();
for (int i = 0; i < 2; i++) {
dealer.dealCard(player);
dealer.dealCard(dealer);
}
dealer.show();
if (player.play(dealer)) {
dealer.play(dealer);
showJudge();
}
}
public void showJudge() {
dealer.show();
player.show();
Player winner = judgeWinner();
System.out.println("----------");
if (winner == player) {
System.out.println("You are the winner.");
} else if (winner == dealer) {
System.out.println("It is your loss.");
} else {
System.out.println("It is a draw.");
}
}
public Player judgeWinner() {
if (player.isBust()) {
return dealer;
} else if (dealer.isBust()) {
return player;
} else if (player.isBlackJack() && !dealer.isBlackJack()) {
return player;
} else if (dealer.isBlackJack() && !player.isBlackJack()) {
return dealer;
}
int diff = player.calcScore() - dealer.calcScore();
if (diff > 0) {
return player;
} else if (diff < 0) {
return dealer;
} else {
return null;
}
}
public static void main(String[] args) {
BlackJack blackjack = new BlackJack();
while (true) {
blackjack.play();
blackjack.player.play(null);
}
}
}
Player.java
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
abstract public class Player {
public final String name;
protected final List<Card> cards = new ArrayList<Card>();
protected boolean stand = false;
public Player() {
this("Player");
}
public Player(String name) {
this.name = name;
}
public void reset() {
cards.clear();
stand = false;
}
public void holdCard(Card card) {
cards.add(card);
}
abstract boolean play(CardDealer dealer);
public int calcScore() {
int score = 0;
boolean hasAce = false;
for (Card card: cards) {
score += card.rank < 10 ? card.rank : 10;
if (card.rank == 1) {
hasAce = true;
}
}
if (score <= 11 && hasAce) {
score += 10;
}
return score;
}
public boolean isBlackJack() {
return cards.size() == 2 && calcScore() == 21;
}
public boolean isBust() {
return calcScore() > 21;
}
public void show() {
System.out.println("----------");
showCards();
System.out.println(name + "'s score: " + calcScore());
}
public void showCards() {
System.out.println(name + "'s card: " + cards.stream().map(Object::toString).collect(Collectors.joining(", ")));
}
}
CUIPlayer.java
import java.util.Scanner;
public class CUIPlayer extends Player {
private Scanner sc = new Scanner(System.in);
public boolean play(CardDealer dealer) {
while (!isBust() || dealer == null) {
if (!stand) {
show();
}
System.out.println("----------");
System.out.println("Please enter a command.");
System.out.println(" q: quit");
System.out.println(" r: restart");
if (!stand && dealer != null) {
System.out.println(" h: hit");
System.out.println(" s: stand");
}
System.out.print("? ");
String inputStr = sc.nextLine();
switch (inputStr) {
case "q":
case "quit":
System.out.println("bye.");
sc.close();
System.exit(0);
break;
case "r":
case "reset":
return false;
case "h":
case "hit":
if (!stand && dealer != null) {
dealer.dealCard(this);
}
break;
case "s":
case "stand":
stand = true;
return true;
default:
System.out.println("Unsupported command.");
break;
}
}
stand = true;
return true;
}
}
Dealer.java
public class Dealer extends Player implements CardDealer {
private final Deck deck;
public Dealer() {
this(new Deck());
}
public Dealer(Deck deck) {
super("Dealer");
this.deck = deck;
}
public void dealCard(Player player) {
player.holdCard(deck.drowCard());
}
public boolean play(CardDealer dealer) {
while (calcScore() < 17) {
dealer.dealCard(this);
}
stand = true;
return true;
}
@Override
public void show() {
if (stand || cards.size() != 2) {
super.show();
} else {
System.out.println("----------");
cards.get(1).faceDown();
showCards();
cards.get(1).faceUp();
}
}
}
CardDealer.java
public interface CardDealer {
public void dealCard(Player player);
}
Deck.java
import java.util.ArrayList;
import java.util.Collections;
public class Deck {
private final ArrayList<Card> cards = new ArrayList<Card>();
public Deck() {
reset();
}
void reset() {
cards.clear();
for (Suit suit: Suit.values()) {
for (int rank = 1; rank <= 13; rank++) {
cards.add(new Card(suit, rank));
}
}
shuffle();
}
public void shuffle() {
Collections.shuffle(cards);
}
public Card drowCard() {
if (cards.size() == 0) {
reset();
}
return cards.remove(0);
}
}
Card.java
enum Suit {
SPADE, CLOBBER, HEART, DIAMOND;
}
public class Card {
public static String[] RANK = {
"", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
};
public final Suit suit;
public final int rank;
private boolean visible;
public Card(Suit suit, int rank) {
this.suit = suit;
this.rank = rank;
faceUp();
}
public void faceUp() {
this.visible = true;
}
public void faceDown() {
this.visible = false;
}
@Override
public String toString() {
if (visible) {
return suit.name() + ' ' + RANK[rank];
} else {
return "???";
}
}
}
Recommended Posts