1
0
mirror of https://github.com/danbee/chess synced 2025-03-04 08:39:06 +00:00

Notification if move would result in check

This commit is contained in:
Daniel Barber 2018-03-23 16:52:18 -04:00
parent 048db4c71c
commit 49540d72bd
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
6 changed files with 122 additions and 11 deletions

View File

@ -34,7 +34,10 @@ class Channel {
}
sendMove(move) {
this.channel.push("game:move", move);
this.channel.push("game:move", move)
.receive("error", resp => {
alert(resp.message);
});
}
}

View File

@ -54,14 +54,17 @@ defmodule Chess.Moves.Piece do
defp _attacked?(_board, {7, _rank}, {1, _}, _), do: false
defp _attacked?(_board, {_file, 7}, {_, 1}, _), do: false
defp _attacked?(board, {file, rank}, {fv, rv}, pieces) do
{file, rank} =
board
|> Generator.moves({file, rank}, {fv, rv})
|> List.last
board
|> Generator.moves({file, rank}, {fv, rv})
|> List.last
|> case do
{file, rank} ->
piece = board["#{file},#{rank}"]
piece = board["#{file},#{rank}"]
Enum.any?(pieces, &(match?(%{"type" => ^&1}, piece)))
Enum.any?(pieces, &(match?(%{"type" => ^&1}, piece)))
nil ->
false
end
end
defp _attacked?(board, {file, rank}, pattern, piece_type) do

View File

@ -28,6 +28,12 @@ defmodule Chess.Store.Game do
|> foreign_key_constraint(:opponent_id)
end
def move_changeset(struct, params \\ %{}) do
struct
|> cast(params, required_attrs())
|> validate_king_in_check(struct, params)
end
def change_turn("black"), do: "white"
def change_turn("white"), do: "black"
@ -41,6 +47,20 @@ defmodule Chess.Store.Game do
or_where: game.opponent_id == ^user_id
end
def validate_king_in_check(changeset, %Game{turn: turn}, %{board: board}) do
case Board.king_in_check?(board, turn) do
true ->
changeset
|> add_error(
:board,
"That move would result in your king being in check"
)
_ ->
changeset
end
end
def validate_king_in_check(changeset, _, _), do: changeset
def ordered(query) do
query
|> order_by([game], desc: game.inserted_at)

View File

@ -24,7 +24,9 @@ defmodule ChessWeb.GameChannel do
board: Board.transform(game.board),
turn: game.turn
}
push(socket, "game:update", payload)
socket
|> push("game:update", payload)
{:noreply, socket}
end
@ -35,7 +37,7 @@ defmodule ChessWeb.GameChannel do
|> Game.for_user_id()
|> Repo.get!(socket.assigns.game_id)
changeset = Game.changeset(
changeset = Game.move_changeset(
game, %{
board: Board.move_piece(game.board, move_params),
turn: Game.change_turn(game.turn)
@ -46,7 +48,11 @@ defmodule ChessWeb.GameChannel do
{:ok, game} ->
send_update(game)
{:noreply, socket}
{:noreply, socket}
{:error, changeset} ->
{message, _} = changeset.errors[:board]
{:reply, {:error, %{message: message}}, socket}
end
end

View File

@ -21,6 +21,16 @@ defmodule Chess.Moves.PieceTest do
refute Piece.attacked?(board, {4, 0})
end
test "piece next to another piece is being attacked" do
board = %{
"4,0" => %{"type" => "king", "colour" => "white"},
"4,1" => %{"type" => "pawn", "colour" => "white"},
"7,3" => %{"type" => "bishop", "colour" => "black"},
}
assert Piece.attacked?(board, {4, 0})
end
test "piece is not being attacked by piece of its own colour" do
board = %{
"4,5" => %{"type" => "king", "colour" => "white"},

View File

@ -115,6 +115,75 @@ defmodule Chess.MovesTest do
|> assert_has(square_containing("f4-r3", "white.pawn"))
end
test "cannot move the king into a position that would result in check",
%{session: session} do
user = insert(:user, %{
name: "Link",
email: "link@hyrule.com",
password: "ilovezelda"
})
opponent = insert(:user, %{
name: "Zelda",
email: "zelda@hyrule.com",
password: "ganonsucks"
})
insert(:game, %{
board: %{
"4,0" => %{"type" => "king", "colour" => "white"},
"3,7" => %{"type" => "queen", "colour" => "black"},
},
user_id: user.id,
opponent_id: opponent.id,
turn: "white",
})
session
|> login("link@hyrule.com", "ilovezelda")
|> visit("/games")
|> click(link("Game with Zelda"))
session
|> click(css("#f4-r0"))
|> click(css("#f3-r0"))
|> refute_has(square_containing("f3-r0", "white.king"))
|> assert_has(square_containing("f4-r0", "white.king"))
end
test "cannot make a move that would place the king in check",
%{session: session} do
user = insert(:user, %{
name: "Link",
email: "link@hyrule.com",
password: "ilovezelda"
})
opponent = insert(:user, %{
name: "Zelda",
email: "zelda@hyrule.com",
password: "ganonsucks"
})
insert(:game, %{
board: %{
"4,0" => %{"type" => "king", "colour" => "white"},
"4,1" => %{"type" => "rook", "colour" => "white"},
"4,7" => %{"type" => "queen", "colour" => "black"},
},
user_id: user.id,
opponent_id: opponent.id,
turn: "white",
})
session
|> login("link@hyrule.com", "ilovezelda")
|> visit("/games")
|> click(link("Game with Zelda"))
session
|> click(css("#f4-r1"))
|> click(css("#f2-r1"))
|> refute_has(square_containing("f2-r1", "white.rook"))
|> assert_has(square_containing("f4-r1", "white.rook"))
end
defp square_selected(square) do
css("##{square}.selected")
end