「プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし」という記事に感化されて、
Kotlinでブラックジャックを作成してみました。
私のスキル
- エンジニア8年目
- Java,PHP:業務で書いている
- Kotlin:実務経験なし,ハンズオンに参加して得た知識のみ
ソースコード
https://github.com/matyahiko2831/BlackJackKotlin
参考サイトの開発開始以降はなるべく見ずに作成しました。
10時間くらいで作れたかなと思います。。。!
開発環境
- Kotlin 1.2.40
- Gradle 4.7
- IntelliJ IDEA
実行結果
↑2018/05/08追記 PLAYERとあなた、DEALERとディーラー 文言統一されてないですねorz作ってみた感想
- 成果物が明確なので「調べながら開発する」という実務に近い営みが出来る。そのため、漫然とチュートリアルやったり参考書読むよりは身になると思いました!
- ブラックジャックという題材はルールがわかりやすく難易度的にちょうどよいと思いました。
- Kotlinがほぼ未経験ということを置いといても、クラス設計が下手くそ。。。
- (本題から外れますが)無からKotlinが動作する環境を整えるということを経験できてよかったです。Gradleの設定やgitignoreがイケてないかもしれませんorz
ソース抜粋
メインクラス
Main.kt
package blackjack
import model.*
import exception.*
fun main(args: Array<String>) {
println("☆★☆☆★☆ブラックジャックへようこそ!☆★☆☆★☆")
println("ゲームを開始します")
// デッキ初期化
var deck = Deck()
// プレイヤー・ディーラー初期化
var player = User()
var dealer = User()
// プレイヤー 最初のドロー
player.hand.add(deck.draw(Role.PLAYER))
player.hand.add(deck.draw(Role.PLAYER))
// ディーラー 最初のドロー
dealer.hand.add(deck.draw(Role.DEALER))
// 2枚目は何を引いたか表示させない
dealer.hand.add(deck.draw(Role.DEALER,true))
println("あなたの現在の得点は${player.getScore()}です。")
var input: String?
// ユーザーのターン
while (true) {
println("カードを引きますか?引く場合はYを、引かない場合はNを入力して下さい")
input = readLine()
if("Y" == input || "y" == input) {
player.hand.add(deck.draw(Role.PLAYER))
println("あなたの現在の得点は${player.getScore()}です。")
if(player.isBurst()) {
println("バーストしました。")
println("あなたの負けです。")
println("ブラックジャック終了!また遊んでね★")
System.exit(0)
}
} else if("N" == input || "n" == input) {
break
} else {
println("YかNを入力して下さい。")
}
}
// ディーラーのターン
println("ディーラーの2枚目のカードは${dealer.hand[1]}でした。")
println("ディーラーの現在の得点は${dealer.getScore()}です。")
// 得点が17点以上になるまで繰り返す
while(dealer.getScore() < 17) {
dealer.hand.add(deck.draw(Role.DEALER))
}
println("あなたの得点は${player.getScore()}です。")
println("ディーラーの得点は${dealer.getScore()}です。")
if(dealer.isBurst()
|| player.getScore() > dealer.getScore()) {
println("あなたの勝ちです。")
} else if (player.getScore() == dealer.getScore()){
println("引き分けです。")
} else {
println("あなたの負けです。")
}
println("ブラックジャック終了!また遊んでね★")
}
所感
- 「カードを引いてユーザの手札に加える」というユースケースをもっとうまく表現出来たと思う。(Userクラスにdrawメソッドを持たせる?)
- RoleはUserクラスに持たせるべきだったかな。
カードクラス
Card.kt
package model
/**
*
* カードクラス
* @param suit マーク
* @param index 表示
* @param rank ランク
* @param used 使用済み
*
* */
class Card(val suit: Suit, val index: String, val rank: Int, var used: Boolean = false){
public override fun toString(): String {
return "${suit}の${index}"
}
}
所感
- PHPではおなじみの引数の初期値が設定できるのが良い。
- フィールドもgetterもsetterもいらないんですね。
デッキクラス
Deck.kt
package model
import java.util.Random
import exception.*
/**
* デッキクラス
* */
class Deck {
/** デッキ残数 */
private var remaining: Int = 52
public val cards = arrayOf<Card>(
Card(Suit.SPADE, "1", 1),
Card(Suit.SPADE, "2", 2),
Card(Suit.SPADE, "3", 3),
Card(Suit.SPADE, "4", 4),
Card(Suit.SPADE, "5", 5),
Card(Suit.SPADE, "6", 6),
Card(Suit.SPADE, "7", 7),
Card(Suit.SPADE, "8", 8),
Card(Suit.SPADE, "9", 9),
Card(Suit.SPADE, "10", 10),
Card(Suit.SPADE, "J", 10),
Card(Suit.SPADE, "Q", 10),
Card(Suit.SPADE, "K", 10),
Card(Suit.HART, "1", 1),
Card(Suit.HART, "2", 2),
Card(Suit.HART, "3", 3),
Card(Suit.HART, "4", 4),
Card(Suit.HART, "5", 5),
Card(Suit.HART, "6", 6),
Card(Suit.HART, "7", 7),
Card(Suit.HART, "8", 8),
Card(Suit.HART, "9", 9),
Card(Suit.HART, "10", 10),
Card(Suit.HART, "J", 10),
Card(Suit.HART, "Q", 10),
Card(Suit.HART, "K", 10),
Card(Suit.DIAMOND, "1", 1),
Card(Suit.DIAMOND, "2", 2),
Card(Suit.DIAMOND, "3", 3),
Card(Suit.DIAMOND, "4", 4),
Card(Suit.DIAMOND, "5", 5),
Card(Suit.DIAMOND, "6", 6),
Card(Suit.DIAMOND, "7", 7),
Card(Suit.DIAMOND, "8", 8),
Card(Suit.DIAMOND, "9", 9),
Card(Suit.DIAMOND, "10", 10),
Card(Suit.DIAMOND, "J", 10),
Card(Suit.DIAMOND, "Q", 10),
Card(Suit.DIAMOND, "K", 10),
Card(Suit.CLUB, "1", 1),
Card(Suit.CLUB, "2", 2),
Card(Suit.CLUB, "3", 3),
Card(Suit.CLUB, "4", 4),
Card(Suit.CLUB, "5", 5),
Card(Suit.CLUB, "6", 6),
Card(Suit.CLUB, "7", 7),
Card(Suit.CLUB, "8", 8),
Card(Suit.CLUB, "9", 9),
Card(Suit.CLUB, "10", 10),
Card(Suit.CLUB, "J", 10),
Card(Suit.CLUB, "Q", 10),
Card(Suit.CLUB, "K", 10)
)
/**
* カードドロー
* デッキが0枚になったらException
* @return Card
* @throws DeckOutException
* */
public fun draw(role: Role, hide: Boolean = false): Card {
while (true) {
val card = cards[Random().nextInt(cards.size)]
if(!card.used) {
card.used = true;
remaining--
if(hide) {
println("${role}の引いたカードは分かりません。")
} else {
println("${role}の引いたカードは${card}です。")
}
return card
}
if (remaining == 0) {
// いらないけど例外の勉強のために
throw DeckOutException("デッキ切れ")
}
}
}
}
所感
- カードリストは絶対もっと良い実装があったと思う。
ご意見お待ちしておりますm(_ _)m