diff --git a/lib/chess/board.ex b/lib/chess/board.ex index 204c887..3a55d22 100644 --- a/lib/chess/board.ex +++ b/lib/chess/board.ex @@ -30,13 +30,20 @@ defmodule Chess.Board do board["#{file},#{rank}"] end - def move_piece(board, move_params) do - [from_file, from_rank] = move_params["from"] - [to_file, to_rank] = move_params["to"] + def move_piece(board, %{"from" => from, "to" => to}) do + [from_file, from_rank] = from + [to_file, to_rank] = to {piece, board} = Map.pop(board, "#{from_file},#{from_rank}") + {piece_captured, board} = Map.pop(board, "#{to_file},#{to_rank}") - Map.put(board, "#{to_file},#{to_rank}", piece) + %{ + from: %{file: from_file, rank: from_rank}, + to: %{file: to_file, rank: to_rank}, + board: Map.put(board, "#{to_file},#{to_rank}", piece), + piece: piece, + piece_captured: piece_captured, + } end def default do diff --git a/lib/chess/game_state.ex b/lib/chess/game_state.ex index 76fd780..5c9a8df 100644 --- a/lib/chess/game_state.ex +++ b/lib/chess/game_state.ex @@ -61,6 +61,7 @@ defmodule Chess.GameState do |> Enum.all?(fn({to_file, to_rank}) -> board |> Board.move_piece(%{"from" => [file, rank], "to" => [to_file, to_rank]}) + |> Map.get(:board) |> king_in_check?(piece["colour"]) end) end diff --git a/lib/chess/store/game.ex b/lib/chess/store/game.ex index d7b3fad..d7a67f4 100644 --- a/lib/chess/store/game.ex +++ b/lib/chess/store/game.ex @@ -35,11 +35,7 @@ defmodule Chess.Store.Game do |> foreign_key_constraint(:opponent_id) end - def move_changeset(struct, move_params) do - params = %{ - board: Board.move_piece(struct.board, move_params), - } - + def move_changeset(struct, params) do struct |> cast(params, required_attrs()) |> validate_king_in_check(struct, params) diff --git a/lib/chess_web/channels/game_channel.ex b/lib/chess_web/channels/game_channel.ex index 108e9ea..3f9a182 100644 --- a/lib/chess_web/channels/game_channel.ex +++ b/lib/chess_web/channels/game_channel.ex @@ -3,6 +3,8 @@ defmodule ChessWeb.GameChannel do use ChessWeb, :channel + alias Ecto.Multi + alias Chess.Store.Game alias Chess.Board alias Chess.Moves @@ -38,14 +40,18 @@ defmodule ChessWeb.GameChannel do |> Game.for_user_id() |> Repo.get!(socket.assigns.game_id) - changeset = Game.move_changeset(game, move_params) + params = Board.move_piece(game.board, move_params) - case Repo.update(changeset) do - {:ok, game} -> + Multi.new + |> Multi.update(:game, Game.move_changeset(game, params)) + |> Multi.insert(:move, Ecto.build_assoc(game, :moves, params)) + |> Repo.transaction + |> case do + {:ok, %{game: game}} -> send_update(game) {:noreply, socket} - {:error, changeset} -> + {:error, :game, changeset, _} -> {message, _} = changeset.errors[:board] {:reply, {:error, %{message: message}}, socket} diff --git a/test/chess/board_test.exs b/test/chess/board_test.exs index b19f7b5..c4ddae8 100644 --- a/test/chess/board_test.exs +++ b/test/chess/board_test.exs @@ -45,7 +45,8 @@ defmodule Chess.BoardTest do "3,0" => %{"type" => "queen", "colour" => "white"}, } - new_board = Board.move_piece(board, %{"from" => [3, 0], "to" => [5, 2]}) + %{board: new_board} = + Board.move_piece(board, %{"from" => [3, 0], "to" => [5, 2]}) assert new_board == %{ "5,2" => %{"type" => "queen", "colour" => "white"}, diff --git a/test/chess/store/game_test.exs b/test/chess/store/game_test.exs index e55eb35..ba69041 100644 --- a/test/chess/store/game_test.exs +++ b/test/chess/store/game_test.exs @@ -89,7 +89,10 @@ defmodule Chess.GameTest do move_params = %{"from" => [4, 1], "to" => [4, 3]} - changeset = Game.move_changeset(game, move_params) + changeset = Game.move_changeset( + game, + Board.move_piece(game.board, move_params) + ) assert {:ok, new_game} = Repo.update(changeset) assert new_game.turn == "black"