こんにちは、ひろきです。
フィヨルドブートキャンプのプラクティスにボウリングのスコア計算プログラムがあります。 ボウリングスコアのプログラムというと、当初、全然コードが書けなくて、身内にボウリングのルールの話をしたら、「普通、人生でこんなにボウリングのこと考えないよ。面白いね。」と言われたことを思い出します。
ネタバレ防止のためコードはあまり書きません。
作りたいもの
- ボウリングの旧ルールの計算プログラム
- ターミナルで実行したら計算結果が出力される
条件
- 入力は
6,3,9,0,0,3,8,2,7,3,X,9,1,8,0,X,6,4,5このようにする。 ,投球の区切り0-10: 何本倒したかX: ストライク- ストライクの場合は2投目は表記しない。
おそらく、私たちがボウリング場で使っているのが旧ルールです。 ルールがわからない場合は、ググってください。
やりたいこと
- ターミナルでスコアを入力して、それを格納する
Xのような表記を数値に変換する- その数値をフレームとして分ける
- ストライクやスペアの計算を実装する
ざっとこんな感じです。
フィヨルドブートキャンプでは新ルールの方のコードが書いてあるので、そこにあるものは載せます。
ターミナルでスコアを入力して、それを格納する
カレンダーの記事ではoptparseを使いましたが、今回は別の方法です。
ARGVを使います。
Object::ARGV (Ruby 3.3 リファレンスマニュアル)
Rubyスクリプトとはfile.rbのようなファイル名のことです。その引数を文字列の配列にします。
score = ARGV[0] p score
これで、ruby bowl.rb 1,2,3で出力すると
"1,2,3"
で返ります。
一方で、ruby bowl.rb 1 2 3と空白で出力すると
"1"
が返ります。
1,2,3は1つの文字列として認識しているため、上の結果となります。
これで、ターミナルの引数を格納できました。
1つずつの要素にする
今は、引数がそのまま1つの要素になっているので、, を取り除いて配列にします。
[0]で文字列を出力しているので、String#splitのsplit(',')を使って,で区切って分割します。(ちなみに、 [0]がない場合、配列となるので、splitは使えません。)
String#split (Ruby 3.3 リファレンスマニュアル)
split('')は、,も配列に含みます。
score = "1,2,3"
score.split('') # => ["1", ",", "2", ",", "3"]
Xのような表記を数値に変換する
ストライクを取った場合、Xを入力していますが自動的に10にはなりません。
新しい配列を作って、Xが10と0を出力するようにします。
先ほど出来上がった配列に繰り返し処理行って、Xが来たら、10と0を返す、式を考えます。
繰り返しeachと、来たらifで行います。
<<で配列に追加ができます。
Array#<< (Ruby 3.3 リファレンスマニュアル)
shots = []
scores.each do |s|
if s == 'X'
shots << 10
shots << 0
else
shots << s.to_i
end
end
配列になんらかの処理を加えて配列で返す場合、mapメソッドを使用して表すこともできます。
【Ruby】eachとmapの違い #Ruby - Qiita
私の完成作品は上記の記事でいう悪い例でした。笑
今回の場合は、配列の中に配列を返すので、それを1つの配列にする必要があります。
class Array (Ruby 3.3 リファレンスマニュアル)からそれができそうなメソッドを探します。
Enumerable#collect_concat (Ruby 3.3 リファレンスマニュアル)を使って、ifの中を配列にします。もっというと、このifも1行で表せます。
?と:でできますので、チャレンジしてみてください。
一番下にあります。
一旦ここまで
思った以上に長くなってしまったので、今回はこの辺で。
プラクティスの時に取り組んでいた時と違い知識がついていて、嬉しかったです。 これからもマイペースにがんばります。