131 lines
4.1 KiB
JavaScript
131 lines
4.1 KiB
JavaScript
const ChessAPI = {
|
|
async joinGame() {
|
|
const response = await fetch('/api/chess/JoinGame');
|
|
return await response.json();
|
|
},
|
|
|
|
async createCPUGame(difficulty, color = "random") {
|
|
const response = await fetch(`/api/chess/new/${difficulty}?color=${color}`);
|
|
return await response.json();
|
|
},
|
|
|
|
async getGameState(gameId) {
|
|
const response = await fetch(`/api/chess/${gameId}`);
|
|
return await response.json();
|
|
},
|
|
|
|
async getPgn(gameId) {
|
|
const response = await fetch(`/api/chess/${gameId}/pgn`);
|
|
if (!response.ok) throw new Error("PGN unavailable");
|
|
return await response.text();
|
|
},
|
|
|
|
async forfeit(gameId, playerId) {
|
|
await fetch("/api/chess/forfeit", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ GameId: gameId, PlayerId: playerId })
|
|
});
|
|
},
|
|
|
|
async getLegalMoves(pieceId) {
|
|
const response = await fetch(`/api/chess/${GameState.currentGameId}/legalMoves/${pieceId}`);
|
|
if (!response.ok) throw new Error("API failed");
|
|
return await response.json();
|
|
},
|
|
|
|
async makeMove(moveDto) {
|
|
const response = await fetch("/api/chess/move", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(moveDto)
|
|
});
|
|
|
|
if (!response.ok) {
|
|
let message = await response.text();
|
|
throw new Error(message || "Invalid move or not your turn.");
|
|
}
|
|
|
|
// The move endpoint returns both the move result and the full resulting
|
|
// board state, so the caller can render without a follow-up fetch.
|
|
const data = await response.json();
|
|
|
|
if (!data.result.success) {
|
|
throw new Error(data.result.message || "Invalid move or not your turn.");
|
|
}
|
|
|
|
return data;
|
|
},
|
|
|
|
async handleMove(targetRow, targetCol) {
|
|
if (!GameState.selectedPiece) return;
|
|
|
|
const isPawn = GameState.selectedPiece.type === 0;
|
|
const reachedEnd = (Number(GameState.selectedPiece.color) === 0 && Number(targetRow) === 0) ||
|
|
(Number(GameState.selectedPiece.color) === 1 && Number(targetRow) === 0);
|
|
|
|
let choice = null;
|
|
|
|
if (isPawn && reachedEnd) {
|
|
choice = await ChessModals.promptPromotion();
|
|
if (!choice) return;
|
|
}
|
|
|
|
[targetRow, targetCol] = ChessUtils.flipCoordinates(targetRow, targetCol);
|
|
|
|
const moveDto = {
|
|
GameId: GameState.currentGameId,
|
|
PlayerId: GameState.currentPlayerId,
|
|
PieceId: GameState.selectedPiece.id,
|
|
SourceRow: GameState.selectedPiece.row,
|
|
SourceCol: GameState.selectedPiece.col,
|
|
TargetRow: targetRow,
|
|
TargetCol: targetCol,
|
|
PromotionChoice: choice
|
|
};
|
|
|
|
GameState.setPreviousMove([GameState.selectedPiece.row, GameState.selectedPiece.col], [targetRow, targetCol]);
|
|
|
|
try {
|
|
const { result, state } = await this.makeMove(moveDto);
|
|
|
|
ChessBoard.renderState(state);
|
|
|
|
GameState.clearSelection();
|
|
ChessInteractions.clearHighlights();
|
|
|
|
this.alertGameStatusChange(result);
|
|
|
|
} catch (error) {
|
|
alert("❌ " + error.message);
|
|
}
|
|
},
|
|
|
|
alertGameStatusChange(moveResult) {
|
|
setTimeout(async () => {
|
|
let gameOver = false;
|
|
|
|
if (moveResult.isCheck) {
|
|
console.log("🛑 Check!");
|
|
}
|
|
|
|
if (moveResult.isCheckmate) {
|
|
alert("♟️ Checkmate!");
|
|
gameOver = true;
|
|
} else if (moveResult.isStalemate) {
|
|
alert("🤝 Stalemate!");
|
|
gameOver = true;
|
|
} else if (moveResult.isThreefoldRepetition) {
|
|
alert("🤝 Draw by threefold repetition!");
|
|
gameOver = true;
|
|
}
|
|
|
|
if (gameOver) {
|
|
showCopyPgn(GameState.currentGameId);
|
|
await ChessSignalR.leaveGame();
|
|
}
|
|
}, 500);
|
|
}
|
|
};
|
|
|
|
console.log("ChessAPI.js loaded"); |