[Ruby] Rubyのみで、すごろくゲームを作ってみた


Rubyのみで、すごろくゲームを作ってみました。

![画面収録 2021-12-05 17 05 06](https://user-images.githubusercontent.com/78095577/144851808-2e93197d-12db-4560-b699-af073d8c75aa.gif)

今回は大まかに付けた機能ごとに解説していきます。

##開発環境

- ruby 2.7.2

## 使用概要

- エンターキーでプレイヤーがサイコロを振る
- 1~6 のランダムでサイコロの目が表示される
- 出たマス分、駒が移動
- 止まったマスにギミックがあれば表示され、指定されたマスに移動します
- CPU も同じ処理をします
- プレイヤーとCPUの現在のマスの位置を表示
- どちらかが、ゴールのマスに止まったら処理を中断する

##実際に書いてみた

なるべくクラス分けを意識して、同じ処理になるのはまとめております。
まだまだ中途半端なのでアドバイスいただけると嬉しいです。

####diceクラス

diceクラスでサイコロの出た目を表示させます。

```ruby:dice.rb
class Dice

  def disp_dice(dice_number)
    case dice_number
    when 1
      puts <<~text
             ---------
             |       |
             |   *   |
             |       |
             ---------            
           text
    when 2
      puts <<~text             
             ---------
             | *     |
             |       |
             |     * |
             ---------            
           text
    when 3
      puts <<~text           
             ---------
             | *     |
             |   *   |
             |     * |
             ---------           
           text
    when 4
      puts <<~text         
             ---------
             | *   * |
             |       |
             | *   * |
             ---------           
           text
    when 5
      puts <<~text            
             ---------
             | *   * |
             |   *   |
             | *   * |
             ---------           
           text
    else
      puts <<~text           
             ---------
             | *   * |
             | *   * |
             | *   * |
             ---------
           
           text
    end
  end
end
```

####characterクラス

プレイヤーとCPUの同じ処理をcharacterクラスでまとめて処理します。
initializeメソッドに、止まるマス=position、サイコロの出目=dice_number、
後で分かり易いよう、名前=nameも定義しておきます。

```ruby:character.rb
require_relative "dice"
class Character

  attr_reader :dice_number, :name
  attr_accessor :position

  def initialize(name)
    @position = 0
    @dice_number = 0
    @name = name
  end

  def character_position
    @position += @dice_number
  end

  def back_position(map)
    @position = map.max_square - (@position - map.max_square)
  end

end
```

####playerクラス

characterクラスを継承したplayerクラスを作成します。
disp_squereはplayerの現在のマスを表示します。


```ruby:player.rb
class Player < Character

  def roll_dice(dice)
    puts ""
    print "あなたの番です。エンターキーを押してください"
    @dice_number = $stdin.gets.chomp
    @dice_number = rand(1..6)
    dice.disp_dice(@dice_number)
  end
  
  def disp_square(map)
    if @position > 0
      puts "□ " * (@position - 1) + "■ " + "□ " * (map.max_square - @position)
    else
      puts "□ " * map.max_square
    end
  end
end
```

####computerクラス

characterクラスを継承したcomputerクラスを作成します。
こちらのdisp_squereはcomputerの現在のマスを表示します。
playerにもありますが、マスの形を変えているのでそれぞれに表示させています。

```ruby:computer.rb
class Computer < Character

  def roll_dice(dice)
    puts "CPUがサイコロを振ります"
    @dice_number = rand(1..6)
    dice.disp_dice(@dice_number)
  end

  def disp_square(map)
    if @position > 0
      puts "□ " * (@position - 1) + "▲ " + "□ " * (map.max_square - @position)
    else
      puts "□ " * map.max_square
    end
  end
end
```

####mapクラス

mapクラスではinitializeメソッドで、すごろくの合計マス=max_square定義し、
characterが止まったマスにギミックがあれば表示させる処理を書き、移動したマスにpositionを移す処理を書きます。

```ruby:map.rb
require_relative "character"

class Map
  attr_reader :max_square

  def initialize
    @max_square = 30
  end
  
  def activate_gimmick(character)
    case character.position
    when 1
      puts <<~text
             ---------------------------
             |      ==2マス進む==      |
             ---------------------------
           text
    when 3
      puts <<~text
             ---------------------------
             |      ==2マス戻る==      |
             ---------------------------
           text
    when 5
      puts <<~text
             ---------------------------
             |    ==スタートに戻る==   |
             ---------------------------
             スタートに戻りました。
           text
    when 7
      puts <<~text
             ---------------------------
             |     ==2マスすすむ==     |
             ---------------------------
           text
    when 10
      puts <<~text
             ---------------------------
             |     ==5マスすすむ==     |
             ---------------------------
           text
    when 14
      puts <<~text
             ---------------------------
             |      ==7マス戻る==      |
             ---------------------------
           text
    when 17
      puts <<~text
             ---------------------------
             |      ==3マス戻る==      |
             ---------------------------
           text
    when 20
      puts <<~text
             ---------------------------
             |    ==スタートに戻る==   |
             ---------------------------
             スタートに戻りました。
           text
    when 26
      puts <<~text
             ---------------------------
             |    ==スタートに戻る==   |
             ---------------------------
             スタートに戻りました。
           text
    when 28
      puts <<~text
             ---------------------------
             |     ==10マスに戻る==    |
             ---------------------------
           text
    when 29
      puts <<~text
             ---------------------------
             |    ==スタートに戻る==   |
             ---------------------------
             スタートに戻りました。
           text
    else
      puts <<~text
             -------------------------------------
             |     ==何も起こりませんでした==    |
             -------------------------------------
           text
    end
  end

  def change_position(character)
    case character.position
    when 1
      character.position = 3
    when 3
      character.position = 2
    when 5
      character.position = 0
    when 7
      character.position = 4
    when 10
      character.position = 15
    when 14
      character.position = 7
    when 17
      character.position = 14
    when 20
      character.position = 0
    when 26
      character.position = 0
    when 28
      character.position = 18
    when 29
      character.position = 0
    end
  end
end
```

####sugorokuクラス

ここのstartメソッドで全体の動きを書いていきます。

playerかcomputerのどちらかがmax_sqareに到達したら、処理を止め、
make_judgmentメソッドで結果を知らせる処理を書いています。

max_sqareにちょうど止まらない限りは、越えた分また戻る処理もしてますので、少し鬼畜な使用になってます。笑


```ruby:sugoroku.rb
require_relative "map"
require_relative "player"
require_relative "computer"

class Sugoroku

  def start

    @map = Map.new
    @dice = Dice.new
    @player = Player.new("プレイヤー")
    @computer = Computer.new("CPU")

    start_informaition

    loop do

      play_user(@player)
      break if @player.position == @map.max_square
      activated_gimmick(@player)

      play_user(@computer)
      break if @computer.position == @map.max_square
      activated_gimmick(@computer)

      show_map

    end
  end

  def make_judgment
    if @player.position == @map.max_square
      goal_informaition
      puts "ゴールしました！！！あなたの勝ちです！！"
      puts ""
    elsif @computer.position == @map.max_square
      goal_informaition
      puts "CPUがゴールしました。あなたの負けです。"
      puts ""
    end
  end

  private

  def start_informaition
    puts <<~text
           ----------------------------------
           |                                |
           |         すごろくゲーム         |
           |                                |
           ----------------------------------
           ゴールまで#{@map.max_square}マスです
         text
  end

  def goal_informaition
    puts <<~text
           ---------------------------
           |                        |
           |        ==GOAL!==       |
           |                        |
           ---------------------------

         text
  end

  
  def move_forward(character)
    puts <<~text
    サイコロの目は#{character.dice_number}です。
    #{character.dice_number}マス進みます。
    
    text
    character.character_position
    if character.position < @map.max_square
      puts ""
      puts "#{character.position}マス目にとまりました。"
    elsif character.position > @map.max_square
      puts "出た目の数がゴールを#{character.position - @map.max_square}マス分超えました。"
    end
  end
  
  def show_square(character)
    if character.position < @map.max_square
      @map.change_position(character)
      puts <<~text
      現在#{character.name}は、#{character.position}マス目です。
      
      text
    elsif character.position > @map.max_square
      puts <<~text
      ちょうどでなければゴールできません
      #{character.position - @map.max_square}マス戻ります。
      text
      character.back_position(@map)
      puts <<~text
      現在、#{character.position}マス目です。
      
      text
    end
  end
  
  def show_map
    puts "-:-:-:-:-:-:-:-:-:-:-:-現在のコマの位置-:-:-:-:-:-:-:-:-:-:-:-:-:-:"
    puts ""
    puts "プレイヤー：■  CPU:▲ "
           @player.disp_square(@map)
           @computer.disp_square(@map)
    puts ""
    puts "-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:"
  end
  
  def play_user(character)
    character.roll_dice(@dice)
    move_forward(character)
  end
  
  def activated_gimmick(character)
    if character.position < @map.max_square
      @map.activate_gimmick(character)
    end
    show_square(character)
  end
end
```

####mainクラス

最後にmainクラスに動く処理を書いて完成です！

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

sugoroku = Sugoroku.new

sugoroku.start
sugoroku.make_judgment
```

##まとめ

エンターキーをただ連打するだけの運ゲー(笑)ですが、1から自分で作ってみてすごく勉強になりました！
まだまだまとめれる箇所もたくさんあるので少しずつ改善していこうと思います。
最後まで読んでいただいて、ありがとうございました🙇‍♂️