【Ruby】High and Low ゲーム

# はじめに

- <font color="Red">**Rubyのみ**</font>で自作アプリ<font color="Blue">**『High and Low』**</font>ゲームを作成しました。



<img width="695" alt="high_and_low_photo" src="https://user-images.githubusercontent.com/80377991/126028121-6503a545-b8ef-4740-bcb1-347103c843db.png">

# 作成目的

- ruby 言語を<font color="Red">**基礎的な部分から理解**</font>していこうと考えたため。
- <font color="Red">**実際に作りながら**</font>文法を使ったり、ロジックを組み立てていった方が<font color="Red">**効率よく学べる**</font>と考えたため。

## インストール方法

```
$ git clone https://github.com/ryokobayashi0321/high_and_low.git
$ cd high_and_low
$ ruby main.rb
```

## 環境

- ruby 2.7.3

## 使い方

1. ターミナルで `ruby main.rb` を実行。
2. 画面のメッセージに従い、`数値を入力`や `Enter キー`を押す。

## フローチャート図
<img width="500" alt="high_and_low_flow" src="https://user-images.githubusercontent.com/80377991/126027594-bd2742b6-ad24-4b77-aa43-3d2f9ea73bde.png">

## 説明

- master がトランプカードを 2 枚引きます。player は 2 枚目の数値が<font color="Red">**high(高い)**</font>か<font color="Blue">**low(低い)**</font>かを当てるゲームです。
- player の宣言通りになれば勝利です。
- トランプカードの数値に則ります。(ex A=1, J=11, Q=12, K=13),ジョーカーは含まれていません。
- 所持金が 0 円になったら、ゲームオーバーです。

## ゲームの流れ

**1. player は賭け金を設定します。（＄ 1〜player の所持金）**

**2. master が 2 枚カードを引きます（1 枚目：表、2 枚目：裏）**

**3. player は<font color="Red">1(high)</font> or <font color="Blue">2(low)</font>を選びます（1 or 2 の数値を入力し Enter キー）**

**4. 判定に入ります。**

   - <font color="Red">**1(high)を選んだ場合**</font>

     - 2 枚目カードの数値が 1 枚目より`高ければ勝ち`
     - 2 枚目カードの数値が 1 枚目より`低ければ負け`
     - 同じ数値は引き分け

   - <font color="Blue">**2(low)を選んだ場合**</font>
     - 2 枚目カードの数値が 1 枚目より`高ければ負け`
     - 2 枚目カードの数値が 1 枚目より`低けば勝ち`
     - 同じ数値は引き分け
   
**5. 賭け金の計算をします。**

   - <font color="Red">**勝ち**</font>
      - 賭け金の2倍額を手に入れられます。(賭け金は含まれる)
   - <font color="Blue">**負け**</font>
      - 賭け金を失います。
   - <font color="Green">**引き分け**</font>
      - 賭け金を返却します。

**6. コンティニューの選択**

   - player は<font color="Red">**1(ゲームを続ける)**</font> or <font color="Blue">**2(やめる)**</font> を選びます(1or2 の数値を入力し Enter キー)

   - <font color="Red">**1(ゲームを続ける)を選んだ場合**</font>

     - 掛け金が変化した状態で、**掛け金設定(最初)**に移行します。

   - <font color="Blue">**2(やめる)を選んだ場合**</font>
     - **ゲームを終了します。**

## 配当金
- <font color="Orange">**所持金**</font> - $100000
- <font color="Red">**勝ち**</font> - 掛け金 × 2 倍
- <font color="Green">**引き分け**</font>- 掛け金を返却する
- <font color="Blue">**負け**</font> - 掛け金を支払う

# さいごに

今後はもっとRubyの理解を深めていき、学習期間2ヶ月目で作ったこのアプリのコードをリファクタリングできるようにしていきたいと考えています。


**ぜひ遊んでみてください！！**

## ソースコード

```ruby:main.rb
require_relative "high_and_low"

master = Master.new
player = Player.new
high_and_low = HighAndLow.new(master, player)

# ゲームスタート
high_and_low.start
```

```ruby:high_and_low.rb
require_relative "card"
require_relative "deck"
require_relative "master"
require_relative "player"
require_relative "message"
class HighAndLow
  attr_reader :bet, :remaining_money, :paid, :first_card, :second_card

  HIGH_NUMBER = 1
  LOW_NUMBER = 2
  MAGNIFICATION_OF_MONEY = 2
  SELECT_NEW_GAME = 1
  SELECT_STOP_GAME = 2
  NO_MONEY = 0
  MINIMUM_AMOUNT_OF_MONEY = 1

  include Message

  def initialize(master, player)
    @master = master
    @player = player
  end

  def start
    start_message

    loop do
      @deck = Deck.new

      give_bet_message(@player)
      disp_bet(@player)

      drow_card_message
      disp_two_cards
      disp_card_message

      select_ation
      open_card_message
      number_message

      judge
      calculate_bet

      next_action
    end
  end

  private

  # <賭け金を提示する>
  def disp_bet(player)
    loop do
      @bet = gets.to_i
      # ¥1〜プレイヤーの所持金のみ入力できる
      if @bet.between?(MINIMUM_AMOUNT_OF_MONEY, player.money)
        @remaining_money = player.bet_money(@bet)
        disp_bet_message
        break
      else
        error_bet_message
      end
    end
  end

  # <2枚のカードを提示する>
  def disp_two_cards
    cards = @master.draw_card(@deck)
      @first_card = cards[0]
      @second_card = cards[1]
  end

  # <最初のカードの数字>
  def first_card_point
    @f_point = []
    @f_point << @first_card.instance_variable_get(:@point)
    @fist_point = @f_point.find { |i| i.integer? }
  end

  # # <次のカードの数字>
  def second_card_point
    @s_point = []
    @s_point << @second_card.instance_variable_get(:@point)
    @second_point = @s_point.find { |i| i.integer? }
  end

  # <highかlowの選択>
  def select_ation
    loop do
      high_low_message
      @select_num = gets.to_i

      case @select_num
      when HIGH_NUMBER
        high_message
        break
      when LOW_NUMBER
        low_message
        break
      else
        error_info_message
      end
    end
  end

  # <判定の条件分岐>
  def judge
    loop do
      case @select_num
      when HIGH_NUMBER
        judge_high
        break
      when LOW_NUMBER
        judge_low
        break
      end
    end
  end

  # <highを選択した場合>
  def judge_high
    if (@win = @select_num == HIGH_NUMBER && second_card_point > first_card_point)
      win_high_message
    elsif (@lose = @select_num == HIGH_NUMBER && first_card_point > second_card_point)
      lose_high_message
    elsif (@draw = @select_num == HIGH_NUMBER && first_card_point == second_card_point)
      draw_game_message
    end
  end

  # <lowを選択した場合>
  def judge_low
    if (@win = @select_num == LOW_NUMBER && first_card_point > second_card_point)
      win_low_message
    elsif (@lose = @select_num == LOW_NUMBER && second_card_point > first_card_point)
      lose_low_message
    elsif (@draw = @select_num == LOW_NUMBER && first_card_point == second_card_point)
      draw_game_message
    end
  end

  # <賭け金の計算>
  def calculate_bet
    if @win
      calculate_win_game
      take_paid_message
    elsif @lose
      calculate_lose_game
    elsif @draw
      calculate_draw_game
    end
      if @player.money <= NO_MONEY
        game_over_message
        exit
      end
  end

  # <勝利時の計算>
  def calculate_win_game
    @paid = @bet * MAGNIFICATION_OF_MONEY
    @remaining_money = @player.add_money(@paid.floor)
  end

  # 敗北時の計算
  def calculate_lose_game
    @paid = @bet
    @remaining_money = @player.bet_money(@paid.floor)
  end

  # <引き分け時の計算>
  def calculate_draw_game
    @remaining_money = @player.add_money(@bet)
  end

  # <次の行動>
  def next_action
    loop do
      next_action_message
      @new_game_num = gets.to_i

      case @new_game_num
      when SELECT_NEW_GAME
        continue_game_message
        break
      when SELECT_STOP_GAME
        stop_game_message
        exit
      else
        error_info_message
      end
    end
  end
end
```

```master.rb
class Master
  def draw_card(deck)
    @card = deck.draw
  end
end
```

```ruby:player.rb
class Player
  attr_reader :money

  # 所持金
  MONEY_IN_POSSESSION = 100_000

  def initialize
    @money = MONEY_IN_POSSESSION
  end

  # お金を賭ける
  def bet_money(bet)
    @money -= bet
  end

  # お金の移動
  def add_money(money)
    @money += money
  end
end
```

```ruby:deck.rb
class Deck
  attr_reader :cards

  # デッキ生成
  def initialize
    @cards = []

    mk = %w[スペード ハート ダイヤ クラブ]
    num = %w[A 2 3 4 5 6 7 8 9 10 J Q K]

    mk.each do |mark|
      num.each do |number|
        card = Card.new(mark, number)
        @cards << card
      end
    end

    @cards.shuffle!
  end

  # カードの取り出し
  def draw
    @cards.shift(2)
  end
end
```

```ruby:card.rb
class Card
  attr_reader :mark, :number, :point

  @@card_point = {
    "A" => 1,
    "2" => 2,
    "3" => 3,
    "4" => 4,
    "5" => 5,
    "6" => 6,
    "7" => 7,
    "8" => 8,
    "9" => 9,
    "10" => 10,
    "J" => 11,
    "Q" => 12,
    "K" => 13
  }

  # トランプ生成
  def initialize(mark, number)
    @mark = mark
    @number = number
    @point = @@card_point.fetch(@number)
  end

  # トランプの種類を提示
  def card_info
    "#{@mark}の#{@number}"
  end
end
```

```ruby:message.rb
module Message
  def start_message
    puts <<~TEXT
      =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
              high_and_low
      =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=

            ~ゲームスタート~
    TEXT
  end

  def give_bet_message(player)
    puts <<~TEXT

      現在の所持金は[＄#{player.money}]です
      賭け金を入力してください
    TEXT
  end

  def disp_bet_message
    puts <<~TEXT
      *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
      賭け金 : ＄#{bet}
      残金 : ＄#{remaining_money}
      *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
    TEXT
  end

  def error_bet_message
    puts <<~TEXT
      ------------------------------------------
      error : 所持金の範囲で数値を入力してください
      ------------------------------------------
    TEXT
  end

  def drow_card_message
    puts <<~TEXT

      カードを2枚引きます。
      1枚目を表示します。

    TEXT
  end

  def disp_card_message
    puts <<~TEXT
      -------------cards--------------
      1枚目 : #{first_card.card_info}
      2枚目 : 伏せている
      -------------cards--------------
    TEXT
  end

  def high_low_message
    puts <<~TEXT

      2枚目のカード値が
      'high' or 'low' であるかを当ててください(数値で入力)

      1.high 2.low
    TEXT
  end

  def high_message
    puts "highですね"
  end

  def low_message
    puts "lowですね"
  end

  def error_info_message
    puts <<~TEXT

      --------------------------------
      error : 1か2を選択してください
      --------------------------------
    TEXT
  end

  def open_card_message
    puts <<~TEXT

      それではカードをめくります

    TEXT
  end

  def number_message
    puts <<~TEXT
      ----------------cards---------------------
      1枚目 :#{first_card.card_info}
      1枚目のカードの数字は[#{first_card_point}]です

      そして

      2枚目のカードの数字は[#{second_card_point}]です
      ----------------cards---------------------
    TEXT
  end

  # <high分岐>
  def win_high_message
    puts "\n2枚目の数字が'高い'ので、highを選んだあなたの勝ちです!"
  end

  def lose_high_message
    puts <<~TEXT

      2枚目の数字が'低い'ので、highを選んだあなたの負けです
      [＄#{bet}]を失いました

    TEXT
  end

  # <low分岐>
  def win_low_message
    puts "\n2枚目の数字が'低い'ので、lowを選んだあなたの勝ちです"
  end

  def lose_low_message
    puts <<~TEXT

      2枚目の数字が'高い'ので、lowを選んだあなたの負けです
      [＄#{bet}]を失いました

    TEXT
  end

  def draw_game_message
    puts "\n引き分けです。賭け金が戻されます"
  end

  def take_paid_message
    puts <<~TEXT

      賭け金が2倍になります！！
      [＄#{paid}]を手に入れました。
    TEXT
  end

  def next_action_message
    puts <<~TEXT

      ゲームを続けますか？

      現在の所持金 : ＄#{remaining_money}
      ---------------------------------

      1.ゲームを続ける 2.やめる
    TEXT
  end

  def continue_game_message
    puts <<~TEXT
      ゲームを続けるですね!!

          ~~NEXT GAME~~
    TEXT
  end

  def stop_game_message
    puts <<~TEXT
      やめるですね。

      あなたは[＄#{remaining_money}]を手に入れました。

      ゲームを終了します
    TEXT
  end

  def game_over_message
    puts <<~TEXT
      所持金が[＄0]になりました。

      *=*=*=*=*=*=*=*=*=*=*
          ゲームオーバー
      *=*=*=*=*=*=*=*=*=*=*
    TEXT
  end
end
```