1.はじめに
ディーラーとプレイヤーの2人で対戦するコンソールゲームを作成した。
コンソール画面のイメージは次の通り。
ブラックジャックを開始します。
あなたの引いたカードはハートの7です。
あなたの引いたカードはクラブの8です。
ディーラーの引いたカードはダイヤのQです。
ディーラーの引いた2枚目のカードはわかりません。
あなたの現在の得点は15です。カードを引きますか?(Y/N)
Y
あなたの引いたカードはスペードの5です。
あなたの現在の得点は20です。カードを引きますか?(Y/N)
N
ディーラーの引いた2枚目のカードはダイヤの2でした。
ディーラーの現在の得点は12です。
ディーラーの引いたカードはハートのKです。
あなたの得点は20です。
ディーラーの得点は22です。
あなたの勝ちです!
ブラックジャックを終了します。
(上記、引用)
1-1.きっかけ
作成しようと思ったきっかけは、現在受講中転職サービスの課題の一つだったからです。
1-2.目的
ブラックジャックゲームをオブジェクト指向を使って実装すること。
オブジェクト指向でプログラムを作成した実績を作るのが目的です。
1-3.開発環境
Windows 11 Home バージョン: 22H2
Visual Studio Code バージョン: 1.77.3
Ruby バージョン: 3.2.1
1-4.納期
他の演習や読まなければならない書籍等あったため、1weekとした。
2.開発の振り返り
2-1.ルール
ブラックジャックはカジノで行われるカードゲームの一種です。
1〜13までの数が書かれたカード52枚を使ってゲームが行われます。
ルールは次の通りです。
実行開始時、ディーラーとプレイヤー全員に2枚ずつカードが配られる
自分のカードの合計値が21に近づくよう、カードを追加するか、追加しないかを決める
カードの合計値が21を超えてしまった時点で、その場で負けが確定する
プレイヤーはカードの合計値が21を超えない限り、好きなだけカードを追加できる
ディーラーはカードの合計値が17を超えるまでカードを追加する
各カードの点数は次のように決まっています。
2から9までは、書かれている数の通りの点数
10,J,Q,Kは10点
Aは1点あるいは11点として、手の点数が最大となる方で数える。
2-2-1.STEP1
ディーラーとプレイヤーの2人で対戦するコンソールゲームを作成しましょう。
以下のルールの元、コンソール(ターミナル)上で動作するようにします。
プレイヤーは実行者、ディーラーはCPUが自動実行する
実行開始時、プレイヤーとディーラーはそれぞれ、カードを2枚引く。
引いたカードは画面に表示する。
ただし、ディーラーの2枚目のカードは分からないようにする。
その後、先にプレイヤーがカードを引く。
プレイヤーのカードの合計値が21を超えたらプレイヤーの負け
プレイヤーはカードを引くたびに次のカードを引くか選択できる。
プレイヤーがカードを引き終えたら、ディーラーは自分のカードの合計値が17以上になるまで引き続ける。
プレイヤーとディーラーが引き終えたら勝負。カードの合計値が21により近い方が勝ち。
Aは1点として取り扱う。
開発が終わって感じた事
SOLID 原則の「単一責任の原則」に則って、 複数の責務を負っているクラスを切り離さなければならなかったが、DeckクラスとCardクラスを一緒にしてしまっている事が「単一責任の原則」を遵守出来ていなかったと感じる。クラス設計をする際にUMLを用いてもっと深く考慮するべきであった。
2-2-2.STEP2
Aを1点あるいは11点のどちらかで扱うようにプログラムを修正しましょう。
Aはカードの合計値が21以内で最大となる方で数えるようにします。
開発が終わって感じた事
Aを1点あるいは11点のどちらかで扱うようにするためには、複数のロジックがある。
・デフォルトを11点として、合計21点を超えたら、合計から-10点×Aの枚数にする。
・1点と11点を配列で保持して起き、それぞれを計算しておく。
合計21点未満ではそれぞれの最大値を表示・合計22点以上はそれぞれの最小値を表示。
・etc..
今回の実装では、2番を選択したが、1を選択した方がロジック・コード共にシンプルでリファクタリングや可読性に優れていたのではないかと思う。
2-2-3.STEP3(任意)-未実装
最大3人までのプレイヤーでプレイできるようにしましょう(ディーラーと合わせて合計4人)。増えたプレイヤーはCPUが自動的に操作します。
時間の都合上、割愛。
2-2-4.STEP4(任意)-未実装
ダブルダウン、スプリット、サレンダーのルールを追加しましょう。ルールは各自調べてみてください。
時間の都合上、割愛。
3.開発中に気をつけたこと
3-1.UML
UML設計して思想を固めた上でコードを実装したい。
(もちろん、書いているうちに変更する場合もあるが、、)
UMLは下記のサイトで作成。
3-2.テスト
クラス毎のファイル作成時に、実装ファイルとテストファイルを作成。最初に簡単なコードを書いてテストが通ることを確認してから、実装ファイルにコードを記載していく。テストコードを書いてから実装する、レッドグリーンを採用。
テストにはMiniTESTを使用したが、今後はRSpecも活用していきたい。
3-3.デバッグ
デバッグを使用すると、デバッグ時点の変数値がわかるので、エラー原因の特定につながる。積極的に使用したい。
#モジュール読み込み
require 'debug'
#デバッグしたい部分に下記を記載
binding.break
3-4.静的解析ツール
rubocopを使用。
Gemfileと.rubocop.ymlを下記の様に記載。
.rubocop_todo.ymlは自動生成される。
# frozen_string_literal: true
source "https://rubygems.org"
group :development do
gem 'rubocop', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
end
inherit_from: .rubocop_todo.yml
3-5.リファクタリング
コードが冗長的でないか・可読性は良いか・関数名がわかり易いか、を念頭に都度、リファクタリングを実施。
4.おわりに
限られた時間の中で、書籍やコードの実装を行い、学びが多い期間となった。
正直、UML設計のシーケンス図やユースケース図、実装できていないSTEPや、まだまだリファクタリングしきれていない部分もあるので、他の課題が終わって時間が出来たら再び戻ってきたい。
引き続き、精進していこう。