diff --git a/JoshHeaps.Net/Controllers/ChessController.cs b/JoshHeaps.Net/Controllers/ChessController.cs index 1181008..87a2042 100644 --- a/JoshHeaps.Net/Controllers/ChessController.cs +++ b/JoshHeaps.Net/Controllers/ChessController.cs @@ -165,7 +165,7 @@ public class ChessController( var expectedPlayerId = isWhiteMove ? gameState.WhitePlayerId : gameState.BlackPlayerId; if (moveDto.PlayerId != expectedPlayerId) - return Forbid("You are not the current player."); + return StatusCode(403, "You are not the current player."); // Make sure player owns the piece var piece = gameState.Pieces.FirstOrDefault(p => p.Id == moveDto.PieceId); @@ -174,7 +174,7 @@ public class ChessController( return NotFound("Chess piece Id does not exist"); if ((isWhiteMove && piece.Color != PieceColor.White) || (!isWhiteMove && piece?.Color != PieceColor.Black)) - return Forbid("You cannot move this piece."); + return StatusCode(403, "You cannot move this piece."); var result = chessService.MakeMove(gameState, moveDto); diff --git a/JoshHeaps.Net/Services/Implementations/ChessService.cs b/JoshHeaps.Net/Services/Implementations/ChessService.cs index 9b76ef1..7b3743a 100644 --- a/JoshHeaps.Net/Services/Implementations/ChessService.cs +++ b/JoshHeaps.Net/Services/Implementations/ChessService.cs @@ -110,7 +110,6 @@ public class ChessService : IChessService var piece = gameState.Pieces.FirstOrDefault(p => p.Id == pieceId); if (piece == null) return []; - if (piece.Color != gameState.CurrentPlayer) return []; var candidateMoves = GenerateCandidateMoves(gameState, piece); var legalMoves = new List(); @@ -529,7 +528,14 @@ public class ChessService : IChessService var ep = gs.EnPassantTarget.Value; if (ep.Row == forward1 && Math.Abs(ep.Col - startCol) == 1) - moves.Add(ep); + { + // Verify there's an enemy pawn to capture + int enemyPawnRow = piece.Color == PieceColor.White ? ep.Row + 1 : ep.Row - 1; + var enemyPawn = gs.Board[enemyPawnRow, ep.Col]; + + if (enemyPawn != null && enemyPawn.Type == PieceType.Pawn && enemyPawn.Color != piece.Color) + moves.Add(ep); + } } return moves; diff --git a/JoshHeaps.Net/wwwroot/css/chess/game.css b/JoshHeaps.Net/wwwroot/css/chess/game.css index 203a487..7ca7512 100644 --- a/JoshHeaps.Net/wwwroot/css/chess/game.css +++ b/JoshHeaps.Net/wwwroot/css/chess/game.css @@ -1,5 +1,10 @@ -#chessBoard { +#boardContainer { + position: relative; + width: fit-content; margin: 2vw auto; +} + +#chessBoard { width: 60vw; height: 60vw; display: grid; @@ -158,4 +163,30 @@ width: 50px; height: 50px; pointer-events: none; /* ensures img doesn't steal the click */ +} + +.chessSquare .coordinate-label { + position: absolute; + font-size: 1.2vw; + font-weight: bold; + pointer-events: none; + user-select: none; +} + +.chessSquare.light .coordinate-label { + color: #656770; +} + +.chessSquare.dark .coordinate-label { + color: #ccc; +} + +.chessSquare .row-label { + top: 2px; + left: 4px; +} + +.chessSquare .col-label { + bottom: 2px; + right: 4px; } \ No newline at end of file diff --git a/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessAPI.js b/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessAPI.js index 1d58820..19de069 100644 --- a/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessAPI.js +++ b/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessAPI.js @@ -27,9 +27,14 @@ const ChessAPI = { body: JSON.stringify(moveDto) }); + if (!response.ok) { + let message = await response.text(); + throw new Error(message || "Invalid move or not your turn."); + } + const result = await response.json(); - if (!response.ok || !result.success) { + if (!result.success) { throw new Error(result.message || "Invalid move or not your turn."); } diff --git a/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessBoard.js b/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessBoard.js index 3f4ab77..0c5a59e 100644 --- a/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessBoard.js +++ b/JoshHeaps.Net/wwwroot/js/ChessScripts/ChessBoard.js @@ -1,6 +1,7 @@ const ChessBoard = { renderPieces(pieces) { this.clearAllSquares(); + this.renderCoordinateLabels(); this.placePieces(pieces); this.setupSquareEventHandlers(); this.highlightPreviousMove(); @@ -106,6 +107,39 @@ const ChessBoard = { ChessAPI.handleMove(targetRow, targetCol); }; } + }, + + renderCoordinateLabels() { + const files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; + const ranks = ['8', '7', '6', '5', '4', '3', '2', '1']; + + // If player is black, reverse the coordinates + if (!GameState.currentPlayerIsWhite) { + files.reverse(); + ranks.reverse(); + } + + for (let i = 0; i < 64; i++) { + const square = document.getElementById(`square-${i}`); + const row = Math.floor(i / 8); + const col = i % 8; + + // Add rank label (1-8) on the leftmost column + if (col === 0) { + const rankLabel = document.createElement('span'); + rankLabel.className = 'coordinate-label row-label'; + rankLabel.textContent = ranks[row]; + square.appendChild(rankLabel); + } + + // Add file label (a-h) on the bottom row + if (row === 7) { + const fileLabel = document.createElement('span'); + fileLabel.className = 'coordinate-label col-label'; + fileLabel.textContent = files[col]; + square.appendChild(fileLabel); + } + } } };