はじめに
こんにちは。
一般事務からエンジニアへ転職するために基礎学習しています。
Ruby演習として、VSコード上でRubyのみにて
「Bowling Game ~本日のラッキーボーイ&ガールは一体誰だ!~」
を作成しました。
まだまだひよっこですが、初投稿やってみます。
何を書いたか
ボウリングゲーム の コード (Ruby)
<仕様>
- 実際の球を投げる行為は、毎回、ランダムな数字が生成および表示されて、それを入力(半角数字)することとした。
表示されたランダムな数字と入力した数字が異なる場合は、スコアは0となる。
(スコアを0とさせることで、入力した数字が10以下であるかどうかの判定用コードは作成していない。) - ボウリングゲーム のプレイヤーは何人でも可能である。
- 毎回、ユーザーごとに1投目2投目(10ゲームは3投目がある場合もある)を入力してもらった後、そのゲームまでの表を表示する。
- 合計スコアが確定していない時は、"..."で表示される。
- ストライクとスペアの時は、"ナイスストライク!""ナイススペア!"と表示する。(※1)
- 最後、全員の順位と勝者名が表示される。
- ( = ※1 )
マークの表示切替は今回していない。(マーク:ストライク、スペア、ガーター) - ( = ※2 )
初心者にとっては、完成までは、コードを書換えして、動作が正しいか確認する時に有効的である。また、ゲームを楽しみたい時にも、コードを書換えして、好きな数字を入力して楽しむこともできる。(途中ズルして高い得点にして、逆転することもできるようになる)
なぜ書いたか
Rubyの基礎学習を終了したため、ボウリングゲーム作成してみました。
WEB検索して、Rubyだけで完結しているボウリングゲームを見つけることができなかったため、記事にします。
今回の目的は、とりあえず完成させることを目的としていました。
コードが長くなってしまいましたが、Rubyのみで作成したい初心者の方の力に少しでもなれたらと思います。
本題
VSコード実行方法
tarminal
ruby ~/ファイル場所/bowling_game.rb
完成図
tarminal
ようこそ BowlingGameへ
このBowlingGameのスコアは全てランダムで決定される運ゲーです
※ ここからの数字は、全て半角で入力ください
Let us BowlingGame Start!!
~本日のラッキーボーイ&ガールは一体誰だ!~
プレイヤーの数を入力してください
2
Player1人目の名前を入力してください
エビ
Player2人目の名前を入力してください
カニ
ここから先のスコアは、ランダムで表示されます
表示された数字を入力ください
エビさん 1game 1投目は4です
4
エビさん 1game 2投目は3です
3
+------------------+
| Bowling_Game |
+------+-----------+
| name | game1 |
+------+-----------+
| | 4 | 3 |
| エビ | --------- |
| | 7 |
+------+-----------+
カニさん 1game 1投目は7です
7
カニさん 1game 2投目は1です
1
+------------------+
| Bowling_Game |
+------+-----------+
| name | game1 |
+------+-----------+
| | 7 | 1 |
| カニ | --------- |
| | 8 |
+------+-----------+
エビさん 2game 1投目は10です
10
ナイスストライク!
+------------------------------+
| Bowling_Game |
+------+-----------+-----------+
| name | game1 | game2 |
+------+-----------+-----------+
| | 4 | 3 | 10 | 0 |
| エビ | --------- | --------- |
| | 7 | ... |
+------+-----------+-----------+
カニさん 2game 1投目は5です
5
カニさん 2game 2投目は2です
2
+------------------------------+
| Bowling_Game |
+------+-----------+-----------+
| name | game1 | game2 |
+------+-----------+-----------+
| | 7 | 1 | 5 | 2 |
| カニ | --------- | --------- |
| | 8 | 15 |
+------+-----------+-----------+
エビさん 3game 1投目は5です
5
エビさん 3game 2投目は1です
1
.
.
.
.
エビさん 9game 1投目は0です
0
エビさん 9game 2投目は7です
7
+------------------------------------------------------------------------------------------------------------------+
| Bowling_Game |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| name | game1 | game2 | game3 | game4 | game5 | game6 | game7 | game8 | game9 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| | 4 | 3 | 10 | 0 | 5 | 1 | 6 | 4 | 6 | 3 | 4 | 0 | 4 | 5 | 9 | 1 | 0 | 7 |
| エビ | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- |
| | 7 | 23 | 29 | 45 | 54 | 58 | 67 | 77 | 84 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
カニさん 9game 1投目は6です
6
カニさん 9game 2投目は4です
4
ナイススペア!
+------------------------------------------------------------------------------------------------------------------+
| Bowling_Game |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| name | game1 | game2 | game3 | game4 | game5 | game6 | game7 | game8 | game9 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| | 7 | 1 | 5 | 2 | 9 | 0 | 10 | 0 | 9 | 0 | 1 | 1 | 7 | 3 | 7 | 0 | 6 | 4 |
| カニ | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- |
| | 8 | 15 | 24 | 43 | 52 | 54 | 71 | 78 | ... |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
エビさん 10game 1投目は2です
2
エビさん 10game 2投目は6です
6
+------------------------------------------------------------------------------------------------------------------------------+
| Bowling_Game |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| name | game1 | game2 | game3 | game4 | game5 | game6 | game7 | game8 | game9 | game10 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| | 4 | 3 | 10 | 0 | 5 | 1 | 6 | 4 | 6 | 3 | 4 | 0 | 4 | 5 | 9 | 1 | 0 | 7 | 2 | 6 | 0 |
| エビ | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- |
| | 7 | 17 | 23 | 39 | 48 | 52 | 61 | 71 | 78 | 86 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
カニさん 10game 1投目は2です
2
カニさん 10game 2投目は2です
2
+------------------------------------------------------------------------------------------------------------------------------+
| Bowling_Game |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| name | game1 | game2 | game3 | game4 | game5 | game6 | game7 | game8 | game9 | game10 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| | 7 | 1 | 5 | 2 | 9 | 0 | 10 | 0 | 9 | 0 | 1 | 1 | 7 | 3 | 7 | 0 | 6 | 4 | 2 | 2 | 0 |
| カニ | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- |
| | 8 | 15 | 24 | 34 | 43 | 45 | 62 | 69 | 81 | 85 |
+------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
ゲームエンド!
今回は、エビが勝利しました!
お疲れ様でした。
1位 エビさん (86点)
2位 カニさん (85点)
コード
bowling_game.rb
#terminal-tableという名前のGem(Rubyのパッケージ)を読み込んでいる
#Gemがインストールされていない場合は、このコードを実行する前にgem install terminal-tableなどのコマンドを使ってインストールする必要がある
require 'terminal-table'
#users という名前の変数に、空の配列を割り当てる
#この後のコードで 「user <<」 (<<:配列に要素を追加するための演算子)を活用して、配列に要素を追加させていく
users = []
#ゲーム開始時に表示させる文章
puts "ようこそ BowlingGameへ\n\n
このBowlingGameのスコアは全てランダムで決定される運ゲーです\n
※ ここからの数字は、全て半角で入力ください\n\n
Let's BowlingGame Start!!\n
~本日のラッキーボーイ&ガールは一体誰だ!~\n\n"
# プレイヤーの数を入力
puts "\nプレイヤーの数を入力してください"
num_players = gets.chomp.to_i
num_players.times do |i|
puts "\nPlayer#{i+1}人目の名前を入力してください"
player_name = gets.chomp
#「user << {}」 配列にハッシュを追加していく
#ハッシュ(Hash):キーと値のペアを格納するデータ構造。インデックス番号ではなくキーによって要素にアクセスする
# frame/total_scoreはこの後、配列として使用したいため「[]」で表示させる (total_scoreは最後に勝者を決めるために作成)
# 今後の配列のイメージ frame = [[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0,0]]
# 今後の配列のイメージ total_score = [[0,0,0,......0,0]]
users << { name: player_name , frame: [] , total_score: [] }
end
# プレイ開始
puts "\nここから先のスコアは、ランダムで表示されます\n表示された数字を入力ください\n"
10.times do |j|
users.each do |user|
# ランダムな数字を生成して表示
random_number = rand(0..10)
puts "\n#{user[:name]}さん #{j+1}game 1投目は#{random_number}です"
temporary_score1 = gets.chomp.to_i
# 入力した数字が、生成されたランダムな数字と異なる場合、スコアは0とする
if temporary_score1 != nil
if temporary_score1 != random_number
#(※2) score1 = temporary_score1 と入力したら、好きな数字を入力できる
score1 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
else
score1 = temporary_score1
end
end
#場合分け ( j <= 8 / j == 9 )
#j == 9の時は、frame内のスコアは3つ発生する
#j <= 8 : user[:frame] << [score1,score2]
#j == 9 : user[:frame] << [score1,score2,score3]
if j <= 8
if score1 == 10
score2 = 0
puts "\nナイスストライク!\n\n"
else
# 2投目の場合は、10 - score1までの数字で ランダムな数字を生成して表示
score1_sub = 10 - score1
random_number = rand(0..score1_sub)
puts "\n#{user[:name]}さん #{j+1}game 2投目は#{random_number}です"
temporary_score2 = gets.chomp.to_i
if temporary_score2 != nil
if temporary_score2 != random_number
#(※2) score2 = temporary_score2
score2 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
else
score2 = temporary_score2
if score1 + score2 == 10
puts "\nナイススペア!\n\n"
end
end
end
end
user[:frame] << [score1,score2]
elsif j == 9
if score1 <= 9
score1_sub = 10 - score1
random_number = rand(0..score1_sub)
puts "\n#{user[:name]}さん #{j+1}game 2投目は#{random_number}です"
temporary_score2 = gets.chomp.to_i
if temporary_score2 != nil
if temporary_score2 != random_number
#(※2) score2 = temporary_score2
score2 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
else
score2 = temporary_score2
end
if score1 + score2 <= 9
score3 = 0
elsif score1 + score2 == 10
puts "\nナイススペア!\nボーナスゲーム!\n\n"
random_number = rand(0..10)
puts "\n#{user[:name]}さん #{j+1}game 3投目は#{random_number}です"
temporary_score3 = gets.chomp.to_i
if temporary_score3 != nil
if temporary_score3 != random_number
#(※2) score3 = temporary_score3
score3 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
else
score3 = temporary_score3
end
end
end
end
elsif score1 == 10
puts "\nナイスストライク!\nボーナスゲーム!\n\n"
random_number = rand(0..10)
puts "\n#{user[:name]}さん #{j+1}game 2投目は#{random_number}です"
temporary_score2 = gets.chomp.to_i
if temporary_score2 != nil
if temporary_score2 != random_number
#(※2) score2 = temporary_score2
score2 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
else
score2 = temporary_score2
end
if score2 <= 9
score2_sub = 10 - score2
random_number = rand(0..score2_sub)
puts "\n#{user[:name]}さん #{j+1}game 3投目は#{random_number}です"
temporary_score3 = gets.chomp.to_i
if temporary_score3 != nil
if temporary_score3 != random_number
#(※2) score3 = temporary_score3
score3 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
else
score3 = temporary_score3
end
end
elsif score2 == 10
puts "\nナイスストライク!\nボーナスゲーム!\n\n"
random_number = rand(0..10)
puts "\n#{user[:name]}さん #{j+1}game 3投目は#{random_number}です"
temporary_score3 = gets.chomp.to_i
if temporary_score3 != nil
if temporary_score3 != random_number
#(※2) score3 = temporary_score3
score3 = 0
puts "入力に謝りがありましたため、今回のスコアは 0点 です"
end
else
score3 = temporary_score3
end
end
end
end
user[:frame] << [score1,score2,score3]
end
#表を作成していく
row_data = [] #row_data という名前の変数に、空の配列を割り当てる
frame_before_total = 0 # 前のフレームまでの合計スコアを保持する変数
total_score = 0 # 最終的な合計スコアを保持する変数
#\nを使用して文字が真ん中に来るようにしている
row_data << "\n#{user[:name]}\n\n"
#user[:frame].each_with_index do |frame,index|内で、
#毎回配列が作成される為(毎回全てのindex時の表が作成されることになる)、
#内側にtemporary_table(一時的なtable)を作成して、最後、「table = temporary_table」とすることで
#一番最後のindex時のみがtableとして反映されるようにしている
table = Terminal::Table.new
user[:frame].each_with_index do |frame,index|
framebefore = index >0 ? frame_before_total : 0 #index==0の時は、0となる
framenow = frame.sum
bounus = 0 #ストライクやスペアが出た時の次のフレームの加算点 (初期値は0)
non_frame_total = 0 #合計が確定していない時は、"..."と表示するため、初期値は0としておく
if index <= 8 || (index == 9 && user[:frame].length <= 9)
frame_next = user[:frame].length > 0 ? user[:frame][index+1] : nil
frame_next_after_next = user[:frame].length > 1 ? user[:frame][index+2] : nil
if frame.sum == 10 && frame[0] == 10
if user[:frame].length == 10 && index >= 8
bounus += frame_next[0] + frame_next[1]
elsif user[:frame].length <= 9
bounus += frame_next.sum if frame_next
non_frame_total = "..." unless frame_next
if frame_next && frame_next.sum == 10 && frame_next[0] == 10
bounus += frame_next_after_next[0] if frame_next_after_next
non_frame_total = "..." unless frame_next_after_next
end
end
elsif
frame.sum == 10
bounus += frame_next[0] if frame_next
non_frame_total = "..." unless frame_next
end
# non_frame_totalを初期値0と設定したため、
#その後に、"..."へ上書きされていなければ、frame_total を計算する
frame_total = non_frame_total != 0? non_frame_total : framenow + framebefore + bounus
# スコアの表示方法 2フレーム目以降は横に並べる
if index == 0
row_data << "#{frame[0]} | #{frame[1]}\n---------\n#{frame_total}"
else
row_data << "#{frame[0]} | #{frame[1]}\n---------\n#{frame_total}"
end
# 前のフレームまでの合計スコアを更新
frame_before_total = frame_total
temporary_total_score = frame_total
elsif index == 9 && user[:frame].length == 10
# 10ゲーム目の時は、次のフレームに対するbounusは発生しない
frame_total = framenow + framebefore
# スコアの表示方法 2フレーム目以降は横に並べる(10ゲーム目は3フレームを横に並べる)
row_data << "#{frame[0]} | #{frame[1]} | #{frame[2]}\n---------\n#{frame_total}"
temporary_total_score = frame_total
end
# テーブルの作成と表示
temporary_table = Terminal::Table.new do |t|
t.title = "Bowling_Game"
t.rows = [row_data]
t.headings = ['name'] + (0..index).map { |i| "game#{i+1}" }
# 全体の中央揃えを設定
t.style = {
all_separators: true,
alignment: :center }
end
table = temporary_table
user[:total_score] << temporary_total_score
end
puts table
end
end
#結果発表
#スコアの順位順に並び替え users(変数)の中の total_scoreの配列の最後の値で降順(-w:降順/w:昇順)
#降順となるため、1位の人は、sorted_user_scores[0]が該当する
sorted_user_scores = users.sort_by { |w| -w[:total_score].last }
puts "\nゲームエンド!\n\n今回は、#{sorted_user_scores[0][:name]}が勝利しました!\nお疲れ様でした。\n\n"
#順位発表
#total_scoreの配列の最後の値を表示したいため、「.last」必要
sorted_user_scores.each_with_index do |w,index|
puts "#{index+1}位 #{w[:name]}さん (#{w[:total_score].last}点)"
end
最後に
最後まで読んでいただきありがとうございました!