From 9aac8d874b2a1045a0d4bc767c9ef55894831f7c Mon Sep 17 00:00:00 2001 From: Jonathan Loh Date: Sun, 21 Jan 2024 05:01:30 +0800 Subject: [PATCH] Add initial end game frontend --- backend/src/server.ts | 17 +++++++++++++---- backend/src/utils/calc.ts | 13 +++++++++++++ frontend/src/Game.tsx | 18 ++++++++---------- frontend/src/utils/socket.ts | 4 ++++ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/backend/src/server.ts b/backend/src/server.ts index b4206c9..e3e6c8f 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -2,7 +2,7 @@ import { createServer } from "http"; import express from "express"; import morgan from "morgan"; import cors from "cors"; -import { generateRoomCode } from "./utils/calc.js"; +import { generateRoomCode, processGameover } from "./utils/calc.js"; import dotenv from "dotenv"; import { Server } from "socket.io"; import { Chess } from "chess.js"; @@ -17,7 +17,8 @@ globalThis.roomFen = new Map(); const ENVIRONMENT = process.env.ENV || "dev"; -const START_FEN = new Chess().fen(); +const START_FEN = + "rnbqkbnr/ppppp2p/5p2/6p1/8/4P1P1/PPPP1P1P/RNBQKBNR w KQkq g6 0 3"; //new Chess().fen(); const engine = stockfish(); engine.onmessage = function (msg) { @@ -49,7 +50,6 @@ expressApp.get("/health-check", (req, res) => { }); expressApp.post("/stockfish", async (req, res) => { - console.log(req.body); console.log("QUERY", req.body.fen); // if chess engine replies engine.onmessage = function (msg) { @@ -147,10 +147,17 @@ io.on("connection", (socket) => { if (res instanceof FailedMove) { callback(res.error); } else if (typeof res === "string") { - io.to(roomId).emit("update", res, socket.id, move); + io.to(roomId === "ai" ? socket.id : roomId).emit( + "update", + res, + socket.id, + move + ); globalThis.roomFen.set(roomId, res); callback(res); + processGameover(new Chess(res), io, roomId === "ai" ? socket.id : roomId); + if (roomId === "ai") { fetch("http://localhost:8080/stockfish", { method: "POST", @@ -165,6 +172,8 @@ io.on("connection", (socket) => { chess.move(res); io.to(socket.id).emit("update", chess.fen(), "ai", res); globalThis.roomFen.set(socket.id, chess.fen()); + + processGameover(chess, io, socket.id); }) ); } diff --git a/backend/src/utils/calc.ts b/backend/src/utils/calc.ts index 80abde6..68c09a5 100644 --- a/backend/src/utils/calc.ts +++ b/backend/src/utils/calc.ts @@ -1,3 +1,6 @@ +import { Chess } from "chess.js"; +import { Server } from "socket.io"; + // Generate a random 6-letter room code export function generateRoomCode() { const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -9,3 +12,13 @@ export function generateRoomCode() { } return roomCode; } + +export function processGameover(chess: Chess, io: Server, roomId: string) { + if (chess.isGameOver()) io.to(roomId).emit("gameover", getWinner(chess)); +} + +function getWinner(chess: Chess) { + if (chess.isCheckmate()) + return chess.turn() === "b" ? "White wins!" : "Black wins!"; + else return "Draw!"; +} diff --git a/frontend/src/Game.tsx b/frontend/src/Game.tsx index 1e67ab8..5279d77 100644 --- a/frontend/src/Game.tsx +++ b/frontend/src/Game.tsx @@ -1,16 +1,9 @@ -import { - Button, - Container, - Grid, - Icon, - Input, - Loader, -} from "semantic-ui-react"; +import { Button, Container, Grid, Icon, Input } from "semantic-ui-react"; import { Chessboard } from "react-chessboard"; import "./Game.css"; import { Message } from "./types/message"; import { useCallback, useEffect, useRef, useState } from "react"; -import { move, onUpdate } from "./utils/socket"; +import { move, onGameover, onUpdate } from "./utils/socket"; export default function Game({ fen, @@ -25,6 +18,7 @@ export default function Game({ const [text, setText] = useState(""); const [messages, setMessages] = useState([]); const [isLoading, setLoading] = useState(false); + const [gameover, setGameover] = useState(false); // const messages: Message[] = [ // { outgoing: true, text: "Knight to E5" }, @@ -51,6 +45,10 @@ export default function Game({ msgs.concat({ outgoing: false, text: "Your turn!" }) ); }); + onGameover((text) => { + setMessages((msgs) => msgs.concat({ outgoing: false, text })); + setGameover(true); + }); }, []); const sendMessage = useCallback(() => { @@ -127,7 +125,7 @@ export default function Game({ ? "Enter move" : "Waiting for opponent..." } - disabled={!isTurn || isLoading} + disabled={!isTurn || isLoading || gameover} /> diff --git a/frontend/src/utils/socket.ts b/frontend/src/utils/socket.ts index 84c67d6..d5270ac 100644 --- a/frontend/src/utils/socket.ts +++ b/frontend/src/utils/socket.ts @@ -41,3 +41,7 @@ export function onUpdate( callback(fen, lastMovedUser !== socket.id, lastMove); }); } + +export function onGameover(callback: (message: string) => void) { + socket.on("gameover", callback); +}