Qiitaでこんな記事を見つけたので、BlackJackをRubyで作ってみました。
プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし | Qiita
感想としては簡単なゲームを作るだけですが、とても楽しかったです。BlackJackを作ってみてゲーム以外にも色々作れそうな気がしたのでもう少しBlackJackのコードを変えながら遊んでみてから次何を作るか考えようかなと思ってます。
全てのコードはGithub上に上げているのでこちらから確認できます
BlackJack Ruby | Ryutaro - Github
ブラックジャックのルール
ブラックジャックのルールについては、こちらの記事に書かれているルールを基準に作成しました。
- 初期カードは52枚。引く際にカードの重複は無いようにする
- プレイヤーとディーラーの2人対戦。プレイヤーは実行者、ディーラーは自動的に実行
- 実行開始時、プレイヤーとディーラーはそれぞれ、カードを2枚引く。引いたカードは画面に表示する。ただし、ディーラーの2枚目のカードは分からないようにする
- その後、先にプレイヤーがカードを引く。プレイヤーが21を超えていたらバースト、その時点でゲーム終了
- プレイヤーは、カードを引くたびに、次のカードを引くか選択できる
- プレイヤーが引き終えたら、その後ディーラーは、自分の手札が17以上になるまで引き続ける
- プレイヤーとディーラーが引き終えたら勝負。より21に近い方の勝ち
- JとQとKは10として扱う
- Aはとりあえず「1」としてだけ扱う。「11」にはしない
- ダブルダウンなし、スプリットなし、サレンダーなし、その他特殊そうなルールなし
悩んだところ
- 用意するクラスについて
- インスタンスメソッドまたはクラスメソッドどっちにするか
- データをどこで保持させるべきか(山札や手札など)
用意したクラス
次の6つのクラスを作成しました。
それぞれのクラスの役割は次になります。
# カードNumberとダイヤやハートなどのマークをそれぞれ配列で用意するクラス
class Card
# 用意したカードから山札を作成してシャッフルするクラス、Cardクラスを継承している
class Deck < Card
# プレイヤーとディーラーのスーパークラスでそれぞれの共通処理をするクラス
class PlayerBase
# プレイヤー専用の処理を作成している、PlayerBaseを継承している
class Player < PlayerBase
# ディーラー専用の処理を作成している、PlayerBaseを継承している
class Dealer < PlayerBase
# ゲームの進行に必要な処理や手札や山札などのデータを保持するクラス
class BlackJack
プレイヤーとディーラーで共通する処理が多かったためPlayerBase
というスーパークラスを作成することでメソッドの使い回しができるようになり楽に進められた気がします。
インススタンスメソッドまたはクラスメソッドにすべきか
これについてもめちゃくちゃ悩んで「ruby インスタンスメソッド クラスメソッド 違い」みたいなことを何回もググりました。
結果的に「基本的にはインスタンスメソッドで作成して、ちょっとインスタンスメソッドだと使いづらいかな?と感じたところはクラスメソッドにしよう」という少し抽象的な判断で決めています。
クラスメソッド例
class Card
class << self
def numbers
no = [1, 2, 3, 4, 5, 6, 7 ,8 ,9 ,10, 11, 12, 13]
end
def suit
suit = ["ダイヤ", "ハート", "クラブ", "スペード"]
end
end
end
インスタンスメソッド例
class PlayerBase
def create_hand(deck)
deck.pop(2)
end
# .
# .
# .
手札や山札などのデータをどのクラスで保持するべきか
データの保管場所が一番悩んだところです。当初は「プレイヤーの手札だからPlayerクラスで、ディーラーの手札だからDealerクラスで管理しよう。山札に関しては共通のものだからPlayerBaseクラスだよね」と思ったのですが、進めていく途中でインスタンスを生成した際に2つの山札が作られてしまうなど色々面倒なことが多かったので、BlackJackクラスで全てのデータを保持する方針で決まりました。
詳細なコード説明
詳細なコードの説明はまた別で記事にしようと思います。今回は感想や苦労したところを書いてみました。