「第3回 オフラインリアルタイムどう書く」参考問題: へなちょこ解答(Java)
鍋谷さんが第3回の参考問題を出してくださったので、さっそく解きました。
今回は、野球です!
野球のボールカウント・アウトカウントの遷移を計算する。(得点・ランナー・イニング の計算は不要)
ただし、ストライク・ボール・ファウル・ヒット・ピッチャーフライしかない。
細かいルールは下記の通り:オフラインリアルタイムどう書く第三回の参考問題 - Qiita
- ストライクが3つになったらアウトが増え、ストライクとボールがゼロになる。
- ボールが4つになったらフォアボールになり、ストライクとボールがゼロになる。アウトは増えない。
- ヒットを打ったらストライクとボールがゼロになる。アウトは増えない。
- ピッチャーフライを打ったらストライクとボールがゼロになり、アウトが増える。
- アウトが3つになったら、アウト・ストライク・ボール全てゼロになる。
- ファウルの場合、もともとストライクが1以下の場合はストライクが増え、ストライクが2の場合には変化なし。
- 入力は "sbsfbhsshssbbffbbssbs" のように、ひとつながりの文字列として与えられる。
- s, b, f, h, p がそれぞれ ストライク、ボール、ファウル、ヒット、ピッチャーフライ を意味する。
- 出力は、アウト・ストライク・ボールの順にカウントをつなげたものをコンマで区切る。例を参照。
- 不正入力には対処しなくてよい。
- 最終回を超えることも考慮しなくてよい。
面白いですねー。
自分の解答
Javaで解きました。
方針は、こんな感じです。
- 出力となる現在の状態(アウト・ストライク・ボール)をContextクラスで保持する
- 入力のストライク、ボール、ファウル、ヒット、ピッチャーフライをそれぞれクラスで表現し、Playインタフェースを実装させる
- Play#evaluateで、各入力に応じた処理を行う
- Playのデフォルト実装クラスDefaultPlayを、ストライク、ボール、ファウル、ヒット、ピッチャーフライに拡張させる
- DefaultPlay#checkで、スリーアウトをチェックする(
どの入力の時も行うため、このようにしました間違っていました。スリーアウトをチェックすべきは、ストライクとピッチャーフライの時だけでした)
class Context { int out; int strike; int ball; @Override // アウト・ストライク・ボールの順にカウントをつなげたものをコンマで区切る。 public String toString() { StringBuilder sb = new StringBuilder(); sb.append(String.valueOf(out)); sb.append(String.valueOf(strike)); sb.append(String.valueOf(ball)); return new String(sb); } } interface Play { void evaluate(Context con); void check(Context con); } class DefaultPlay implements Play { @Override public void evaluate(Context con) { } @Override // アウトが3つになったら、アウト・ストライク・ボール全てゼロになる。 public void check(Context con) { if (con.out == 3) { con.out = 0; con.strike = 0; con.ball = 0; } } } class Strike extends DefaultPlay implements Play { @Override // ストライクが3つになったらアウトが増え、ストライクとボールがゼロになる。 public void evaluate(Context con) { con.strike++; if (2 < con.strike) { con.out++; con.strike = 0; con.ball = 0; } } } class Ball extends DefaultPlay implements Play { @Override // ボールが4つになったらフォアボールになり、ストライクとボールがゼロになる。アウトは増えない。 public void evaluate(Context con) { con.ball++; if (3 < con.ball) { con.strike = 0; con.ball = 0; } } } class Foul extends DefaultPlay implements Play { @Override // ファウルの場合、もともとストライクが1以下の場合はストライクが増え、ストライクが2の場合には変化なし。 public void evaluate(Context con) { if (con.strike < 2) { con.strike++; } } } class Hit extends DefaultPlay implements Play { @Override // ヒットを打ったらストライクとボールがゼロになる。アウトは増えない。 public void evaluate(Context con) { con.strike = 0; con.ball = 0; } } class PitcherFly extends DefaultPlay implements Play { @Override // ピッチャーフライを打ったらストライクとボールがゼロになり、アウトが増える。 public void evaluate(Context con) { con.strike = 0; con.ball = 0; con.out++; } } /** * 問題: http://qiita.com/items/ebd8a56b41711ba459f9 */ public class BallCount { protected Play convertPlay(char c) { Play result = null; if (c == 's') { result = new Strike(); } else if (c == 'b') { result = new Ball(); } else if (c == 'f') { result = new Foul(); } else if (c == 'h') { result = new Hit(); } else if (c == 'p') { result = new PitcherFly(); } return result; } protected String execute(String input) { Context con = new Context(); String[] tmp = new String[input.length()]; for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); Play play = convertPlay(c); play.evaluate(con); play.check(con); tmp[i] = con.toString(); } StringBuilder result = new StringBuilder(); result.append(tmp[0]); for (int i = 1; i < input.length(); i++) { result.append(','); result.append(tmp[i]); } return new String(result); } public static void main(String[] args) { BallCount count = new BallCount(); System.out.println(count.execute("ssffpffssp")); // 010,020,020,020,100,110,120,200,210,000 // すべてのテストは、https://gist.github.com/3380648を参照。 } }
- 上のコードとテストコード https://gist.github.com/3380648
クラス8個+インタフェース1個はさすがにひどいと思いましたが、後に引けませんでした。
スマートな方法は、ほかの方の解答例でお楽しみください!(^^;
- コメント欄に解答例が並んでいくハズ… http://qiita.com/items/ebd8a56b41711ba459f9