Powered by AppSignal & Oban Pro

闘魂Elixir ── ボーリングの点数計算をElixirで楽しむ

notebooks/toukonex/bowling.livemd

闘魂Elixir ── ボーリングの点数計算をElixirで楽しむ

About

Answer

defmodule BowlingGameKata do
  def score!(frames), do: do_score(frames, false, [], 0)

  def do_score([], _spared, _strikes, score_acc), do: score_acc

  def do_score([frame | rest], spared, strikes, score_acc) do
    new_score_acc = score_acc + calc_score(frame, spared, strikes)

    do_score(
      rest,
      spare?(frame),
      update_strikes(frame, strikes),
      new_score_acc
    )
  end

  defp calc_score({10}, true, []), do: 10 + 10
  defp calc_score({10}, false, []), do: 0
  defp calc_score({10}, false, [10]), do: 0
  defp calc_score({10}, false, [10, 10]), do: 30
  defp calc_score({a, b, c}, true, []), do: 10 + a + (a + b + c)
  defp calc_score({a, b, c}, false, []), do: a + b + c
  defp calc_score({a, b, c}, false, [10]), do: 10 + a + b + (a + b + c)
  defp calc_score({a, b, c}, false, [10, 10]), do: 10 + 10 + a + (10 + a + b) + (a + b + c)
  defp calc_score({a, b}, true, []) when a + b == 10, do: 10 + a
  defp calc_score({a, b}, false, []) when a + b == 10, do: 0
  defp calc_score({a, b}, false, [10]) when a + b == 10, do: 10 + a + b
  defp calc_score({a, b}, false, [10, 10]) when a + b == 10, do: 10 + 10 + a + (10 + a + b)
  defp calc_score({a, b}, true, []), do: 10 + a + (a + b)
  defp calc_score({a, b}, false, []), do: a + b
  defp calc_score({a, b}, false, [10]), do: 10 + a + b + (a + b)
  defp calc_score({a, b}, false, [10, 10]), do: 10 + 10 + a + (10 + a + b) + (a + b)

  defp spare?({a, b}) when a + b == 10, do: true
  defp spare?(_), do: false

  defp update_strikes({10}, []), do: [10]
  defp update_strikes({10}, [10]), do: [10, 10]
  defp update_strikes({10}, [10, 10]), do: [10, 10]
  defp update_strikes(_, []), do: []
  defp update_strikes(_, [10]), do: []
  defp update_strikes(_, [10, 10]), do: []
end

## Test 

ExUnit.start(auto_run: false)

defmodule BowlingGameKataTest do
  use ExUnit.Case, async: false

  test "all 0" do
    list = List.duplicate({0, 0}, 10)
    assert BowlingGameKata.score!(list) == 0
  end

  test "all 1" do
    list = List.duplicate({1, 1}, 10)
    assert BowlingGameKata.score!(list) == 20
  end

  test "spare" do
    list = [{5, 5}, {3, 0}] ++ List.duplicate({0, 0}, 8)
    assert BowlingGameKata.score!(list) == 16
  end

  test "strike" do
    list = [{10}, {3, 4}] ++ List.duplicate({0, 0}, 8)
    assert BowlingGameKata.score!(list) == 24
  end

  test "perfect game" do
    list = List.duplicate({10}, 9) ++ [{10, 10, 10}]
    assert BowlingGameKata.score!(list) == 300
  end

  test "scoring bowling 1" do
    list = [{1, 4}, {4, 5}, {6, 4}, {5, 5}, {10}, {0, 1}, {7, 3}, {6, 4}, {10}, {2, 8, 6}]
    assert BowlingGameKata.score!(list) == 133
  end

  test "scoring bowling 2" do
    list = List.duplicate({1, 1}, 9) ++ [{1, 9, 1}]
    assert BowlingGameKata.score!(list) == 29
  end

  test "scoring bowling 3" do
    # https://hideo002.com/archives/5639
    list = [{3, 5}, {6, 1}, {3, 2}, {7, 1}, {10}, {9, 1}, {10}, {10}, {2, 5}, {2, 8, 3}]
    assert BowlingGameKata.score!(list) == 127
  end

  test "scoring bowling 4" do
    # https://nageyo.com/score/
    list = [{9, 1}, {8, 0}, {10}, {10}, {9, 0}, {10}, {10}, {10}, {7, 3}, {9, 1, 10}]
    assert BowlingGameKata.score!(list) == 199
  end

  test "scoring bowling 5" do
    # https://codezine.jp/article/detail/13320
    list = [{6, 4}, {8, 0}, {10}, {2, 7}, {5, 5}, {3, 4}, {10}, {9, 1}, {1, 2}, {7, 1}]
    assert BowlingGameKata.score!(list) == 116
  end

  test "scoring bowling 6" do
    # https://codezine.jp/article/detail/13320
    list = [{1, 8}, {9, 1}, {7, 2}, {10}, {0, 0}, {9, 1}, {3, 6}, {8, 0}, {5, 4}, {10, 8, 1}]
    assert BowlingGameKata.score!(list) == 103
  end

  test "scoring bowling 7" do
    list = List.duplicate({0, 0}, 7) ++ [{10}, {10}, {10, 10, 0}]
    assert BowlingGameKata.score!(list) == 80
  end

  test "scoring bowling 8" do
    list = List.duplicate({0, 0}, 7) ++ [{10}, {10}, {5, 5, 0}]
    assert BowlingGameKata.score!(list) == 55
  end

  test "scoring bowling 9" do
    list = List.duplicate({0, 0}, 7) ++ [{10}, {10}, {0, 0}]
    assert BowlingGameKata.score!(list) == 30
  end

  test "scoring bowling 10" do
    list = List.duplicate({0, 0}, 7) ++ [{10}, {5, 5}, {10, 10, 0}]
    assert BowlingGameKata.score!(list) == 60
  end

  test "scoring bowling 11" do
    list = List.duplicate({0, 0}, 7) ++ [{10}, {5, 5}, {5, 5, 0}]
    assert BowlingGameKata.score!(list) == 45
  end

  test "scoring bowling 12" do
    list = List.duplicate({0, 0}, 7) ++ [{10}, {5, 5}, {0, 0}]
    assert BowlingGameKata.score!(list) == 30
  end

  test "scoring bowling 13" do
    list = List.duplicate({0, 0}, 7) ++ [{5, 5}, {10}, {10, 10, 0}]
    assert BowlingGameKata.score!(list) == 70
  end

  test "scoring bowling 14" do
    list = List.duplicate({0, 0}, 7) ++ [{5, 5}, {10}, {5, 5, 0}]
    assert BowlingGameKata.score!(list) == 50
  end

  test "scoring bowling 15" do
    list = List.duplicate({0, 0}, 7) ++ [{5, 5}, {10}, {0, 0}]
    assert BowlingGameKata.score!(list) == 30
  end

  test "scoring bowling 16" do
    list = List.duplicate({0, 0}, 8) ++ [{5, 5}, {10, 10, 0}]
    assert BowlingGameKata.score!(list) == 40
  end

  test "scoring bowling 17" do
    list = List.duplicate({0, 0}, 8) ++ [{5, 5}, {5, 5, 0}]
    assert BowlingGameKata.score!(list) == 25
  end

  test "scoring bowling 18" do
    list = List.duplicate({0, 0}, 8) ++ [{5, 5}, {0, 0}]
    assert BowlingGameKata.score!(list) == 10
  end

  test "scoring bowling 19" do
    list = List.duplicate({0, 0}, 9) ++ [{10, 10, 0}]
    assert BowlingGameKata.score!(list) == 20
  end

  test "scoring bowling 20" do
    list = List.duplicate({0, 0}, 9) ++ [{5, 5, 0}]
    assert BowlingGameKata.score!(list) == 10
  end

  test "scoring bowling 21" do
    list = List.duplicate({0, 0}, 9) ++ [{0, 0}]
    assert BowlingGameKata.score!(list) == 0
  end
end

ExUnit.run()