mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
130 lines
2.8 KiB
Elixir
130 lines
2.8 KiB
Elixir
defmodule ChessWeb.BoardLive do
|
|
use Phoenix.LiveView, container: {:div, class: "board__container"}
|
|
|
|
alias Chess.Store.User
|
|
alias Chess.Store.Game
|
|
alias Chess.Store.Move
|
|
alias Chess.Repo
|
|
alias Chess.Moves
|
|
|
|
alias ChessWeb.GameView
|
|
|
|
import Ecto.Query
|
|
|
|
require Logger
|
|
|
|
def render(assigns) do
|
|
Phoenix.View.render(GameView, "board.html", assigns)
|
|
end
|
|
|
|
def mount(_params, %{"user_id" => user_id, "game_id" => game_id}, socket) do
|
|
ChessWeb.Endpoint.subscribe("game:#{game_id}")
|
|
|
|
user = Repo.get!(User, user_id)
|
|
|
|
game =
|
|
Game.for_user(user)
|
|
|> Repo.get!(game_id)
|
|
|
|
{:ok, assign(socket, default_assigns(game, user))}
|
|
end
|
|
|
|
def handle_event("click", %{"rank" => rank, "file" => file}, socket) do
|
|
{
|
|
:noreply,
|
|
socket |> handle_click(String.to_integer(file), String.to_integer(rank))
|
|
}
|
|
end
|
|
|
|
defp default_assigns(game, user) do
|
|
%{
|
|
board: game.board,
|
|
game: game,
|
|
user: user,
|
|
selected: nil,
|
|
available: []
|
|
}
|
|
end
|
|
|
|
def handle_info(%{event: "move", payload: state}, socket) do
|
|
Logger.info("Handling move from board")
|
|
{:noreply, assign(socket, state)}
|
|
end
|
|
|
|
defp handle_click(socket, file, rank) do
|
|
game = socket.assigns[:game]
|
|
board = game.board
|
|
user = socket.assigns[:user]
|
|
|
|
colour = GameView.player_colour(user, game)
|
|
|
|
assigns =
|
|
if colour == game.turn do
|
|
case socket.assigns do
|
|
%{selected: nil} ->
|
|
handle_selection(board, colour, file, rank)
|
|
|
|
_ ->
|
|
handle_move(socket.assigns, file, rank)
|
|
end
|
|
end
|
|
|
|
assign(socket, assigns)
|
|
end
|
|
|
|
defp handle_selection(board, colour, file, rank) do
|
|
case GameView.piece(board, {file, rank}) do
|
|
%{"colour" => ^colour} ->
|
|
[
|
|
{:selected, {file, rank}},
|
|
{:available, Moves.available(board, {file, rank})}
|
|
]
|
|
|
|
_ ->
|
|
[]
|
|
end
|
|
end
|
|
|
|
defp handle_move(
|
|
%{game: game, available: available, selected: selected},
|
|
file,
|
|
rank
|
|
) do
|
|
if {file, rank} in available do
|
|
game
|
|
|> Moves.make_move(%{from: selected, to: {file, rank}})
|
|
|> case do
|
|
{:ok, %{game: game}} ->
|
|
game
|
|
|> Repo.preload([:user, :opponent])
|
|
|> Repo.preload(
|
|
moves:
|
|
from(
|
|
move in Move,
|
|
order_by: [asc: move.inserted_at]
|
|
)
|
|
)
|
|
|> broadcast_move(game.board)
|
|
|
|
[
|
|
{:selected, nil},
|
|
{:available, []},
|
|
{:board, game.board},
|
|
{:game, game}
|
|
]
|
|
end
|
|
else
|
|
[{:selected, nil}, {:available, []}]
|
|
end
|
|
end
|
|
|
|
defp broadcast_move(game, board) do
|
|
ChessWeb.Endpoint.broadcast_from(
|
|
self(),
|
|
"game:#{game.id}",
|
|
"move",
|
|
%{game: game, board: board}
|
|
)
|
|
end
|
|
end
|