この記事はCランク記事にこれから挑戦する、初心者向けに書かれた記事です。
言語はRubyで記載しますが他の言語でも考え方は共通です。
途中ネタバレも入りますが、ご了承いただける方はぜひご一読ください。
私自身もまだまだ未経験のエンジニアであるため他に良いコード例などありましたら
ぜひコメントなどで教えてください!!!
Cランク問題の解き方
Cランク問題の感覚
Dランクでは単純にインプットからアウトプットの形式が変わるものや
if文の条件分岐などが発生しても2択で終わるようなものが多いと思いますが
Cランクからは状態の変化や状態の監視が必要になるような感じがします。
最初はこの辺りの値の保持などがややこしいということもあると思いますので
個人的には状況が整理しやすい問題から解いてみると良いと思います。
ということで今回は実際にCランク問題の中でも理解しやすい
野球の審判の問題があったので解いて解説してみます。
問題
問題文
野球の各打者はストライクが 3 つたまるとアウトとなり、ボールが 4 つたまるとフォアボールとなります。
アウトあるいはフォアボールになると、この打者の番は終了します。
あなたはストライクとボールを判定してコールする審判です。
その場の状況に合わせて適切なコールを出しましょう。
【コール一覧】
ストライクが 1 〜 2 つたまったとき → "strike!"
ストライクが 3 つたまったとき → "out!"
ボールが 1 〜 3 つたまったとき → "ball!"
ボールが 4 つたまったとき → "fourball!"
ある打者の番における投球の結果 (ストライクまたはボール) が与えられるので、各投球に対してどのようなコールをすればよいかを出力してください。
なお、実際の野球にあっても上記にないルール (ヒット、ファウルなど) については考慮する必要はありません。
1 球目: ボール → "ball!"
2 球目: ストライク → "strike!"
3 球目: ボール → "ball!"
4 球目: ストライク → "strike!"
5 球目: ストライク → "out!"
5 球目では、ボールが 2 つ、ストライクが 3 つたまったのでこの打者はアウトとなります。
これは、入力例 1 に対応しています。
1 球目: ボール → "ball!"
2 球目: ストライク → "strike!"
3 球目: ボール → "ball!"
4 球目: ボール → "ball!"
5 球目: ストライク → "strike!"
6 球目: ボール → "fourball!"
6 球目では、ストライクが 2 つ、ボールが 4 つたまったのでこの打者はフォアボールとなります。
これは、入力例 2 に対応しています。
どうでしょう?野球といえば日本の国民的なスポーツでもあるかと思うので理解しやすいのではないでしょうか?
ストライク、ボール、アウト、フォアボールいずれもルールとしては理解できます。
つまりあなたは審判でピッチャーが投げたボールの判定と状況に合わせて言い換えを行えばいいです。
入力
入力される値
入力は、以下のフォーマットで与えられます。
N
s_1
s_2
...
s_n
1 行目に合計の投球数を表す整数 N が与えられます。
続く N 行のうち i 行目 (1 ≦ i ≦ N) に i 番目の投球の結果を表す文字列 s_i が与えられます。i 番目の投球がストライクであれば s_i は "strike"、ボールであれば "ball" となります。
入力は合計で N + 1 行からなり、入力値最終行の末尾に改行が1つ入ります。
入力値最終行の末尾に改行が1つ入ります。
文字列は標準入力から渡されます。 標準入力からの値取得方法はこちらをご確認ください
ここから何言ってるの?となるかもしれませんが冷静にみると
N: 野球でいうピッチャーの投げる回数を表します。
s_1 sがscoreとすると1回目に投げた時の判定を入力
s_2 sがscoreとすると2回目に投げた時の判定を入力
・・・ その状況が複数回続きます
s_n sがscoreとするとn回目まで続くことを表します。
ここでいうnは事前にピッチャーが投げる回数が指定されているので
N = nとなります。
ここまででピッチャーが投げる回数は決まっているので
最初に取得した回数分判定を行えば良いということがわかります。
期待する出力
各投球に対する適切なコールを以下の形で出力してください。
c_1
c_2
...
c_N
期待する出力は N 行からなります。
N 行のうちの i 行目 (1 ≦ i ≦ N) に問題文の条件に即して打者へのコールを表す文字列 c_i を "strike!", "ball!", "out!", "fourball!" のいずれかで出力してください。
出力の N 行目の末尾に改行を 1 つ入れ、余計な文字、空行を含んではいけません。
ここでは'strike'など入力で受け取ったものの判定後の出力について書かれています。
'strike'や'ball'などはそのまま出力するわけではなく'strike!','ball!'となります。
また野球と同じようにスコアに応じて'out!','fourball'という出力が求められます。
入力で受け取ったものをそのまま出すわけではないので注意しましょう!
条件
すべてのテストケースにおいて、以下の条件をみたします。
3 ≦ N ≦ 6
s_i (1 ≦ i ≦ N) は英字小文字で構成される文字列で、"strike", "ball" のいずれか。
投球はこの打者の番がちょうど終了するまで続きます。すなわち、最終的にこの打者にはアウトかフォアボールのいずれかが必ず与えられ、それ以降の投球はおこなわれません。
投球回数は野球でいう打席が終わるまでの回数になります。
野球のようにファールはないのでストライクが成立する最低3回、最大でも6回までに
判定が出るようになります。
入力例・出力例
入力例1
5
ball
strike
ball
strike
strike
出力例1
ball!
strike!
ball!
strike!
out!
入力例2
6
ball
strike
ball
ball
strike
ball
出力例2
ball!
strike!
ball!
ball!
strike!
fourball!
このように入力例と出力例が出てきますが、この出力例を見ることで理解しやすいかと思います。
問題を読んでも理解できない方は最初はこの入力・出力の例と
問題のどこが一致するのかを見比べながら読むとわかりやすいでしょう。
ここからはネタバレ私の回答になります。
もしこのまま自分で解いてみたい方は問題に移り是非解いてみてください。
下の回答を選択すると私の回答を見ることができます。
私の回答
N = gets.chomp.to_i #ピッチャーの投球回数を取得
s_count, b_count = 0, 0 #各投球後のカウントを保存する変数を用意。ストライクとボールをそれぞれ分けて保存。
N.times do #ピッチャーの投球回数分だけ繰り返し動作を行う
score = gets.chomp #ピッチャーが投げるごとに(入力ごとに)scoreを取得
case score #今回は条件分岐にcase文を使用
when 'strike' #scoreの状態がstrikeの時実行
s_count += 1 #まずはストライクのカウントを行う
puts score == 'strike' && s_count < 3 ? 'strike!' : 'out!'
#審判がストライクと言うが如くputsで出力する putsで出力することで改行も行える。
when 'ball' #scoreの状態がballの時実行
b_count += 1 #まずはボールのカウントを行う
puts score == 'ball' && b_count < 4 ? 'ball!' : 'fourball!'
#審判がボールと言うが如くputsで出力する putsで出力することで改行も行える。
end
end
このように整理してみると実際に野球の試合に行われているものと変わりありません。
Point
一つ一つの動作を理解できるものから取り込むと 言語化しやすくコードに落としやすくなってきます。
まずは自分の理解できる事象から取り組んでいき
何度も取り組んでいると同じような入力の受け取り方や
出力方できるものがわかってくるので
Cランク問題でもすんなりと解けるようになってくるでしょう。
また今回はわかりやすいようにcase文を使っていますが
まだまだリファクタリングを行い文章を見やすくしたりすることもできますので
何度かコードを書き換えて、より簡潔にかける方法などを探すと
便利なメソッドなども見つかり勉強になります。
最後に
私の解き方ということで一例を挙げてみましたが
まだまだスキルが足らないのでこれからも精進していきます。
みんなで頑張りましょう!