Javaでブラックジャックを作る

# TL;DR
昨年GW期間中に[TypeScript](https://github.com/yuta-yoshinaga/typescript_trumpcards)で作成したブラックジャックをJavaで作り直したので、その作業メモ。

## 公開リポジトリ
[GitHub](https://github.com/yuta-yoshinaga/java_trumpcards)

## doxygenドキュメント
[doxygen](https://yuta-yoshinaga.github.io/java_trumpcards/)

## 各種クラス

### Card

```java
////////////////////////////////////////////////////////////////////////////////
///	@file			Card.java
///	@brief			カードクラス
///	@author			Yuta Yoshinaga
///	@date			2019.04.27
///	$Version:		$
///	$Revision:		$
///
/// (c) 2019 Yuta Yoshinaga.
///
/// - 本ソフトウェアの一部又は全てを無断で複写複製（コピー）することは、
///   著作権侵害にあたりますので、これを禁止します。
/// - 本製品の使用に起因する侵害または特許権その他権利の侵害に関しては
///   当方は一切その責任を負いません。
///
////////////////////////////////////////////////////////////////////////////////

package jp.gr.java_conf.yuta_yoshinaga.java_trumpcards;

////////////////////////////////////////////////////////////////////////////////
///	@class		Card
///	@brief		カードクラス
///
////////////////////////////////////////////////////////////////////////////////
public class Card {
	public static final int DEF_CARD_TYPE_JOKER = 0;
	public static final int DEF_CARD_TYPE_SPADE = 1;
	public static final int DEF_CARD_TYPE_CLOVER = 2;
	public static final int DEF_CARD_TYPE_HEART = 3;
	public static final int DEF_CARD_TYPE_DIAMOND = 4;
	public static final int DEF_CARD_TYPE_MIN = DEF_CARD_TYPE_JOKER;
	public static final int DEF_CARD_TYPE_MAX = DEF_CARD_TYPE_DIAMOND;

	public static final int DEF_CARD_VALUE_JOKER = 0;
	public static final int DEF_CARD_VALUE_MIN = 0;
	public static final int DEF_CARD_VALUE_MAX = 13;

	private int type; //!< カード種類
	private int value; //!< カード値
	private boolean drowFlag; //!< カード払い出しフラグ
	private String ext; //!< カード拡張情報など(カード別にメッセージを出す場合など)

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			コンストラクタ
	///	@fn				public Card()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public Card() {
		this.type = DEF_CARD_TYPE_JOKER;
		this.value = DEF_CARD_VALUE_JOKER;
		this.drowFlag = false;
		this.ext = "";
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public int getType()
	///	@return			カード種類
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getType() {
		return type;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setType(int type)
	///	@param[in]		int type		カード種類
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setType(int type) {
		if(DEF_CARD_TYPE_MIN <= type && type <= DEF_CARD_TYPE_MAX){
			this.type = type;
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public getValue(): number
	///	@return			カード値
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getValue() {
		return value;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setValue(int value)
	///	@param[in]		int value		カード値
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setValue(int value) {
		if(DEF_CARD_VALUE_MIN <= value && value <= DEF_CARD_VALUE_MAX){
			this.value = value;
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public boolean getDrowFlag()
	///	@return			カード払い出しフラグ
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public boolean getDrowFlag() {
		return drowFlag;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setDrowFlag(boolean drowFlag)
	///	@param[in]		boolean drowFlag		カード払い出しフラグ
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setDrowFlag(boolean drowFlag) {
		this.drowFlag = drowFlag;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public String getExt()
	///	@return			カード払い出しフラグ
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public String getExt() {
		return ext;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setExt(String ext)
	///	@param[in]		String ext		カード拡張情報など(カード別にメッセージを出す場合など)
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setExt(String ext) {
		this.ext = ext;
	}

}
```

トランプのカード情報を保持するクラス。

### TrumpCards

```java
////////////////////////////////////////////////////////////////////////////////
///	@file			TrumpCards.java
///	@brief			トランプカードクラス
///	@author			Yuta Yoshinaga
///	@date			2019.04.27
///	$Version:		$
///	$Revision:		$
///
/// (c) 2019 Yuta Yoshinaga.
///
/// - 本ソフトウェアの一部又は全てを無断で複写複製（コピー）することは、
///   著作権侵害にあたりますので、これを禁止します。
/// - 本製品の使用に起因する侵害または特許権その他権利の侵害に関しては
///   当方は一切その責任を負いません。
///
////////////////////////////////////////////////////////////////////////////////
package jp.gr.java_conf.yuta_yoshinaga.java_trumpcards;

import java.util.ArrayList;
import java.util.Collections;

////////////////////////////////////////////////////////////////////////////////
///	@class		TrumpCards
///	@brief		トランプカードクラス
///
////////////////////////////////////////////////////////////////////////////////
public class TrumpCards {
	public static final int DEF_CARD_CNT = (13 * 4);
	private ArrayList<Card> deck; //!< 山札
	private int deckDrowCnt; //!< 山札配った枚数
	private int deckCnt; //!< 山札枚数

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			コンストラクタ
	///	@fn				public TrumpCards(int jokerCnt)
	///	@param[in]		int jokerCnt		ジョーカー枚数
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public TrumpCards(int jokerCnt) {
		this.deckCnt = DEF_CARD_CNT + jokerCnt;
		this.cardsInit();
		this.deckInit();
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public ArrayList<Card> getDeck()
	///	@return			山札
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public ArrayList<Card> getDeck() {
		return deck;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setDeck(ArrayList<Card> deck)
	///	@param[in]		ArrayList<Card> deck	山札
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setDeck(ArrayList<Card> deck) {
		this.deck = deck;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public int getDeckDrowCnt()
	///	@return			山札配った枚数
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getDeckDrowCnt() {
		return deckDrowCnt;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setDeckDrowCnt(int deckDrowCnt)
	///	@param[in]		int deckDrowCnt	山札配った枚数
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setDeckDrowCnt(int deckDrowCnt) {
		this.deckDrowCnt = deckDrowCnt;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public int getDeckCnt()
	///	@return			山札枚数
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getDeckCnt() {
		return deckCnt;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setDeckCnt(int deckCnt)
	///	@param[in]		int deckCnt	山札枚数
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setDeckCnt(int deckCnt) {
		this.deckCnt = deckCnt;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			カード初期化
	///	@fn				private void cardsInit()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	private void cardsInit() {
		this.deck = new ArrayList<Card>();
		for (int i = 0; i < this.deckCnt; i++) {
			Card curCard = new Card();
			curCard.setDrowFlag(false);
			if (0 <= i && i <= 12) {
				// *** スペード *** //
				curCard.setType(Card.DEF_CARD_TYPE_SPADE);
				curCard.setValue(i + 1);
			} else if (13 <= i && i <= 25) {
				// *** クローバー *** //
				curCard.setType(Card.DEF_CARD_TYPE_CLOVER);
				curCard.setValue((i - 13) + 1);
			} else if (26 <= i && i <= 38) {
				// *** ハート *** //
				curCard.setType(Card.DEF_CARD_TYPE_HEART);
				curCard.setValue((i - 26) + 1);
			} else if (39 <= i && i <= 51) {
				// *** ダイアモンド *** //
				curCard.setType(Card.DEF_CARD_TYPE_DIAMOND);
				curCard.setValue((i - 39) + 1);
			} else {
				// *** ジョーカー *** //
				curCard.setType(Card.DEF_CARD_TYPE_JOKER);
				curCard.setValue((i - 52) + 1);
			}
			this.deck.add(curCard);
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			山札初期化
	///	@fn				private void deckInit()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	private void deckInit() {
		this.deckDrowFlagInit();
		this.deckDrowCnt = 0;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			山札ドローフラグ初期化
	///	@fn				private deckDrowFlagInit(): void
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	private void deckDrowFlagInit() {
		for (int i = 0; i < this.deckCnt; i++) {
			this.deck.get(i).setDrowFlag(false);
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			山札シャッフル
	///	@fn				public shuffle(): void
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void shuffle() {
		Collections.shuffle(this.deck);
		this.deckDrowFlagInit();
		this.deckDrowCnt = 0;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			山札配る
	///	@fn				public drowCard(): Card
	///	@return			カードクラス
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public Card drowCard() {
		Card res = null;
		if (this.deckDrowCnt < this.deckCnt) {
			this.deck.get(this.deckDrowCnt).setDrowFlag(true);
			res = this.deck.get(this.deckDrowCnt++);
		}
		return res;
	}

}
```

トランプカードの山札などを管理するクラス。

### Player

```java
////////////////////////////////////////////////////////////////////////////////
///	@file			Player.java
///	@brief			プレイヤークラス
///	@author			Yuta Yoshinaga
///	@date			2019.04.27
///	$Version:		$
///	$Revision:		$
///
/// (c) 2019 Yuta Yoshinaga.
///
/// - 本ソフトウェアの一部又は全てを無断で複写複製（コピー）することは、
///   著作権侵害にあたりますので、これを禁止します。
/// - 本製品の使用に起因する侵害または特許権その他権利の侵害に関しては
///   当方は一切その責任を負いません。
///
////////////////////////////////////////////////////////////////////////////////
package jp.gr.java_conf.yuta_yoshinaga.java_trumpcards;

import java.util.ArrayList;

////////////////////////////////////////////////////////////////////////////////
///	@class		Player
///	@brief		プレイヤークラス
///
////////////////////////////////////////////////////////////////////////////////
public class Player {
	private ArrayList<Card> cards; //!< プレイヤーカード
	private int cardsCnt; //!< プレイヤーカード枚数
	private int score; //!< プレイヤースコア

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			コンストラクタ
	///	@fn				public Player()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public Player() {
		this.cards = new ArrayList<Card>();
		this.cardsCnt = 0;
		this.score = 0;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				ArrayList<Card> getCards()
	///	@return			プレイヤーカード
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public ArrayList<Card> getCards() {
		return cards;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setCards(ArrayList<Card> cards)
	///	@param[in]		ArrayList<Card> cards プレイヤーカード
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setCards(ArrayList<Card> cards) {
		this.cards = cards;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public int getCardsCnt()
	///	@return			プレイヤーカード枚数
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getCardsCnt() {
		return cardsCnt;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setCardsCnt(int cardsCnt)
	///	@param[in]		int cardsCnt プレイヤーカード枚数
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setCardsCnt(int cardsCnt) {
		this.cardsCnt = cardsCnt;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public int getScore()
	///	@return			プレイヤースコア
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getScore() {
		return score;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setScore(int score)
	///	@param[in]		int score プレイヤースコア
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setScore(int score) {
		this.score = score;
	}

}
```

ブラックジャックのプレイヤー情報を保持するクラス

### BlackJack

```java
////////////////////////////////////////////////////////////////////////////////
///	@file			BlackJack.java
///	@brief			ブラックジャッククラス
///	@author			Yuta Yoshinaga
///	@date			2019.04.27
///	$Version:		$
///	$Revision:		$
///
/// (c) 2019 Yuta Yoshinaga.
///
/// - 本ソフトウェアの一部又は全てを無断で複写複製（コピー）することは、
///   著作権侵害にあたりますので、これを禁止します。
/// - 本製品の使用に起因する侵害または特許権その他権利の侵害に関しては
///   当方は一切その責任を負いません。
///
////////////////////////////////////////////////////////////////////////////////
package jp.gr.java_conf.yuta_yoshinaga.java_trumpcards;

import java.util.ArrayList;

////////////////////////////////////////////////////////////////////////////////
///	@class		BlackJack
///	@brief		ブラックジャッククラス
///
////////////////////////////////////////////////////////////////////////////////
public class BlackJack {
	public static final int DEF_SHUFFLE_CNT = 10;
	private TrumpCards trumpCards; //!< トランプカード
	private Player player; //!< プレイヤー
	private Player dealer; //!< ディーラー
	private boolean gameEndFlag; //!< ゲーム終了フラグ

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			コンストラクタ
	///	@fn				public BlackJack()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public BlackJack() {
		this.trumpCards = new TrumpCards(0);
		this.player = new Player();
		this.dealer = new Player();
		this.gameInit();
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				TrumpCards getTrumpCards()
	///	@return			トランプカード
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public TrumpCards getTrumpCards() {
		return trumpCards;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setTrumpCards(TrumpCards trumpCards)
	///	@param[in]		TrumpCards trumpCards	トランプカード
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setTrumpCards(TrumpCards trumpCards) {
		this.trumpCards = trumpCards;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public Player getPlayer()
	///	@return			プレイヤー
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public Player getPlayer() {
		return player;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setPlayer(Player player)
	///	@param[in]		Player player	プレイヤー
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setPlayer(Player player) {
		this.player = player;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public Player getDealer()
	///	@return			ディーラー
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public Player getDealer() {
		return dealer;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setDealer(Player dealer)
	///	@param[in]		Player dealer	ディーラー
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setDealer(Player dealer) {
		this.dealer = dealer;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲッター
	///	@fn				public boolean getGameEndFlag()
	///	@return			ディーラー
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public boolean getGameEndFlag() {
		return gameEndFlag;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			セッター
	///	@fn				public void setGameEndFlag(boolean gameEndFlag)
	///	@param[in]		boolean gameEndFlag	ゲーム終了フラグ
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void setGameEndFlag(boolean gameEndFlag) {
		this.gameEndFlag = gameEndFlag;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲーム初期化
	///	@fn				public void gameInit()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void gameInit() {
		this.gameEndFlag = false;
		// *** 山札シャッフル *** //
		for (int i = 0; i < DEF_SHUFFLE_CNT; i++) {
			this.trumpCards.shuffle();
		}
		// *** プレイヤー・ディーラー初期化 *** //
		this.player.setCards(new ArrayList<Card>());
		this.player.setCardsCnt(0);
		this.dealer.setCards(new ArrayList<Card>());
		this.dealer.setCardsCnt(0);
		// *** プレイヤー・ディーラー手札を2枚づつ配る *** //
		for (int i = 0; i < 2; i++) {
			this.player.getCards().add(this.trumpCards.drowCard());
			this.player.setCardsCnt(this.player.getCardsCnt() + 1);
			this.dealer.getCards().add(this.trumpCards.drowCard());
			this.dealer.setCardsCnt(this.dealer.getCardsCnt() + 1);
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			プレイヤーヒット
	///	@fn				public void playerHit()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void playerHit() {
		if (this.gameEndFlag == false) {
			this.player.getCards().add(this.trumpCards.drowCard());
			this.player.setCardsCnt(this.player.getCardsCnt() + 1);
			int score = this.getScore(this.player.getCards(), this.player.getCardsCnt());
			if (22 <= score)
				this.playerStand(); // バーストしたので強制終了
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			プレイヤースタンド
	///	@fn				public void playerStand()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void playerStand() {
		this.dealerHit();
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ディーラーヒット
	///	@fn				private void dealerHit()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	private void dealerHit() {
		for (;;) {
			int score = this.getScore(this.dealer.getCards(), this.dealer.getCardsCnt());
			if (score < 17) {
				// *** ディーラーは自分の手持ちのカードの合計が「17」以上になるまで	  *** //
				// *** ヒットし続ける（カードを引き続ける）							*** //
				this.dealer.getCards().add(this.trumpCards.drowCard());
				this.dealer.setCardsCnt(this.dealer.getCardsCnt() + 1);
			} else {
				// *** ディーラーは自分の手持ちカードの合計が「17」以上になったら	  *** //
				// *** ステイする（カードを引かない）。								*** //
				this.dealerStand();
				break;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ディーラースタンド
	///	@fn				private void dealerStand()
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	private void dealerStand() {
		this.gameEndFlag = true;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			手札から現在のスコア取得
	///	@fn				public int getScore(ArrayList<Card> cards,int cardsCnt)
	///	@param[in]		ArrayList<Card> cards	手札
	///	@param[in]		int cardsCnt			手札枚数
	///	@return			現在のスコア
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int getScore(ArrayList<Card> cards, int cardsCnt) {
		int res = 0;
		boolean aceFlag = false;
		for (int i = 0; i < cardsCnt; i++) {
			if (2 <= cards.get(i).getValue() && cards.get(i).getValue() <= 10) {
				// *** 2～10 *** //
				res += cards.get(i).getValue();
			} else if (11 <= cards.get(i).getValue() && cards.get(i).getValue() <= 13) {
				// *** 11～13 *** //
				res += 10;
			} else {
				if (aceFlag) {
					// *** 2枚目のエースは強制的に1で換算する*** //
					res += 1;
				} else {
					// *** エースは後ほど計算する *** //
					aceFlag = true;
				}
			}
		}
		if (aceFlag) {
			// *** エース計算 *** //
			var tmpScore1 = res + 1;
			var tmpScore2 = res + 11;
			var diff1 = 21 - tmpScore1;
			var diff2 = 21 - tmpScore2;
			if ((22 <= tmpScore1) && (22 <= tmpScore2)) {
				// *** どちらもバーストしているならエースを1 *** //
				res = tmpScore1;
			} else if ((22 <= tmpScore1) && (tmpScore2 <= 21)) {
				// *** エースが1でバーストしているならエースを11 *** //
				res = tmpScore2;
			} else if ((tmpScore1 <= 21) && (22 <= tmpScore2)) {
				// *** エースが11でバーストしているならエースを1 *** //
				res = tmpScore1;
			} else {
				// *** どちらもバーストしていないなら21との差分が小さい方を採用 *** //
				if (diff1 < diff2)
					res = tmpScore1;
				else
					res = tmpScore2;
			}
		}
		return res;
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ゲーム勝敗判定
	///	@fn				public int gameJudgment()
	///	@return			ゲーム勝敗判定
	///					- 1 : プレイヤーの勝利
	///					- 0 : 引き分け
	///					- -1 : プレイヤーの敗北
	///
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public int gameJudgment() {
		int res = 0;
		int score1 = this.getScore(this.player.getCards(), this.player.getCardsCnt());
		int score2 = this.getScore(this.dealer.getCards(), this.dealer.getCardsCnt());
		int diff1 = 21 - score1;
		int diff2 = 21 - score2;
		if (22 <= score1 && 22 <= score2) {
			// *** プレイヤー・ディーラー共にバーストしているので負け *** //
			res = -1;
		} else if (22 <= score1 && score2 <= 21) {
			// *** プレイヤーバーストしているので負け *** //
			res = -1;
		} else if (score1 <= 21 && 22 <= score2) {
			// *** ディーラーバーストしているので勝ち *** //
			res = 1;
		} else {
			if (diff1 == diff2) {
				// *** 同スコアなら引き分け *** //
				res = 0;
				if (score1 == 21 && this.player.getCardsCnt() == 2 && this.dealer.getCardsCnt() != 2) {
					// *** プレイヤーのみがピュアブラックジャックならプレイヤーの勝ち *** //
					res = 1;
				}
			} else if (diff1 < diff2) {
				// *** プレイヤーの方が21に近いので勝ち *** //
				res = 1;
			} else {
				// *** ディーラーの方が21に近いので負け *** //
				res = -1;
			}
		}
		return res;
	}

}
```

ブラックジャックゲーム及びプレイヤーの状態を管理するクラス。

### BlackJackMain

```java
////////////////////////////////////////////////////////////////////////////////
///	@file			BlackJackMain.java
///	@brief			ブラックジャックメインクラス
///	@author			Yuta Yoshinaga
///	@date			2019.04.27
///	$Version:		$
///	$Revision:		$
///
/// (c) 2019 Yuta Yoshinaga.
///
/// - 本ソフトウェアの一部又は全てを無断で複写複製（コピー）することは、
///   著作権侵害にあたりますので、これを禁止します。
/// - 本製品の使用に起因する侵害または特許権その他権利の侵害に関しては
///   当方は一切その責任を負いません。
///
////////////////////////////////////////////////////////////////////////////////
package jp.gr.java_conf.yuta_yoshinaga.java_trumpcards;

import java.util.ArrayList;
import java.util.Scanner;

////////////////////////////////////////////////////////////////////////////////
///	@class		BlackJackMain
///	@brief		ブラックジャックメインクラス
///
////////////////////////////////////////////////////////////////////////////////
public class BlackJackMain {

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			メインメソッド
	///	@fn				public static void main(String[] args)
	///	@param[in]		String[] args
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public static void main(String[] args) {
		BlackJackMain blackJackMain = new BlackJackMain();
		BlackJack blackJack = new BlackJack();
		Scanner sc = new Scanner(System.in);
		while (true) {
			System.out.println("Please enter a command.");
			System.out.println("q・・・quit");
			System.out.println("r・・・reset");
			System.out.println("h・・・hit");
			System.out.println("s・・・stand");
			blackJackMain.showStatus(blackJack);
			String inputStr = sc.nextLine();
			switch (inputStr) {
			case "q":
			case "quit":
				// quit
				System.out.println("bye.");
				sc.close();
				System.exit(0);
				break;
			case "r":
			case "reset":
				// reset
				blackJack.gameInit();
				break;
			case "h":
			case "hit":
				// hit
				blackJack.playerHit();
				break;
			case "s":
			case "stand":
				// stand
				blackJack.playerStand();
				break;
			default:
				// Unsupported command
				System.out.println("Unsupported command.");
				break;
			}
		}

	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			ステータス表示
	///	@fn				public void showStatus(BlackJack blackJack)
	///	@param[in]		BlackJack blackJack
	///	@return			ありません
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public void showStatus(BlackJack blackJack) {
		System.out.println("----------");
		// dealer
		ArrayList<Card> dc = blackJack.getDealer().getCards();
		int dcc = blackJack.getDealer().getCardsCnt();
		System.out.println("dealer score " + (blackJack.getGameEndFlag() ? blackJack.getScore(dc, dcc) : ""));
		String cardStr = "";
		if (blackJack.getGameEndFlag()) {
			for (int i = 0; i < dcc; i++) {
				if (i != 0)
					cardStr += ",";
				cardStr += getCardStr(dc.get(i));
			}
		} else {
			cardStr = getCardStr(dc.get(0)) + ",*";
		}
		System.out.println(cardStr);
		System.out.println("----------");
		// player
		ArrayList<Card> pc = blackJack.getPlayer().getCards();
		int pcc = blackJack.getPlayer().getCardsCnt();
		System.out.println("player score " + blackJack.getScore(pc, pcc));
		cardStr = "";
		for (int i = 0; i < pcc; i++) {
			if (i != 0)
				cardStr += ",";
			cardStr += getCardStr(pc.get(i));
		}
		System.out.println(cardStr);
		System.out.println("----------");
		if (blackJack.getGameEndFlag()) {
			if (blackJack.gameJudgment() == 1) {
				System.out.println("You are the winner.");
			} else if (blackJack.gameJudgment() == 0) {
				System.out.println("It is a draw.");
			} else {
				System.out.println("It is your loss.");
			}
			System.out.println("----------");
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	///	@brief			カード情報文字列取得
	///	@fn				public String getCardStr(Card card)
	///	@param[in]		Card card
	///	@return			カード情報文字列取得
	///	@author			Yuta Yoshinaga
	///	@date			2019.04.27
	///
	////////////////////////////////////////////////////////////////////////////////
	public String getCardStr(Card card) {
		String res = "";
		switch (card.getType()) {
		case Card.DEF_CARD_TYPE_SPADE:
			res = "SPADE ";
			break;
		case Card.DEF_CARD_TYPE_CLOVER:
			res = "CLOVER ";
			break;
		case Card.DEF_CARD_TYPE_HEART:
			res = "HEART ";
			break;
		case Card.DEF_CARD_TYPE_DIAMOND:
			res = "DIAMOND ";
			break;
		default:
			res = "Unsupported card";
			break;
		}
		res = res + card.getValue();
		return res;
	}
}
```

ブラックジャックゲームをコンソールで行う為のクラス。
コンソールからの入力に応じて、対応したアクションを取る。

## 所感

- なるべくオブジェクト指向に沿うようにクラス設計を行った。
- 現在業務にてJavaのコンソールアプリに携わっているので、コンソールアプリで作成した。
- できれば今後サーブレット版を作ってWebアプリ化したい。
- GW10連休の初日で、昼寝をしすぎて夜眠れなそうな変なテンションで作業を開始した。
- 作業時間2時間くらい。コンソールアプリは手軽に作れるので良い。