前回紹介したフィッシュボウルをまた社内でやった. 前回はFizzBuzzがお題だったけど,今回は時間をとれることもあって難易度を上げて,ボウリングのスコア計算がお題になった. おもしろそうなので,同僚が挑戦しているのを横目に自分も Haskell でやってみた.
ちなみに挑戦したペアは2ペアあるけど,2ペアとも最後まで辿りつけなかった. さすがに40分じゃキツいと思う. 自分も割り込み入れつつダラダラやって,トータル3時間くらいかかった.
お題
ボウリングのスコアを計算するプログラムを作成する.
ストライクはX
,スペアは/
,ガーターは-
と表現し,ゲームの結果は以下のように入力される.
XXXXXXXXXXXX #パーフェクト -------------------/5 # 9フレームまでガーターで10フレームでスペア
書いたコード
反省
関数の入力にやたらタプルを使った
別にタプルじゃなくてよかったと思う.
foldl
使ってて素人っぽい
これに関しては気に入らないならreverse
すればいいだけなんだろうけど.
パターンマッチ使いすぎ?
where
でパターンマッチしてとってきたやつを返すってパターンがあんまり綺麗に思えない.
どうやるのがよかったんだろう.
総評
今回はとりあえず Haskell でやってみたけど,がんばってやっただけでいい感じに書けてないと思う. もっといい感じに書けるようになりたい.
以下方針とかはまったことを書いておきます. やろうと思う人は読まないように!
方針
- ボーナスは
(2, 1) = (その投擲, 次の投擲)
みたいに持つ - 投擲ごとに投擲の結果と前の投擲でのトータルスコア,投擲のスコア,ボーナスをとってトータルスコアと投擲のスコア,次のボーナスを計算
- 10フレームはボーナス加算が無いので最後に減算
はまったこと
ある投擲のスコアを計算するには前の投擲のスコアが必要
スペアをとった投擲ではその投擲でのスコアを計算するのに前回の投擲のスコアが必要なことに気づかなくて,計算する関数を書いてる途中に気づいて困った. 関数のインターフェースが変わってしまうし,地味に最初の壁だった.
ボーナスの計算
当初スペアのボーナスとストライクのボーナスを別に考えていてややこしくなってしまった.
特にストライクのボーナスが重複してるときのハンドリングがややこしい.
そこで,方針2のように考えることでボーナスの処理が簡単になった.
ある投擲のボーナスが(b1, b2)
だとすると,次の投擲のボーナスは(b2, 0)
にその投擲で発生したボーナスを加算すればいいだけ.
まとめると下の表になる.
結果 | 次のボーナス |
---|---|
ストライク | (b2 + 1, 1) |
スペア | (b2 + 1, 0) |
それ以外 | (b2, 0) |
10フレーム目の投擲にはボーナスが加算されない
書き終わったーと思ってパーフェクトのパターンを見てみたら330ってなってなんぞってなった. 10フレームだけ別の処理にするってのは面倒でダサいから,10フレームの投擲をとってきて,足しすぎたボーナスを減算することにした.