Skip to content

5.リザルト機能を追加する

Suzuki-Takumi0505 edited this page Jun 8, 2022 · 11 revisions

演習5-1

ゲーム終了後に表示させるリザルト画面を作成します。

まず、以下を行なってください。
以下のコードを削除してください。

  • live/game_editor_live.ex
def handle_event("toggle_" <> event, params, socket)
    when event == "select_mode" do
  socket =
    update(socket, :editor, fn editor ->
      GameEditor.update(editor, event, params)
    end)
  if connected?(socket) and socket.assigns.editor.mode in [:training, :game] do
    :timer.send_interval(1000, "timer")
  end

  {:noreply, socket}
end

:timer.send_intrval/2 をマウント時に呼び出すようにします。

  • live/game_editor_live.ex
def mount(_params, _session, socket) do
  socket =
    socket
    |> assign(:editor, GameEditor.construct())
    |> assign(:page_title, "タイピングゲーム")
    |> assign(:template, "main.html")

  if connected?(socket) do
    :timer.send_interval(1000, "timer")
  end

  {:ok, socket}
end

リザルト画面を作成するために以下を実装してください。

  1. Typing.Editor.GameEditor構造体のfailure_count(ゲーム内でミスした回数)をfailure_countsに変更してください。
  2. Typing.Editor.GameEditor構造体に以下の表のキーを追加してください。
  3. Typing.Editor.GameEditor構造体のgame_statsuに3(ゲームクリア)のフラグを追加します。
  4. Typing.Editor.GameEditor構造体のmodeに:result(リザルト)のフラグを追加します。
  5. リザルト画面では、ゲーム全体の時間(練習モードの場合)、クリアした回数、ゲーム全体のミスした回数、入力した内容(お題、結果、入力にかかった時間、ミスした回数)を表示させてください。
キー 値の型
failure_count integer お題でミスした回数
input_time integer お題を入力するのにかかった時間
results リスト お題、実行結果、ミスした回数、入力にかかった時間をマップにしてリストで保存する

【回答】演習5-1

Typing.Editor.GameEditor構造体にキーを追加します。

  • editor/game_editor.ex
defstruct input_char: "",
          display_char: "",
          char_count: 0,
          now_char_count: 0,
          failure_counts: 0,
          game_status: 0,
          char_list: [],
          clear_count: 0,
          result: nil,
          mode: :select,
          timer: 0,
          input_time: 0,
          failure_count: 0,
          results: []

main.html.heex テンプレートの case に :result を追加します。

  • templates/game_editor/main.html.heex
<%=
  case @editor.mode do
    :select -> render "select.html", editor: @editor
    mode when mode in [:training, :game] -> render "game.html", editor: @editor
    :result -> render "result.html", editor: @editor
  end
%>

game.html.heex にゲームが終了したらリザルト画面に移行するボタンを追加します。
ゲーム全体のミスした回数も変更します。

  • templats/game_editor/game.html.heex
<h2>
  <%= if @editor.game_status == 1 do %>
    <span style="color: blue;"><%= @editor.input_char %></span><%= trem_display_char(@editor) %>
  <% else %>
    <%= @editor.display_char %>
  <% end %>
</h2>

<p>クリアした回数:<%= @editor.clear_count %> 回</p>
<p>ミスした回数:<%= @editor.failure_counts %> 回</p>

<h2>実行結果</h2>
<h2><%= if @editor.result, do: inspect(@editor.result), else: "" %></h2>

<%= if @editor.game_status == 2 do %>
  <h1>Enterを押してください</h1>
<% end %>

<h2><%= get_timer_title(@editor) %></h2>
<h2><%= @editor.timer %></h2>

<%= if @editor.game_status == 3 do %>
  <button phx-click="toggle_select_mode" phx-value-mode="result">
    結果を表示
  </button>
<% end %>

<div 
  phx-window-blur="page-inacive"
  phx-window-focus="page-active"
  phx-window-keyup="toggle_input_key">
</div>

editorのselect_modeを変更します。
mode を select にした時に全ての値を最初の状態にします。

  • editor/game_editor.ex
def update(%__MODULE__{} = editor, "select_mode", %{"mode" => "game"}) do
  %{editor | mode: :game, timer: 60, game_status: 1}
end

# trainigを割り当てる
def update(%__MODULE__{} = editor, "select_mode", %{"mode" => mode})
    when mode in ["training", "result"] do
  timer =
    if mode == "result", do: editor.timer, else: 0

  %{editor | mode: String.to_atom(mode), timer: 0, game_status: 1}
end

# game, training どちらでもない場合は select を割り当てる
def update(%__MODULE__{} = editor, "select_mode", _params) do
  char_list =
    [
      "Enum.map([1, 2, 3], fn a -> a * 2 end)",
      "Enum.shuffle([1, 2, 3])",
      "Enum.map([1, 2, 3])"
    ]

  %{
    editor
    | mode: :select,
      failure_counts: 0,
      failure_count: 0,
      game_status: 0,
      clear_count: 0,
      timer: 0,
      results: [],
      char_list: char_list,
      display_char: hd(char_list),
      char_count: String.length(hd(char_list)),
      input_char: "",
      now_char_count: 0,
      input_time: 0
  }
end

リザルト画面を追加します。

  • templates/game_editor/result.html.heex
<h2>結果</h2>

<%= if @editor.timer > 0 do %>
  <h3>経過時間</h3>
  <h3><%= @editor.timer %></h3>
<% end %>

<h3>クリアした回数</h3>
<h3><%= @editor.clear_count %> 回</h3>

<h3>ミスした回数</h3>
<h3><%= @editor.failure_counts %> 回</h3>

<h3>入力した内容</h3>

<%= for result <- @editor.results do %>
  <h3>お題:<%= result.display_char %></h3>
  <h3>結果:<%= inspect(result.result) %></h3>
  <h3>入力にかかった時間:<%= result.time %> 秒</h3>
  <h3>ミスした回数:<%= result.failure_count %> 回</h3>
  <hr>
<% end %>

<button phx-click="toggle_select_mode" phx-value-mode="">
  選択画面に戻る
</button>

ゲームモード時にタイマーが0になった場合に、game_statusを3にするように記述を追加します。

  • editor/game_editor.ex
def update(%__MODULE__{} = editor, "timer")
    when editor.mode == :game and editor.game_status == 1 and editor.timer <= 0 do
  %{
    editor
    | display_char: "終了",
      game_status: 3,
      result: nil,
      failure_count: 0
  }
end

練習モードとゲームモードでinput_timeを+1づつしていくので追加してきます。

  • editor/game_editor.ex
def update(%__MODULE__{} = editor, "timer")
    when editor.mode == :game and editor.game_status == 1 do
  %{editor | timer: editor.timer - 1, input_time: editor.input_time + 1}
end

def update(%__MODULE__{} = editor, "timer")
    when editor.mode == :training and editor.game_status == 1 do
  %{editor | timer: editor.timer + 1, input_time: editor.input_time + 1}
end

練習モード時のゲーム終了の際にgame_statsuを3にします。

  • editor/game_editor.ex
defp next_char(editor, key) do
  char_list = List.delete(editor.char_list, editor.display_char)

  char_list =
    if length(char_list) == 0 and editor.mode == :game do
      list =
        [
          "Enum.map([1, 2, 3])",
          "Enum.map([1, 2, 3], fn a -> a * 2 end)",
          "Enum.shuffile([1, 2, 3])"
        ]

      Enum.shuffle(list)
    else
      char_list
    end

  timer =
    if editor.mode == :game, do: editor.timer + 2, else: editor.timer

  case length(char_list) do
    0 ->
      %{
        editor
        | char_list: char_list,
          display_char: "クリア",
          input_char: editor.input_char <> key,
          game_status: 3,
          result: nil
      }

    _num ->
      display_char = hd(char_list)

      %{
        editor
        | char_list: char_list,
          display_char: display_char,
          input_char: "",
          char_count: String.length(display_char),
          now_char_count: 0,
          game_status: 1,
          result: nil,
          timer: timer,
          input_time: 0
      }
  end
end

お題を入力し終わった際にお題の関数を実行します。 その時にresultsにもお題、実行結果、入力にかかった時間、ミスした回数を追加していきます。

  • editor/game_editor.ex
defp display_result(editor, key) do
  result =
    case Execution.execution(editor.display_char) do
      {r, _} -> r

      error -> error
    end

  results =
    %{
      display_char: editor.display_char,
      time: editor.input_time,
      result: result,
      failure_count: editor.failure_count
    }

  %{
    editor
    | result: result,
      game_status: 2,
      input_char: editor.input_char <> key,
      clear_count: editor.clear_count + 1,
      results: List.insert_at(editor.results, -1, results)
  }
end