Ruby練習問題4-☆2:ナインゲームを作ろう

記事内に商品プロモーションを含む場合があります

Rubyの初心者向け問題4-☆2:ナインゲームを作ろう

この問題を解くために必要な知識:
【レベル1~3の知識】
コメントの書き方、変数と定数、基本データ型、四則演算と演算子、入力と出力、文字列操作、分岐処理(if、if~else、elsif、case)、繰り返し処理(for、while、until、each)、範囲(Range)、例外処理(begin-rescue-end)、配列(Array)、ハッシュ(Hash)、コレクション操作(配列、ハッシュの操作)、Enumerableモジュール、メソッドの定義と呼び出し、メソッドの戻り値、クラスの定義と使用、コンストラクタ、クラスの継承、モジュールの定義と使用、ミックスイン

【レベル4の知識】
アクセスメソッド(ゲッター、セッター)、カプセル化、クラスメソッドとインスタンスメソッド、共通メソッド、ブロックとイテレータ、プロック(Proc)、ラムダ(Lambda)、ファイル操作(読み書き)、正規表現、メタプログラミングの基礎

<<前の問題 問題集Top 次の問題>>

Ruby練習問題4-☆2:ナインゲームを作ろう

ナインゲームはプレイヤーとコンピュータが対戦するゲームです。

プレイヤーとコンピュータは最初に1から9までの9枚の牌を持ち、順番に一つずつ選びます。大きい数字の牌を出した方にその数字と同じ数の得点が入ります。

両者の持っている牌がなくなるまで勝負を続け、最終的により多くの得点を持っていた方が勝利となります。

この問題の要件

以下の要件に従ったプログラムを作成すること。

  • プレイヤーとコンピュータの得点を初期化する変数を作成すること。
  • プレイヤーとコンピュータの持ち牌を配列として初期化すること。
  • プレイヤーとコンピュータの使用済み牌を格納するための配列を作成すること。
  • ゲームの開始を知らせるメッセージを表示すること。
  • 9回の勝負を繰り返すためのループを作成すること。
  • 各ラウンドの開始時に現在の得点と持ち牌を表示すること。
  • プレイヤーが有効な牌を選択するまで繰り返し入力を求める処理を作成すること。
  • コンピュータがランダムに牌を選択する処理を作成すること。
  • 選択した牌を使用済み牌の配列に追加すること。
  • 選択した牌の数字を比較し、勝者を決定し得点を加算すること。
  • 最終結果を表示し、勝者を決定すること。

ただし、以下のような実行結果となること。

----- ↓出力される結果の例↓ -----

ナインゲームを開始します!

【第1回戦】
プレイヤーの得点 :0点
コンピュータの得点:0点
プレイヤーの持ち牌 ⇒ [1, 2, 3, 4, 5, 6, 7, 8, 9]
コンピュータの持ち牌⇒ [1, 2, 3, 4, 5, 6, 7, 8, 9]
持ち牌の中から出す牌を選択してください > 9
プレイヤーの打牌:9 > 5:コンピュータの打牌
プレイヤーは9点獲得

【第2回戦】
プレイヤーの得点 :9点
コンピュータの得点:0点
プレイヤーの持ち牌 ⇒ [1, 2, 3, 4, 5, 6, 7, 8, -]
コンピュータの持ち牌⇒ [1, 2, 3, 4, -, 6, 7, 8, 9]
持ち牌の中から出す牌を選択してください > 
...

----- ↑出力される結果の例↑ -----

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは以下のような構成となっています。

1.ナインゲームを開始するプログラム
 1-1.プレイヤーとコンピュータの得点を初期化する
  1-1-1.player_score = 0:プレイヤーの得点を0で初期化する
  1-1-2.computer_score = 0:コンピュータの得点を0で初期化する
 1-2.プレイヤーとコンピュータの持ち牌を初期化する
  1-2-1.player_tiles = (1..9).to_a:プレイヤーの持ち牌を1から9までの配列で初期化する
  1-2-2.computer_tiles = (1..9).to_a:コンピュータの持ち牌を1から9までの配列で初期化する
 1-3.プレイヤーとコンピュータの使用済み牌を格納する配列を初期化する
  1-3-1.player_used_tiles = []:プレイヤーの使用済み牌を格納する空の配列を作成する
  1-3-2.computer_used_tiles = []:コンピュータの使用済み牌を格納する空の配列を作成する
 1-4.ゲーム開始のメッセージを表示する
  1-4-1.puts “ナインゲームを開始します!”:ゲーム開始のメッセージを表示する
2.9回の勝負を行う
 2-1.繰り返し処理を9回行うためのeach文
  2-1-1.ラウンド開始のメッセージを表示する
   2-1-1-1.puts “\n【第#{round}回戦】”:ラウンド開始のメッセージを表示する
  2-1-2.現在の得点を表示する
   2-1-2-1.puts “プレイヤーの得点 :#{player_score}点”:プレイヤーの得点を表示する
   2-1-2-2.puts “コンピュータの得点:#{computer_score}点”:コンピュータの得点を表示する
  2-1-3.現在の持ち牌を表示する
   2-1-3-1.def display_tiles(tiles, used_tiles):持ち牌を表示するメソッドを定義する
   2-1-3-2.tiles.map { |tile| used_tiles.include?(tile) ? ‘-‘ : tile }.join(‘, ‘):使用済み牌を’-‘で表示する
   2-1-3-3.puts “プレイヤーの持ち牌 ⇒ [#{display_tiles(player_tiles, player_used_tiles)}]”:プレイヤーの持ち牌を表示する
   2-1-3-4.puts “コンピュータの持ち牌⇒ [#{display_tiles(computer_tiles, computer_used_tiles)}]”:コンピュータの持ち牌を表示する
  2-1-4.プレイヤーが出す牌を選択する
   2-1-4-1.print “持ち牌の中から出す牌を選択してください > “:プレイヤーに牌の選択を促す
   2-1-4-2.player_choice = gets.to_i:プレイヤーが選択した牌を取得する
   2-1-4-3.until (player_tiles – player_used_tiles).include?(player_choice):有効な牌を選択するまで繰り返す
   2-1-4-4.print “無効な選択です。もう一度選択してください > “:無効な選択をした場合再入力を促す
  2-1-5.コンピュータがランダムに牌を選択する
   2-1-5-1.computer_choice = (computer_tiles – computer_used_tiles).sample:コンピュータがランダムに牌を選択する
  2-1-6.選択した牌を使用済み牌に追加する
   2-1-6-1.player_used_tiles << player_choice:プレイヤーの使用済み牌に追加する
   2-1-6-2.computer_used_tiles << computer_choice:コンピュータの使用済み牌に追加する
  2-1-7.選択した牌を表示する
   2-1-7-1.puts “プレイヤーの打牌:#{player_choice} > #{computer_choice}:コンピュータの打牌”:選択した牌を表示する
  2-1-8.勝者を決定し、得点を追加する
   2-1-8-1.if player_choice > computer_choice:プレイヤーの牌が大きい場合
   2-1-8-2.player_score += player_choice:プレイヤーの得点を追加する
   2-1-8-3.puts “プレイヤーは#{player_choice}点獲得”:プレイヤーが得点を獲得したことを表示する
   2-1-8-4.elsif computer_choice > player_choice:コンピュータの牌が大きい場合
   2-1-8-5.computer_score += computer_choice:コンピュータの得点を追加する
   2-1-8-6.puts “コンピュータは#{computer_choice}点獲得”:コンピュータが得点を獲得したことを表示する
   2-1-8-7.else:引き分けの場合
   2-1-8-8.puts “引き分けです”:引き分けを表示する
3.最終得点を表示し、勝者を決定する
 3-1.最終得点を表示する
  3-1-1.puts “\n最終結果”:最終結果の表示を行う
  3-1-2.puts “プレイヤーの得点 :#{player_score}点”:プレイヤーの最終得点を表示する
  3-1-3.puts “コンピュータの得点:#{computer_score}点”:コンピュータの最終得点を表示する
 3-2.勝者を決定する
  3-2-1.if player_score > computer_score:プレイヤーの得点が多い場合
  3-2-2.puts “プレイヤーの勝利です!”:プレイヤーの勝利を表示する
  3-2-3.elsif computer_score > player_score:コンピュータの得点が多い場合
  3-2-4.puts “コンピュータの勝利です!”:コンピュータの勝利を表示する
  3-2-5.else:引き分けの場合
  3-2-6.puts “引き分けです!”:引き分けを表示する

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させてください。

# ナインゲームを開始するプログラム

# プレイヤーとコンピュータの得点を初期化
player_score = 0
computer_score = 0

# プレイヤーとコンピュータの持ち牌を初期化
player_tiles = (1..9).to_a
computer_tiles = (1..9).to_a

# プレイヤーとコンピュータの使用済み牌を格納する配列
player_used_tiles = []
computer_used_tiles = []

# ゲーム開始のメッセージ
puts "ナインゲームを開始します!"

# 9回の勝負を行う
(1..9).each do |round|
  puts "\n【第#{round}回戦】"
  
  # 現在の得点を表示
  puts "プレイヤーの得点 :#{player_score}点"
  puts "コンピュータの得点:#{computer_score}点"

  # 現在の持ち牌を表示
  def display_tiles(tiles, used_tiles)
    tiles.map { |tile| used_tiles.include?(tile) ? '-' : tile }.join(', ')
  end
  
  puts "プレイヤーの持ち牌 ⇒ [#{display_tiles(player_tiles, player_used_tiles)}]"
  puts "コンピュータの持ち牌⇒ [#{display_tiles(computer_tiles, computer_used_tiles)}]"
  
  # プレイヤーが出す牌を選択
  print "持ち牌の中から出す牌を選択してください > "
  player_choice = gets.to_i

  # ***ここでプレイヤーが有効な牌を出すまで繰り返す処理を追加してください。***
  until (player_tiles - player_used_tiles).include?(player_choice)
    print "無効な選択です。もう一度選択してください > "
    player_choice = gets.to_i
  end
  
  # ***ここでコンピュータがランダムに牌を選択する処理を追加してください。***
  computer_choice = (computer_tiles - computer_used_tiles).sample
  
  # 選択した牌を使用済み牌に追加
  player_used_tiles << player_choice
  computer_used_tiles << computer_choice
  
  # 選択した牌を表示
  puts "プレイヤーの打牌:#{player_choice} > #{computer_choice}:コンピュータの打牌"
  
  # ***ここでプレイヤーとコンピュータの牌を比較して勝者を決定し、得点を追加する処理を追加してください。***
  if player_choice > computer_choice
    player_score += player_choice
    puts "プレイヤーは#{player_choice}点獲得"
  elsif computer_choice > player_choice
    computer_score += computer_choice
    puts "コンピュータは#{computer_choice}点獲得"
  else
    puts "引き分けです"
  end
end

# 最終得点を表示し、勝者を決定
puts "\n最終結果"
puts "プレイヤーの得点 :#{player_score}点"
puts "コンピュータの得点:#{computer_score}点"

# ***ここでプレイヤーの得点とコンピュータの得点を比較し、勝者を表示する処理を追加してください。***
if player_score > computer_score
  puts "プレイヤーの勝利です!"
elsif computer_score > player_score
  puts "コンピュータの勝利です!"
else
  puts "引き分けです!"
end

 

この問題の解答例

例えば以下のようなプログラムが考えられます。

********************

# ナインゲームを開始するプログラム

# プレイヤーとコンピュータの得点を初期化
player_score = 0
computer_score = 0

# プレイヤーとコンピュータの持ち牌を初期化
player_tiles = (1..9).to_a
computer_tiles = (1..9).to_a

# プレイヤーとコンピュータの使用済み牌を格納する配列
player_used_tiles = []
computer_used_tiles = []

# ゲーム開始のメッセージ
puts "ナインゲームを開始します!"

# 9回の勝負を行う
(1..9).each do |round|
  puts "\n【第#{round}回戦】"
  
  # 現在の得点を表示
  puts "プレイヤーの得点 :#{player_score}点"
  puts "コンピュータの得点:#{computer_score}点"

  # 現在の持ち牌を表示
  def display_tiles(tiles, used_tiles)
    tiles.map { |tile| used_tiles.include?(tile) ? '-' : tile }.join(', ')
  end
  
  puts "プレイヤーの持ち牌 ⇒ [#{display_tiles(player_tiles, player_used_tiles)}]"
  puts "コンピュータの持ち牌⇒ [#{display_tiles(computer_tiles, computer_used_tiles)}]"
  
  # プレイヤーが出す牌を選択
  print "持ち牌の中から出す牌を選択してください > "
  player_choice = gets.to_i

  # プレイヤーが有効な牌を出すまで繰り返す
  until (player_tiles - player_used_tiles).include?(player_choice)
    print "無効な選択です。もう一度選択してください > "
    player_choice = gets.to_i
  end
  
  # コンピュータがランダムに牌を選択
  computer_choice = (computer_tiles - computer_used_tiles).sample
  
  # 選択した牌を使用済み牌に追加
  player_used_tiles << player_choice
  computer_used_tiles << computer_choice
  
  # 選択した牌を表示
  puts "プレイヤーの打牌:#{player_choice} > #{computer_choice}:コンピュータの打牌"
  
  # 勝者を決定し、得点を追加
  if player_choice > computer_choice
    player_score += player_choice
    puts "プレイヤーは#{player_choice}点獲得"
  elsif computer_choice > player_choice
    computer_score += computer_choice
    puts "コンピュータは#{computer_choice}点獲得"
  else
    puts "引き分けです"
  end
end

# 最終得点を表示し、勝者を決定
puts "\n最終結果"
puts "プレイヤーの得点 :#{player_score}点"
puts "コンピュータの得点:#{computer_score}点"

if player_score > computer_score
  puts "プレイヤーの勝利です!"
elsif computer_score > player_score
  puts "コンピュータの勝利です!"
else
  puts "引き分けです!"
end

********************

正解のコードの解説

このRubyコードは、プレイヤーとコンピュータが9回戦で勝負する「ナインゲーム」を実装しています。各ブロックに分けて、コードの動作を詳しく解説していきます。

ゲームの初期設定

# プレイヤーとコンピュータの得点を初期化
player_score = 0
computer_score = 0

# プレイヤーとコンピュータの持ち牌を初期化
player_tiles = (1..9).to_a
computer_tiles = (1..9).to_a

# プレイヤーとコンピュータの使用済み牌を格納する配列
player_used_tiles = []
computer_used_tiles = []
  • 得点の初期化: player_scorecomputer_scoreでそれぞれプレイヤーとコンピュータの得点を管理しています。最初はどちらも0点です。
  • 持ち牌の初期化: player_tilescomputer_tilesには1から9までの数字(牌)が格納されています。これらはお互いに使用可能な牌を表しています。
  • 使用済み牌の初期化: player_used_tilescomputer_used_tilesには、プレイヤーとコンピュータが既に使った牌が記録されます。

ゲーム開始のメッセージ

# ゲーム開始のメッセージ
puts "ナインゲームを開始します!"

ここでゲームの開始を告げるメッセージが表示されます。

各ラウンドの処理

(1..9).each do |round|
  puts "\n【第#{round}回戦】"

ゲームは9回戦行われます。このループでは、1回戦から9回戦まで繰り返され、それぞれのラウンドを表すround変数が設定されます。

得点と持ち牌の表示

# 現在の得点を表示
puts "プレイヤーの得点 :#{player_score}点"
puts "コンピュータの得点:#{computer_score}点"

# 現在の持ち牌を表示
def display_tiles(tiles, used_tiles)
  tiles.map { |tile| used_tiles.include?(tile) ? '-' : tile }.join(', ')
end
puts "プレイヤーの持ち牌 ⇒ [#{display_tiles(player_tiles, player_used_tiles)}]"
puts "コンピュータの持ち牌⇒ [#{display_tiles(computer_tiles, computer_used_tiles)}]"
  • 得点の表示: 各ラウンド開始時に、プレイヤーとコンピュータの得点が表示されます。
  • 持ち牌の表示: display_tilesメソッドを使って、プレイヤーとコンピュータの現在の持ち牌が表示されます。既に使った牌は「-」で表現され、使える牌が表示されます。

プレイヤーの選択と検証

# プレイヤーが出す牌を選択
print "持ち牌の中から出す牌を選択してください > "
player_choice = gets.to_i

# プレイヤーが有効な牌を出すまで繰り返す
until (player_tiles - player_used_tiles).include?(player_choice)
  print "無効な選択です。もう一度選択してください > "
  player_choice = gets.to_i
end

プレイヤーが1から9の中から牌を選びますが、既に使った牌を選ぶことはできません。もし無効な牌を選んだ場合、再度選び直すよう促されます。

コンピュータの選択

# コンピュータがランダムに牌を選択
computer_choice = (computer_tiles - computer_used_tiles).sample

コンピュータは使用可能な牌の中からランダムに1枚選びます。

牌の表示と得点の加算

# 選択した牌を使用済み牌に追加
player_used_tiles << player_choice
computer_used_tiles << computer_choice

# 選択した牌を表示
puts "プレイヤーの打牌:#{player_choice} > #{computer_choice}:コンピュータの打牌"

# 勝者を決定し、得点を追加
if player_choice > computer_choice
  player_score += player_choice
  puts "プレイヤーは#{player_choice}点獲得"
elsif computer_choice > player_choice
  computer_score += computer_choice
  puts "コンピュータは#{computer_choice}点獲得"
else
  puts "引き分けです"
end
  • 使用済み牌の追加: プレイヤーとコンピュータが選んだ牌は、それぞれplayer_used_tilescomputer_used_tilesに追加されます。
  • 結果の表示: どちらが選んだ牌が大きいかによって勝敗が決まり、勝者がその牌の点数を得ます。同点の場合は引き分けです。

最終結果の表示

# 最終得点を表示し、勝者を決定
puts "\n最終結果"
puts "プレイヤーの得点 :#{player_score}点"
puts "コンピュータの得点:#{computer_score}点"

if player_score > computer_score
  puts "プレイヤーの勝利です!"
elsif computer_score > player_score
  puts "コンピュータの勝利です!"
else
  puts "引き分けです!"
end

9回戦が終了した後、最終的な得点が表示され、プレイヤーとコンピュータのどちらが勝者か、または引き分けかが表示されます。

まとめ

このプログラムでは、Rubyの基本的な構文(条件分岐、ループ、メソッド定義、配列操作など)を学びながら、ゲームを通じてプログラミングを体験できます。

<<前の問題 問題集Top 次の問題>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Ruby練習問題集へ戻る
    トップページへ戻る