diff --git a/assets/js/hooks/chessBoard.js b/assets/js/hooks/chessBoard.js index bbecd04..a09f6c8 100644 --- a/assets/js/hooks/chessBoard.js +++ b/assets/js/hooks/chessBoard.js @@ -3,24 +3,41 @@ import { Chess } from 'chess.js'; export const ChessBoard = { mounted() { - // Initialize chess.js for local rule validation - this.chess = new Chess(); + this.chess = new Chess(); - // Initialize Chessground - this.ground = Chessground(this.el, { - fen: this.chess.fen(), - movable: { - color: 'white', - free: false, // Don't allow completely arbitrary drops - dests: this.getValidDests() // Only allow legal chess moves - }, - events: { - // Triggered when a piece is successfully dropped - move: (orig, dest, _metadata) => { - this.handleMove(orig, dest); - } - } - }); + this.ground = Chessground(this.el, { + fen: this.chess.fen(), + movable: { + color: 'white', + free: false, + dests: this.getValidDests() + }, + events: { + move: (orig, dest, _metadata) => { + this.handleMove(orig, dest); + } + } + }); + + this.handleEvent("set_fen", ({ fen }) => { + try { + this.chess.load(fen); + + const currentTurnColor = this.chess.turn() === 'w' ? 'white' : 'black'; + + this.ground.set({ + fen: fen, + turnColor: currentTurnColor, + movable: { + color: currentTurnColor, + dests: this.getValidDests() + } + }); + } catch (error) { + console.error("Invalid FEN string submitted:", error); + alert("Invalid FEN configuration!"); + } + }); }, getValidDests() { @@ -34,30 +51,26 @@ export const ChessBoard = { }, handleMove(orig, dest) { - // 1. Try to execute the move in chess.js state const move = this.chess.move({ from: orig, to: dest, promotion: 'q' }); if (move) { - // 2. Telemetry back up to Phoenix LiveView this.pushEvent("move_played", { from: orig, to: dest, - fen: this.chess.fen() + fen: this.chess.fen(), + san: move.san, }); - // 3. Determine whose turn it is now ('w' or 'b') const nextTurnColor = this.chess.turn() === 'w' ? 'white' : 'black'; - // 4. Force Chessground to update its internal state for the next player this.ground.set({ - turnColor: nextTurnColor, // Switches turn tracking + turnColor: nextTurnColor, movable: { - color: nextTurnColor, // 👈 THIS IS CRITICAL: Changes who is allowed to drag pieces! - dests: this.getValidDests() // Re-calculates valid legal squares for Black + color: nextTurnColor, + dests: this.getValidDests() } }); } else { - // If chess.js says it's an illegal move, snap the piece back instantly this.ground.set({ fen: this.chess.fen() }); } } diff --git a/lib/chesstrainer_web/live/chess_test_live.ex b/lib/chesstrainer_web/live/chess_test_live.ex index b944b05..9815924 100644 --- a/lib/chesstrainer_web/live/chess_test_live.ex +++ b/lib/chesstrainer_web/live/chess_test_live.ex @@ -3,7 +3,7 @@ defmodule ChesstrainerWeb.ChessTestLive do @impl true def mount(_params, _session, socket) do - {:ok, assign(socket, last_move: "None yet", total_moves: 0)} + {:ok, assign(socket, last_move: "None yet", san: "None yet", move_list: [])} end @impl true @@ -12,14 +12,36 @@ defmodule ChesstrainerWeb.ChessTestLive do

Chessground LiveView Test

+
+
+ +
+ +
+

Last Played Move:

{@last_move}

-
-
-

Total Moves:

-

{@total_moves}

+

{@san}

+

+ {if length(@move_list) == 0 do + "No Moves" + else + Enum.reverse(@move_list) |> Enum.join(", ") + end} +

@@ -37,11 +59,29 @@ defmodule ChesstrainerWeb.ChessTestLive do end @impl true - def handle_event("move_played", %{"from" => from, "to" => to, "fen" => _fen}, socket) do - # Receive the payload sent from the client JS Hook via this.pushEvent + def handle_event("load_fen", %{"fen" => fen}, socket) do + clean_fen = String.trim(fen) + + {:noreply, + socket + |> assign(:last_move, "Position Loaded") + |> assign(:san, "None yet") + |> assign(:move_list, []) + |> push_event("set_fen", %{fen: clean_fen})} + end + + @impl true + def handle_event( + "move_played", + %{"from" => from, "to" => to, "fen" => _fen, "san" => san}, + socket + ) do + current_moves = socket.assigns.move_list + {:noreply, socket |> assign(:last_move, "#{from} âž” #{to}") - |> assign(:total_moves, socket.assigns.total_moves + 1)} + |> assign(:san, san) + |> assign(:move_list, [san | current_moves])} end end