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:
parent
048db4c71c
commit
49540d72bd
@ -34,7 +34,10 @@ class Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendMove(move) {
|
sendMove(move) {
|
||||||
this.channel.push("game:move", move);
|
this.channel.push("game:move", move)
|
||||||
|
.receive("error", resp => {
|
||||||
|
alert(resp.message);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,14 +54,17 @@ defmodule Chess.Moves.Piece do
|
|||||||
defp _attacked?(_board, {7, _rank}, {1, _}, _), do: false
|
defp _attacked?(_board, {7, _rank}, {1, _}, _), do: false
|
||||||
defp _attacked?(_board, {_file, 7}, {_, 1}, _), do: false
|
defp _attacked?(_board, {_file, 7}, {_, 1}, _), do: false
|
||||||
defp _attacked?(board, {file, rank}, {fv, rv}, pieces) do
|
defp _attacked?(board, {file, rank}, {fv, rv}, pieces) do
|
||||||
{file, rank} =
|
|
||||||
board
|
board
|
||||||
|> Generator.moves({file, rank}, {fv, rv})
|
|> Generator.moves({file, rank}, {fv, rv})
|
||||||
|> List.last
|
|> 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
|
end
|
||||||
|
|
||||||
defp _attacked?(board, {file, rank}, pattern, piece_type) do
|
defp _attacked?(board, {file, rank}, pattern, piece_type) do
|
||||||
|
|||||||
@ -28,6 +28,12 @@ defmodule Chess.Store.Game do
|
|||||||
|> foreign_key_constraint(:opponent_id)
|
|> foreign_key_constraint(:opponent_id)
|
||||||
end
|
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("black"), do: "white"
|
||||||
def change_turn("white"), do: "black"
|
def change_turn("white"), do: "black"
|
||||||
|
|
||||||
@ -41,6 +47,20 @@ defmodule Chess.Store.Game do
|
|||||||
or_where: game.opponent_id == ^user_id
|
or_where: game.opponent_id == ^user_id
|
||||||
end
|
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
|
def ordered(query) do
|
||||||
query
|
query
|
||||||
|> order_by([game], desc: game.inserted_at)
|
|> order_by([game], desc: game.inserted_at)
|
||||||
|
|||||||
@ -24,7 +24,9 @@ defmodule ChessWeb.GameChannel do
|
|||||||
board: Board.transform(game.board),
|
board: Board.transform(game.board),
|
||||||
turn: game.turn
|
turn: game.turn
|
||||||
}
|
}
|
||||||
push(socket, "game:update", payload)
|
|
||||||
|
socket
|
||||||
|
|> push("game:update", payload)
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
@ -35,7 +37,7 @@ defmodule ChessWeb.GameChannel do
|
|||||||
|> Game.for_user_id()
|
|> Game.for_user_id()
|
||||||
|> Repo.get!(socket.assigns.game_id)
|
|> Repo.get!(socket.assigns.game_id)
|
||||||
|
|
||||||
changeset = Game.changeset(
|
changeset = Game.move_changeset(
|
||||||
game, %{
|
game, %{
|
||||||
board: Board.move_piece(game.board, move_params),
|
board: Board.move_piece(game.board, move_params),
|
||||||
turn: Game.change_turn(game.turn)
|
turn: Game.change_turn(game.turn)
|
||||||
@ -47,6 +49,10 @@ defmodule ChessWeb.GameChannel do
|
|||||||
send_update(game)
|
send_update(game)
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
|
{:error, changeset} ->
|
||||||
|
{message, _} = changeset.errors[:board]
|
||||||
|
|
||||||
|
{:reply, {:error, %{message: message}}, socket}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,16 @@ defmodule Chess.Moves.PieceTest do
|
|||||||
refute Piece.attacked?(board, {4, 0})
|
refute Piece.attacked?(board, {4, 0})
|
||||||
end
|
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
|
test "piece is not being attacked by piece of its own colour" do
|
||||||
board = %{
|
board = %{
|
||||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||||
|
|||||||
@ -115,6 +115,75 @@ defmodule Chess.MovesTest do
|
|||||||
|> assert_has(square_containing("f4-r3", "white.pawn"))
|
|> assert_has(square_containing("f4-r3", "white.pawn"))
|
||||||
end
|
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
|
defp square_selected(square) do
|
||||||
css("##{square}.selected")
|
css("##{square}.selected")
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user