From b8f94c74eff7b06009bea01457b82723c34f8488 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Thu, 4 May 2023 17:00:21 +0430 Subject: [PATCH 01/22] Done === add draw result to modal decrease animate time --- React/src/app/pages/game/BotGamePage/BotGamePage.tsx | 8 +++++++- React/src/app/pages/game/GamePage.tsx | 8 ++++++++ .../app/pages/game/components/Modal/Modal.module.scss | 10 ++++++++-- React/src/app/pages/game/components/Modal/Modal.tsx | 7 ++++--- React/src/app/utils/minimax.ts | 2 +- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/React/src/app/pages/game/BotGamePage/BotGamePage.tsx b/React/src/app/pages/game/BotGamePage/BotGamePage.tsx index 53033b9..6ddf225 100644 --- a/React/src/app/pages/game/BotGamePage/BotGamePage.tsx +++ b/React/src/app/pages/game/BotGamePage/BotGamePage.tsx @@ -6,7 +6,7 @@ import { Footer } from "../components/Footer"; import { Header } from "../components/Header"; import { Modal } from "../components/Modal"; import { GameMode } from "~/utils/game-mode"; -import { minimax } from "~/utils/minimax"; +import { minimax, isAvailableCell } from "~/utils/minimax"; import classes from "./BotGamePage.module.scss"; const INITIAL_BOARD = Array(3) @@ -20,6 +20,7 @@ export function BotGamePage() { ); const [result, setResult] = useState(); const [showModal, setShowModal] = useState(false); + const [isDraw, setIsDraw] = useState(false); const isFirstMove = useRef(true); useEffect(() => { @@ -62,6 +63,10 @@ export function BotGamePage() { } setBoardData([...boardData]); if (checkWinner(P2)) return; + if (!isAvailableCell(boardData)) { + setIsDraw(true); + setShowModal(true); + } setCurrentPlayer(P1); }; @@ -105,6 +110,7 @@ export function BotGamePage() { {showModal && (); const [showModal, setShowModal] = useState(false); + const [isDraw, setIsDraw] = useState(false); const handleClick = (i: number, j: number) => { if (boardData[i][j] || result) return; @@ -26,6 +28,10 @@ export function GamePage() { setBoardData([...boardData]); if (checkWinner()) return; + if (!isAvailableCell(boardData)) { + setIsDraw(true); + setShowModal(true); + } setCurrentPlayer(currentPlayer === P1 ? P2 : P1); }; @@ -44,6 +50,7 @@ export function GamePage() { setBoardData(structuredClone(INITIAL_BOARD)); setCurrentPlayer(generateRandomTurn()); setResult(undefined); + setIsDraw(false); setShowModal(false); } @@ -66,6 +73,7 @@ export function GamePage() { {showModal && void; gameMode: GameMode; } -export function Modal({ winner, onRefresh, gameMode }: Props) { +export function Modal({ winner, onRefresh, gameMode, isDraw }: Props) { return (
- x + {isDraw ? "" : x}
-
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
+ {isDraw ?
It's Draw
:
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
}
diff --git a/React/src/app/utils/minimax.ts b/React/src/app/utils/minimax.ts index 59c233a..a918020 100644 --- a/React/src/app/utils/minimax.ts +++ b/React/src/app/utils/minimax.ts @@ -1,7 +1,7 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; -function isAvailableCell(board: string[][]) { +export function isAvailableCell(board: string[][]) { return board.some(row => row.some(cell => cell == null)); } From 8c87e94f4fb20632ae38d35b94d13076f0a7531e Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 7 May 2023 10:20:39 +0430 Subject: [PATCH 02/22] add images --- React/static/images/board_size_3.svg | 52 ++++++++++ React/static/images/board_size_6.svg | 80 ++++++++++++++ React/static/images/board_size_9.svg | 149 +++++++++++++++++++++++++++ React/static/images/vector-left.png | Bin 0 -> 379 bytes React/static/images/vector-right.png | Bin 0 -> 378 bytes 5 files changed, 281 insertions(+) create mode 100644 React/static/images/board_size_3.svg create mode 100644 React/static/images/board_size_6.svg create mode 100644 React/static/images/board_size_9.svg create mode 100644 React/static/images/vector-left.png create mode 100644 React/static/images/vector-right.png diff --git a/React/static/images/board_size_3.svg b/React/static/images/board_size_3.svg new file mode 100644 index 0000000..491443f --- /dev/null +++ b/React/static/images/board_size_3.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/React/static/images/board_size_6.svg b/React/static/images/board_size_6.svg new file mode 100644 index 0000000..d5bd74f --- /dev/null +++ b/React/static/images/board_size_6.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/React/static/images/board_size_9.svg b/React/static/images/board_size_9.svg new file mode 100644 index 0000000..df2af5f --- /dev/null +++ b/React/static/images/board_size_9.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/React/static/images/vector-left.png b/React/static/images/vector-left.png new file mode 100644 index 0000000000000000000000000000000000000000..8ad2cf7f23c15004469d6496be0d2dc3fea08416 GIT binary patch literal 379 zcmV->0fhdEP) zf-n>Y;MW=tgo`6Mf+IKrZr}!vppM`OPT&Z-fo`B1aM6@kh1x148YuMj{RxnA_|g#i zw*ZmR_xtRHm?@>E5S!-{*BXl)u{dbN++uT}rbe#KOdO(haikb6q=u&M9Sb2tK7<7I zA;HiP5(I@HgHR~a3sDd+L`6EG7^DToB7cxu#j(gQB*l2VhRSS{B)I`2(ik(-WqAQ+ zq`ReQngcUZ2ysEg1u!FDRkf1>R;1nX=Wd2xUH90Xr88%rwomM8(Z-F_HU{-=oA>_U4Skkl(-Z`jHSaMLe$skV zA^i+%(V-Yc?PtuAhVdTVjtg9QxN4I&J!4^2>3f{@qTTq|BLS9`96k9glXDG3Tmx6V z;$mI){c;qe&_!m0vVJnKJJl|H9}e+#g%FbnvIR08M_x zWT|L&LekJNu7mHB8_;eeCtd9;{hAyzXBFR!@jpIGs^!FkO4Syg$m^Y1cN!Y@Fq~Tb W?QrIo&uze Date: Sun, 7 May 2023 10:28:28 +0430 Subject: [PATCH 03/22] Revert "Done" This reverts commit b8f94c74eff7b06009bea01457b82723c34f8488. --- React/src/app/pages/game/BotGamePage/BotGamePage.tsx | 8 +------- React/src/app/pages/game/GamePage.tsx | 8 -------- .../app/pages/game/components/Modal/Modal.module.scss | 10 ++-------- React/src/app/pages/game/components/Modal/Modal.tsx | 7 +++---- React/src/app/utils/minimax.ts | 2 +- 5 files changed, 7 insertions(+), 28 deletions(-) diff --git a/React/src/app/pages/game/BotGamePage/BotGamePage.tsx b/React/src/app/pages/game/BotGamePage/BotGamePage.tsx index 6ddf225..53033b9 100644 --- a/React/src/app/pages/game/BotGamePage/BotGamePage.tsx +++ b/React/src/app/pages/game/BotGamePage/BotGamePage.tsx @@ -6,7 +6,7 @@ import { Footer } from "../components/Footer"; import { Header } from "../components/Header"; import { Modal } from "../components/Modal"; import { GameMode } from "~/utils/game-mode"; -import { minimax, isAvailableCell } from "~/utils/minimax"; +import { minimax } from "~/utils/minimax"; import classes from "./BotGamePage.module.scss"; const INITIAL_BOARD = Array(3) @@ -20,7 +20,6 @@ export function BotGamePage() { ); const [result, setResult] = useState(); const [showModal, setShowModal] = useState(false); - const [isDraw, setIsDraw] = useState(false); const isFirstMove = useRef(true); useEffect(() => { @@ -63,10 +62,6 @@ export function BotGamePage() { } setBoardData([...boardData]); if (checkWinner(P2)) return; - if (!isAvailableCell(boardData)) { - setIsDraw(true); - setShowModal(true); - } setCurrentPlayer(P1); }; @@ -110,7 +105,6 @@ export function BotGamePage() {
{showModal && (); const [showModal, setShowModal] = useState(false); - const [isDraw, setIsDraw] = useState(false); const handleClick = (i: number, j: number) => { if (boardData[i][j] || result) return; @@ -28,10 +26,6 @@ export function GamePage() { setBoardData([...boardData]); if (checkWinner()) return; - if (!isAvailableCell(boardData)) { - setIsDraw(true); - setShowModal(true); - } setCurrentPlayer(currentPlayer === P1 ? P2 : P1); }; @@ -50,7 +44,6 @@ export function GamePage() { setBoardData(structuredClone(INITIAL_BOARD)); setCurrentPlayer(generateRandomTurn()); setResult(undefined); - setIsDraw(false); setShowModal(false); } @@ -73,7 +66,6 @@ export function GamePage() {
{showModal && void; gameMode: GameMode; } -export function Modal({ winner, onRefresh, gameMode, isDraw }: Props) { +export function Modal({ winner, onRefresh, gameMode }: Props) { return (
- {isDraw ? "" : x} + x
- {isDraw ?
It's Draw
:
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
} +
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
diff --git a/React/src/app/utils/minimax.ts b/React/src/app/utils/minimax.ts index a918020..59c233a 100644 --- a/React/src/app/utils/minimax.ts +++ b/React/src/app/utils/minimax.ts @@ -1,7 +1,7 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; -export function isAvailableCell(board: string[][]) { +function isAvailableCell(board: string[][]) { return board.some(row => row.some(cell => cell == null)); } From 2af3596bee3d4bcb628818c469b911770819570f Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 7 May 2023 12:58:10 +0430 Subject: [PATCH 04/22] Done === change names add draw result to modal add utilzs --- React/src/app/AppRouter.tsx | 11 +- .../PlayerVsBotPage.module.scss} | 0 .../game/PlayerVsBotPage/PlayerVsBotPage.tsx | 122 ++++++++++++++++++ .../app/pages/game/PlayerVsBotPage/index.ts | 1 + .../PlayerVsPlayerPage.module.scss | 33 +++++ .../PlayerVsPlayerPage.tsx} | 20 +-- .../pages/game/PlayerVsPlayerPage/index.ts | 1 + .../pages/game/components/Footer/Footer.tsx | 2 +- .../GamePageButtons/GamePageButtons.tsx | 8 +- .../app/pages/game/components/Modal/Modal.tsx | 28 ---- .../ResultModal.module.scss} | 10 +- .../Modal/ResultModal/ResultModal.tsx | 36 ++++++ .../components/Modal/ResultModal/index.ts | 1 + .../app/pages/game/components/Modal/index.ts | 1 - React/src/app/pages/game/index.ts | 1 - React/src/app/pages/home/HomePage.tsx | 4 +- React/src/app/utils/isboardfull.ts | 3 + React/src/app/utils/minimax.ts | 7 +- 18 files changed, 232 insertions(+), 57 deletions(-) rename React/src/app/pages/game/{GamePage.module.scss => PlayerVsBotPage/PlayerVsBotPage.module.scss} (100%) create mode 100644 React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx create mode 100644 React/src/app/pages/game/PlayerVsBotPage/index.ts create mode 100644 React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.module.scss rename React/src/app/pages/game/{GamePage.tsx => PlayerVsPlayerPage/PlayerVsPlayerPage.tsx} (78%) create mode 100644 React/src/app/pages/game/PlayerVsPlayerPage/index.ts delete mode 100644 React/src/app/pages/game/components/Modal/Modal.tsx rename React/src/app/pages/game/components/Modal/{Modal.module.scss => ResultModal/ResultModal.module.scss} (85%) create mode 100644 React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx create mode 100644 React/src/app/pages/game/components/Modal/ResultModal/index.ts delete mode 100644 React/src/app/pages/game/components/Modal/index.ts delete mode 100644 React/src/app/pages/game/index.ts create mode 100644 React/src/app/utils/isboardfull.ts diff --git a/React/src/app/AppRouter.tsx b/React/src/app/AppRouter.tsx index 0cc588e..b1c5971 100644 --- a/React/src/app/AppRouter.tsx +++ b/React/src/app/AppRouter.tsx @@ -5,9 +5,10 @@ import { Route, RootRoute, } from "@tanstack/react-router"; -import { GamePage } from "./pages/game"; + import { HomePage } from "./pages/home"; -import {BotGamePage} from "./pages/game/BotGamePage" +import { PlayerVsPlayerPage } from "./pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage"; +import {BotGamePage} from "./pages/game/PlayerVsBotPage/PlayerVsBotPage" const rootRoute = new RootRoute({ component: () => , @@ -21,13 +22,13 @@ const homeRoute = new Route({ const gameRoute = new Route({ getParentRoute: () => rootRoute, - path: "/game", - component: GamePage, + path: "/playerVsplayer", + component: PlayerVsPlayerPage, }); const botGameRoute = new Route({ getParentRoute: () => rootRoute, - path: "/botgame", + path: "/playerVsBot", component: BotGamePage, }); diff --git a/React/src/app/pages/game/GamePage.module.scss b/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.module.scss similarity index 100% rename from React/src/app/pages/game/GamePage.module.scss rename to React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.module.scss diff --git a/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx new file mode 100644 index 0000000..46484d5 --- /dev/null +++ b/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx @@ -0,0 +1,122 @@ +import { useState, useRef, useEffect } from "react"; +import { checkBoard } from "~/utils/check-board"; +import { P1, P2, generateRandomTurn } from "~/utils/players"; +import { Board } from "../components/Board"; +import { Footer } from "../components/Footer"; +import { Header } from "../components/Header"; +import { ResultModal } from "../components/Modal/ResultModal"; +import { GameMode } from "~/utils/game-mode"; +import { minimax } from "~/utils/minimax"; +import classes from "./PlayerVsBotPage.module.scss"; +import { isBoardFull } from "~/utils/isboardfull"; + +const INITIAL_BOARD = Array(3) + .fill(null) + .map(() => Array(3).fill(null)); + +export function BotGamePage() { + const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); + const [currentPlayer, setCurrentPlayer] = useState( + generateRandomTurn() + ); + const [result, setResult] = useState(); + const [showModal, setShowModal] = useState(false); + const isFirstMove = useRef(true); + + useEffect(() => { + if (isFirstMove.current && currentPlayer === P2) { + handleBot(); + } + isFirstMove.current = false; + }, [isFirstMove.current]) + + const handleClick = (i: number, j: number) => { + if (boardData[i][j] || result) return; + if (currentPlayer === P1) { + boardData[i][j] = currentPlayer; + setBoardData([...boardData]); + if (checkWinner(P1)) return; + setCurrentPlayer(P2); + handleBot(); + } + }; + + const handleBot = () => { + + let bestScore = -Infinity; + let move; + for (let i = 0; i < 3; i++) { + for (let j = 0; j < 3; j++) { + if (boardData[i][j] == null) { + boardData[i][j] = P2; + let score = minimax(boardData, 0, false); + boardData[i][j] = null; + if (score > bestScore) { + bestScore = score; + move = { i, j }; + } + } + } + } + if (move) { + boardData[move.i][move.j] = P2; + } + setBoardData([...boardData]); + if (checkWinner(P2)) return; + if (isBoardFull(boardData)) { + setShowModal(true); + } + setCurrentPlayer(P1); + }; + + const checkWinner = (currentPlayer: string) => { + const winResult = checkBoard(boardData, currentPlayer); + if (!winResult) return false; + setResult(winResult); + setTimeout(() => { + setShowModal(true); + }, 500); + return true; + }; + + const refreshBoard = () => { + let newRandomTurnGenerator = generateRandomTurn(); + setBoardData(structuredClone(INITIAL_BOARD)); + setCurrentPlayer(newRandomTurnGenerator); + if (newRandomTurnGenerator === P2) { + isFirstMove.current = true; + } + setResult(undefined); + setShowModal(false); + } + + return ( +
+
+
+
+ +
+ +
+ + {showModal && } + +
+
+
+
+ ); +} diff --git a/React/src/app/pages/game/PlayerVsBotPage/index.ts b/React/src/app/pages/game/PlayerVsBotPage/index.ts new file mode 100644 index 0000000..12a02b3 --- /dev/null +++ b/React/src/app/pages/game/PlayerVsBotPage/index.ts @@ -0,0 +1 @@ +export * from "./PlayerVsBotPage"; diff --git a/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.module.scss b/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.module.scss new file mode 100644 index 0000000..6037a56 --- /dev/null +++ b/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.module.scss @@ -0,0 +1,33 @@ +.page { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + width: 100%; + height: 100%; + background-image: url("static/images/game-page_bg.svg"); + background-size: 100% 100%; + background-repeat: no-repeat; +} + +.header { + display: flex; + gap: 16px; + margin-top: 36px; + align-items: center; + font-family: Arial, Helvetica, sans-serif; + color: white; +} + +.body { + display: flex; + justify-content: center; +} + +.footer { + margin-bottom: 60px; + display: flex; + justify-content: center; + gap: 32px; + align-items: center; +} diff --git a/React/src/app/pages/game/GamePage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.tsx similarity index 78% rename from React/src/app/pages/game/GamePage.tsx rename to React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.tsx index 816d143..596d2a0 100644 --- a/React/src/app/pages/game/GamePage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.tsx @@ -1,18 +1,19 @@ import { useState } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; -import { Board } from "./components/Board"; -import { Footer } from "./components/Footer"; -import { Header } from "./components/Header"; -import { Modal } from "./components/Modal"; +import { Board } from "../components/Board"; +import { Footer } from "../components/Footer"; +import { Header } from "../components/Header"; +import { ResultModal } from "../components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; -import classes from "./GamePage.module.scss"; +import classes from "./PlayerVsPlayerPage.module.scss"; +import { isBoardFull } from "~/utils/isboardfull"; const INITIAL_BOARD = Array(3) .fill(null) .map(() => Array(3).fill(null)); -export function GamePage() { +export function PlayerVsPlayerPage() { const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); const [currentPlayer, setCurrentPlayer] = useState( generateRandomTurn() @@ -26,6 +27,9 @@ export function GamePage() { setBoardData([...boardData]); if (checkWinner()) return; + if (isBoardFull(boardData)) { + setShowModal(true); + } setCurrentPlayer(currentPlayer === P1 ? P2 : P1); }; @@ -65,8 +69,8 @@ export function GamePage() { />
- {showModal && } diff --git a/React/src/app/pages/game/PlayerVsPlayerPage/index.ts b/React/src/app/pages/game/PlayerVsPlayerPage/index.ts new file mode 100644 index 0000000..f813908 --- /dev/null +++ b/React/src/app/pages/game/PlayerVsPlayerPage/index.ts @@ -0,0 +1 @@ +export * from "./PlayerVsPlayerPage"; diff --git a/React/src/app/pages/game/components/Footer/Footer.tsx b/React/src/app/pages/game/components/Footer/Footer.tsx index 177c735..fccbfe4 100644 --- a/React/src/app/pages/game/components/Footer/Footer.tsx +++ b/React/src/app/pages/game/components/Footer/Footer.tsx @@ -8,7 +8,7 @@ interface Props { export function Footer({ onRefresh }: Props) { return ( ); diff --git a/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx b/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx index 5ca7ac7..8659775 100644 --- a/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx +++ b/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx @@ -2,17 +2,17 @@ import classes from "./GamePageButtons.module.scss"; interface Props { onRefresh: () => void; - winner: string | undefined; + modal: boolean; } -export function GamePageButtons({ winner, onRefresh }: Props){ +export function GamePageButtons({ modal, onRefresh }: Props){ return ( <> - onRefresh()}> + onRefresh()}> refresh - + home diff --git a/React/src/app/pages/game/components/Modal/Modal.tsx b/React/src/app/pages/game/components/Modal/Modal.tsx deleted file mode 100644 index b8d1c1b..0000000 --- a/React/src/app/pages/game/components/Modal/Modal.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import classes from "./Modal.module.scss"; -import { P1 } from "~/utils/players"; -import { GamePageButtons } from "../GamePageButtons"; -import { GameMode } from "~/utils/game-mode"; - -interface Props { - winner: string; - onRefresh: () => void; - gameMode: GameMode; -} - -export function Modal({ winner, onRefresh, gameMode }: Props) { - return ( -
-
-
-
- x -
-
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
-
- -
-
-
-
- ) -} diff --git a/React/src/app/pages/game/components/Modal/Modal.module.scss b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.module.scss similarity index 85% rename from React/src/app/pages/game/components/Modal/Modal.module.scss rename to React/src/app/pages/game/components/Modal/ResultModal/ResultModal.module.scss index d8c7872..b0461ed 100644 --- a/React/src/app/pages/game/components/Modal/Modal.module.scss +++ b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.module.scss @@ -6,7 +6,7 @@ display: flex; justify-content: center; align-items: center; - animation: backDropOpen 1s forwards ease-in-out; + animation: backDropOpen .8s forwards ease-in-out; } .main { @@ -16,7 +16,7 @@ border: 1px solid #5570fd; border-radius: 56px; padding: 8px; - animation: scaleUp 1s 1s forwards ease-in-out; + animation: scaleUp .5s .8s forwards ease-in-out; } .container { @@ -40,6 +40,12 @@ font-size: 24px; } +.drawText { + margin-bottom: 50px; + color: #E9E9E9; + font-size: 45px; +} + .footer { margin-bottom: 60px; display: flex; diff --git a/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx new file mode 100644 index 0000000..4dfabe0 --- /dev/null +++ b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx @@ -0,0 +1,36 @@ +import classes from "./ResultModal.module.scss"; +import { P1 } from "~/utils/players"; +import { GamePageButtons } from "../../GamePageButtons"; +import { GameMode } from "~/utils/game-mode"; + +interface Props { + winner: string | undefined; + onRefresh: () => void; + gameMode: GameMode; +} + +export function ResultModal({ winner, onRefresh, gameMode }: Props) { + + let resultModalIcon = <>; + let resultModalText =
It's Draw
; + if (winner) { + resultModalIcon = x; + resultModalText =
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
; + } + + return ( +
+
+
+
+ {resultModalIcon} +
+ {resultModalText} +
+ +
+
+
+
+ ) +} diff --git a/React/src/app/pages/game/components/Modal/ResultModal/index.ts b/React/src/app/pages/game/components/Modal/ResultModal/index.ts new file mode 100644 index 0000000..3c4657c --- /dev/null +++ b/React/src/app/pages/game/components/Modal/ResultModal/index.ts @@ -0,0 +1 @@ +export * from "./ResultModal" \ No newline at end of file diff --git a/React/src/app/pages/game/components/Modal/index.ts b/React/src/app/pages/game/components/Modal/index.ts deleted file mode 100644 index 4800f16..0000000 --- a/React/src/app/pages/game/components/Modal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Modal" \ No newline at end of file diff --git a/React/src/app/pages/game/index.ts b/React/src/app/pages/game/index.ts deleted file mode 100644 index d5ed319..0000000 --- a/React/src/app/pages/game/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./GamePage"; diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index 3eb9980..ea3f0c2 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -22,10 +22,10 @@ export function HomePage() { />
- + Play Now! - + Play with bot diff --git a/React/src/app/utils/isboardfull.ts b/React/src/app/utils/isboardfull.ts new file mode 100644 index 0000000..278837c --- /dev/null +++ b/React/src/app/utils/isboardfull.ts @@ -0,0 +1,3 @@ +export function isBoardFull(board: string[][]) { + return !board.some(row => row.some(cell => cell == null)); +} \ No newline at end of file diff --git a/React/src/app/utils/minimax.ts b/React/src/app/utils/minimax.ts index 59c233a..1d794ad 100644 --- a/React/src/app/utils/minimax.ts +++ b/React/src/app/utils/minimax.ts @@ -1,16 +1,13 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; - -function isAvailableCell(board: string[][]) { - return board.some(row => row.some(cell => cell == null)); -} +import { isBoardFull } from "./isboardfull"; export function minimax(board: any[][], depth: number, isMaximizing: boolean) { let current = isMaximizing ? P2 : P1; let winResult = checkBoard(board, current); if (winResult) return isMaximizing ? 1 : -1; - if (!isAvailableCell(board)) return 0; + if (isBoardFull(board)) return 0; if (isMaximizing) return findMaxMove(board, depth); return findMinMove(board, depth) From 383c82a34e92b34459feaef52d7699105effe190 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 7 May 2023 13:01:47 +0430 Subject: [PATCH 05/22] Done === change bot page name --- React/src/app/AppRouter.tsx | 4 ++-- React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/React/src/app/AppRouter.tsx b/React/src/app/AppRouter.tsx index b1c5971..2e0de8f 100644 --- a/React/src/app/AppRouter.tsx +++ b/React/src/app/AppRouter.tsx @@ -8,7 +8,7 @@ import { import { HomePage } from "./pages/home"; import { PlayerVsPlayerPage } from "./pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage"; -import {BotGamePage} from "./pages/game/PlayerVsBotPage/PlayerVsBotPage" +import { PlayerVsBotPage } from "./pages/game/PlayerVsBotPage"; const rootRoute = new RootRoute({ component: () => , @@ -29,7 +29,7 @@ const gameRoute = new Route({ const botGameRoute = new Route({ getParentRoute: () => rootRoute, path: "/playerVsBot", - component: BotGamePage, + component: PlayerVsBotPage, }); const routeTree = rootRoute.addChildren([homeRoute, gameRoute, botGameRoute]); diff --git a/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx index 46484d5..67fdf48 100644 --- a/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx @@ -14,7 +14,7 @@ const INITIAL_BOARD = Array(3) .fill(null) .map(() => Array(3).fill(null)); -export function BotGamePage() { +export function PlayerVsBotPage() { const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); const [currentPlayer, setCurrentPlayer] = useState( generateRandomTurn() From 41084160eff659552844132892f3ff14a4418105 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Thu, 18 May 2023 00:53:49 +0430 Subject: [PATCH 06/22] Done === add nesting file setting remove extra files change modal conditions implement move minimax to utils --- React/src/app/AppRouter.tsx | 6 +- .../game/BotGamePage/BotGamePage.module.scss | 33 ----- .../pages/game/BotGamePage/BotGamePage.tsx | 118 ------------------ React/src/app/pages/game/BotGamePage/index.ts | 1 - .../PlayerVsBotPage.module.scss | 0 .../{PlayerVsBotPage => }/PlayerVsBotPage.tsx | 37 ++---- .../app/pages/game/PlayerVsBotPage/index.ts | 1 - .../PlayerVsPlayerPage.module.scss | 0 .../PlayerVsPlayerPage.tsx | 15 ++- .../pages/game/components/Footer/Footer.tsx | 1 - .../GamePageButtons/GamePageButtons.tsx | 8 +- .../Modal/ResultModal/ResultModal.tsx | 14 +-- .../game/{PlayerVsPlayerPage => }/index.ts | 1 + React/src/app/pages/home/HomePage.tsx | 4 +- .../utils/{minimax.ts => bot-move-logic.ts} | 22 +++- 15 files changed, 57 insertions(+), 204 deletions(-) delete mode 100644 React/src/app/pages/game/BotGamePage/BotGamePage.module.scss delete mode 100644 React/src/app/pages/game/BotGamePage/BotGamePage.tsx delete mode 100644 React/src/app/pages/game/BotGamePage/index.ts rename React/src/app/pages/game/{PlayerVsBotPage => }/PlayerVsBotPage.module.scss (100%) rename React/src/app/pages/game/{PlayerVsBotPage => }/PlayerVsBotPage.tsx (76%) delete mode 100644 React/src/app/pages/game/PlayerVsBotPage/index.ts rename React/src/app/pages/game/{PlayerVsPlayerPage => }/PlayerVsPlayerPage.module.scss (100%) rename React/src/app/pages/game/{PlayerVsPlayerPage => }/PlayerVsPlayerPage.tsx (85%) rename React/src/app/pages/game/{PlayerVsPlayerPage => }/index.ts (52%) rename React/src/app/utils/{minimax.ts => bot-move-logic.ts} (68%) diff --git a/React/src/app/AppRouter.tsx b/React/src/app/AppRouter.tsx index 2e0de8f..ccaf88e 100644 --- a/React/src/app/AppRouter.tsx +++ b/React/src/app/AppRouter.tsx @@ -7,7 +7,7 @@ import { } from "@tanstack/react-router"; import { HomePage } from "./pages/home"; -import { PlayerVsPlayerPage } from "./pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage"; +import { PlayerVsPlayerPage } from "./pages/game/PlayerVsPlayerPage"; import { PlayerVsBotPage } from "./pages/game/PlayerVsBotPage"; const rootRoute = new RootRoute({ @@ -22,13 +22,13 @@ const homeRoute = new Route({ const gameRoute = new Route({ getParentRoute: () => rootRoute, - path: "/playerVsplayer", + path: "/player-vs-player", component: PlayerVsPlayerPage, }); const botGameRoute = new Route({ getParentRoute: () => rootRoute, - path: "/playerVsBot", + path: "/player-vs-bot", component: PlayerVsBotPage, }); diff --git a/React/src/app/pages/game/BotGamePage/BotGamePage.module.scss b/React/src/app/pages/game/BotGamePage/BotGamePage.module.scss deleted file mode 100644 index 6037a56..0000000 --- a/React/src/app/pages/game/BotGamePage/BotGamePage.module.scss +++ /dev/null @@ -1,33 +0,0 @@ -.page { - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - width: 100%; - height: 100%; - background-image: url("static/images/game-page_bg.svg"); - background-size: 100% 100%; - background-repeat: no-repeat; -} - -.header { - display: flex; - gap: 16px; - margin-top: 36px; - align-items: center; - font-family: Arial, Helvetica, sans-serif; - color: white; -} - -.body { - display: flex; - justify-content: center; -} - -.footer { - margin-bottom: 60px; - display: flex; - justify-content: center; - gap: 32px; - align-items: center; -} diff --git a/React/src/app/pages/game/BotGamePage/BotGamePage.tsx b/React/src/app/pages/game/BotGamePage/BotGamePage.tsx deleted file mode 100644 index 53033b9..0000000 --- a/React/src/app/pages/game/BotGamePage/BotGamePage.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useState, useRef, useEffect } from "react"; -import { checkBoard } from "~/utils/check-board"; -import { P1, P2, generateRandomTurn } from "~/utils/players"; -import { Board } from "../components/Board"; -import { Footer } from "../components/Footer"; -import { Header } from "../components/Header"; -import { Modal } from "../components/Modal"; -import { GameMode } from "~/utils/game-mode"; -import { minimax } from "~/utils/minimax"; -import classes from "./BotGamePage.module.scss"; - -const INITIAL_BOARD = Array(3) - .fill(null) - .map(() => Array(3).fill(null)); - -export function BotGamePage() { - const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); - const [currentPlayer, setCurrentPlayer] = useState( - generateRandomTurn() - ); - const [result, setResult] = useState(); - const [showModal, setShowModal] = useState(false); - const isFirstMove = useRef(true); - - useEffect(() => { - if (isFirstMove.current && currentPlayer === P2) { - handleBot(); - } - isFirstMove.current = false; - }, [isFirstMove.current]) - - const handleClick = (i: number, j: number) => { - if (boardData[i][j] || result) return; - if (currentPlayer === P1) { - boardData[i][j] = currentPlayer; - setBoardData([...boardData]); - if (checkWinner(P1)) return; - setCurrentPlayer(P2); - handleBot(); - } - }; - - const handleBot = () => { - - let bestScore = -Infinity; - let move; - for (let i = 0; i < 3; i++) { - for (let j = 0; j < 3; j++) { - if (boardData[i][j] == null) { - boardData[i][j] = P2; - let score = minimax(boardData, 0, false); - boardData[i][j] = null; - if (score > bestScore) { - bestScore = score; - move = { i, j }; - } - } - } - } - if (move) { - boardData[move.i][move.j] = P2; - } - setBoardData([...boardData]); - if (checkWinner(P2)) return; - setCurrentPlayer(P1); - }; - - const checkWinner = (currentPlayer: string) => { - const winResult = checkBoard(boardData, currentPlayer); - if (!winResult) return false; - setResult(winResult); - setTimeout(() => { - setShowModal(true); - }, 500); - return true; - }; - - const refreshBoard = () => { - let newRandomTurnGenerator = generateRandomTurn(); - setBoardData(structuredClone(INITIAL_BOARD)); - setCurrentPlayer(newRandomTurnGenerator); - if (newRandomTurnGenerator === P2) { - isFirstMove.current = true; - } - setResult(undefined); - setShowModal(false); - } - - return ( -
-
-
-
- -
- -
- - {showModal && } - -
-
-
-
- ); -} diff --git a/React/src/app/pages/game/BotGamePage/index.ts b/React/src/app/pages/game/BotGamePage/index.ts deleted file mode 100644 index 0144240..0000000 --- a/React/src/app/pages/game/BotGamePage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./BotGamePage"; diff --git a/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.module.scss b/React/src/app/pages/game/PlayerVsBotPage.module.scss similarity index 100% rename from React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.module.scss rename to React/src/app/pages/game/PlayerVsBotPage.module.scss diff --git a/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx similarity index 76% rename from React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx rename to React/src/app/pages/game/PlayerVsBotPage.tsx index 67fdf48..b693d41 100644 --- a/React/src/app/pages/game/PlayerVsBotPage/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -1,24 +1,21 @@ import { useState, useRef, useEffect } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; -import { Board } from "../components/Board"; -import { Footer } from "../components/Footer"; -import { Header } from "../components/Header"; -import { ResultModal } from "../components/Modal/ResultModal"; +import { Footer } from "./components/Footer"; +import { Header } from "./components/Header"; +import { ResultModal } from "./components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; -import { minimax } from "~/utils/minimax"; import classes from "./PlayerVsBotPage.module.scss"; import { isBoardFull } from "~/utils/isboardfull"; - +import { botMove } from "~/utils/bot-move-logic"; +import { Board } from "./components/Board"; const INITIAL_BOARD = Array(3) .fill(null) .map(() => Array(3).fill(null)); export function PlayerVsBotPage() { const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); - const [currentPlayer, setCurrentPlayer] = useState( - generateRandomTurn() - ); + const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [result, setResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); @@ -36,6 +33,10 @@ export function PlayerVsBotPage() { boardData[i][j] = currentPlayer; setBoardData([...boardData]); if (checkWinner(P1)) return; + if (isBoardFull(boardData)) { + setShowModal(true); + return; + } setCurrentPlayer(P2); handleBot(); } @@ -43,21 +44,7 @@ export function PlayerVsBotPage() { const handleBot = () => { - let bestScore = -Infinity; - let move; - for (let i = 0; i < 3; i++) { - for (let j = 0; j < 3; j++) { - if (boardData[i][j] == null) { - boardData[i][j] = P2; - let score = minimax(boardData, 0, false); - boardData[i][j] = null; - if (score > bestScore) { - bestScore = score; - move = { i, j }; - } - } - } - } + let move = botMove(boardData) if (move) { boardData[move.i][move.j] = P2; } @@ -109,7 +96,7 @@ export function PlayerVsBotPage() {
{showModal && } diff --git a/React/src/app/pages/game/PlayerVsBotPage/index.ts b/React/src/app/pages/game/PlayerVsBotPage/index.ts deleted file mode 100644 index 12a02b3..0000000 --- a/React/src/app/pages/game/PlayerVsBotPage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./PlayerVsBotPage"; diff --git a/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.module.scss b/React/src/app/pages/game/PlayerVsPlayerPage.module.scss similarity index 100% rename from React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.module.scss rename to React/src/app/pages/game/PlayerVsPlayerPage.module.scss diff --git a/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage.tsx similarity index 85% rename from React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.tsx rename to React/src/app/pages/game/PlayerVsPlayerPage.tsx index 596d2a0..2e4b8b3 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage/PlayerVsPlayerPage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage.tsx @@ -1,10 +1,10 @@ import { useState } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; -import { Board } from "../components/Board"; -import { Footer } from "../components/Footer"; -import { Header } from "../components/Header"; -import { ResultModal } from "../components/Modal/ResultModal"; +import { Board } from "./components/Board"; +import { Footer } from "./components/Footer"; +import { Header } from "./components/Header"; +import { ResultModal } from "./components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; import classes from "./PlayerVsPlayerPage.module.scss"; import { isBoardFull } from "~/utils/isboardfull"; @@ -15,9 +15,7 @@ const INITIAL_BOARD = Array(3) export function PlayerVsPlayerPage() { const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); - const [currentPlayer, setCurrentPlayer] = useState( - generateRandomTurn() - ); + const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [result, setResult] = useState(); const [showModal, setShowModal] = useState(false); @@ -29,6 +27,7 @@ export function PlayerVsPlayerPage() { if (checkWinner()) return; if (isBoardFull(boardData)) { setShowModal(true); + return; } setCurrentPlayer(currentPlayer === P1 ? P2 : P1); @@ -70,7 +69,7 @@ export function PlayerVsPlayerPage() {
{showModal && } diff --git a/React/src/app/pages/game/components/Footer/Footer.tsx b/React/src/app/pages/game/components/Footer/Footer.tsx index fccbfe4..77ec50c 100644 --- a/React/src/app/pages/game/components/Footer/Footer.tsx +++ b/React/src/app/pages/game/components/Footer/Footer.tsx @@ -8,7 +8,6 @@ interface Props { export function Footer({ onRefresh }: Props) { return ( ); diff --git a/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx b/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx index 8659775..2adefbf 100644 --- a/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx +++ b/React/src/app/pages/game/components/GamePageButtons/GamePageButtons.tsx @@ -2,17 +2,17 @@ import classes from "./GamePageButtons.module.scss"; interface Props { onRefresh: () => void; - modal: boolean; + inResultModal?: boolean; } -export function GamePageButtons({ modal, onRefresh }: Props){ +export function GamePageButtons({ inResultModal, onRefresh }: Props){ return ( <> - onRefresh()}> + onRefresh()}> refresh - + home diff --git a/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx index 4dfabe0..dccf864 100644 --- a/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx +++ b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx @@ -11,11 +11,11 @@ interface Props { export function ResultModal({ winner, onRefresh, gameMode }: Props) { - let resultModalIcon = <>; - let resultModalText =
It's Draw
; + let resultModalIconSrc = ""; + let resultModalText = "Draw"; if (winner) { - resultModalIcon = x; - resultModalText =
{gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`}
; + resultModalIconSrc = gameMode === GameMode.playerVsBot ? `static/images/${winner === P1 ? 'smile' : 'sad'}.svg` : `static/images/${winner === P1 ? 'Xmodal' : 'Omodal'}.svg`; + resultModalText = gameMode === GameMode.playerVsBot ? winner === P1 ? "you Won" : "you Lost" : `Player ${winner === P1 ? 1 : 2} Won!`; } return ( @@ -23,11 +23,11 @@ export function ResultModal({ winner, onRefresh, gameMode }: Props) {
- {resultModalIcon} +
- {resultModalText} +
{resultModalText}
- +
diff --git a/React/src/app/pages/game/PlayerVsPlayerPage/index.ts b/React/src/app/pages/game/index.ts similarity index 52% rename from React/src/app/pages/game/PlayerVsPlayerPage/index.ts rename to React/src/app/pages/game/index.ts index f813908..5537a2c 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage/index.ts +++ b/React/src/app/pages/game/index.ts @@ -1 +1,2 @@ export * from "./PlayerVsPlayerPage"; +export * from "./PlayerVsBotPage"; diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index ea3f0c2..9d04cb0 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -22,10 +22,10 @@ export function HomePage() { />
- + Play Now! - + Play with bot diff --git a/React/src/app/utils/minimax.ts b/React/src/app/utils/bot-move-logic.ts similarity index 68% rename from React/src/app/utils/minimax.ts rename to React/src/app/utils/bot-move-logic.ts index 1d794ad..4953cab 100644 --- a/React/src/app/utils/minimax.ts +++ b/React/src/app/utils/bot-move-logic.ts @@ -2,7 +2,27 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; import { isBoardFull } from "./isboardfull"; -export function minimax(board: any[][], depth: number, isMaximizing: boolean) { +export function botMove(board: any[][]) { + let bestScore = -Infinity; + let move; + for (let i = 0; i < 3; i++) { + for (let j = 0; j < 3; j++) { + if (board[i][j] == null) { + board[i][j] = P2; + let score = minimax(board, 0, false); + board[i][j] = null; + if (score > bestScore) { + bestScore = score; + move = { i, j }; + } + } + } + } + return move; +} + +function minimax(board: any[][], depth: number, isMaximizing: boolean) { + let current = isMaximizing ? P2 : P1; let winResult = checkBoard(board, current); From e2052deaaad2e56705d9f151356ea3b05e704dd7 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Tue, 30 May 2023 15:42:40 +0430 Subject: [PATCH 07/22] Done === add 3x3 & 6x6 & 9x9 image slider in HomePage --- React/src/app/pages/home/HomePage.module.scss | 60 ++++++++++++++++++- React/src/app/pages/home/HomePage.tsx | 23 +++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/React/src/app/pages/home/HomePage.module.scss b/React/src/app/pages/home/HomePage.module.scss index b54b916..30e221d 100644 --- a/React/src/app/pages/home/HomePage.module.scss +++ b/React/src/app/pages/home/HomePage.module.scss @@ -8,12 +8,12 @@ } .title { - justify-content: center; position: relative; } .titleImg { - width: 170px; + width: 130px; + margin-top: 30px; } .titleBg1 { @@ -30,6 +30,8 @@ .body { gap: 16px; + justify-content: flex-end; + padding-bottom: 20px; background-image: url("static/images/bg.png"); background-repeat: no-repeat; background-size: cover; @@ -72,4 +74,58 @@ font-family: Arial, Helvetica, sans-serif; background: linear-gradient(#4b61e9, #4b61e9) padding-box, linear-gradient(to right, rgba(255, 255, 255, 0.5), #5570fd) border-box; +} + +.boardSizesContainer { + position: absolute; + top: 50%; + transform: translate3d(0%, -65%, 0); + width: 100%; + gap: 85px; + height: 200px; + display: flex; + overflow: hidden; + align-items: center; + justify-content: center; +} + +.boardSize { + width: 126px; + height: auto; +} + +.boardSizeSelected { + // scale: 1.3; +} + +.vectorContainer { + position: absolute; + width: 215px; + top: 46.5%; + left: 50%; + transform: translate(-50%, 0%); + z-index: 2; +} + +.vectorContainer img { + position: absolute; + width: 17px; + height: 32px; + top: 50%; + z-index: 1; + transform: translate3d(0, -20%, 0); + transition: .3s; + cursor: pointer; +} + +.vectorContainer img:hover { + scale: 1.1; +} + +.leftVector { + left: 0; +} + +.rightVector { + right: 0; } \ No newline at end of file diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index 3eb9980..e87e05e 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -1,7 +1,21 @@ import { Link } from "@tanstack/react-router"; +import { useState } from "react"; import classes from "./HomePage.module.scss"; +const boardSizes = [3, 6, 9]; export function HomePage() { + +const [selectedSize,setSelectedSize] = useState(6); + + function clickLeftVector() { + selectedSize != 3 && setSelectedSize(selectedSize - 3); + + } + + function clickRightVector() { + selectedSize != 9 && setSelectedSize(selectedSize + 3); + } + return ( <>
@@ -21,6 +35,15 @@ export function HomePage() { className={classes.titleBg2} />
+
+ leftVector + rightVector +
+
+ {boardSizes.map((board, i) => ( + + ))} +
Play Now! From 29f56e3a22ef5fa7ec50274d735ada09842d64b0 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Tue, 30 May 2023 21:05:57 +0430 Subject: [PATCH 08/22] Done --- React/src/app/pages/home/HomePage.module.scss | 11 ++++------- React/src/app/pages/home/HomePage.tsx | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/React/src/app/pages/home/HomePage.module.scss b/React/src/app/pages/home/HomePage.module.scss index 30e221d..596e76a 100644 --- a/React/src/app/pages/home/HomePage.module.scss +++ b/React/src/app/pages/home/HomePage.module.scss @@ -31,10 +31,11 @@ .body { gap: 16px; justify-content: flex-end; - padding-bottom: 20px; + padding-bottom: 30px; background-image: url("static/images/bg.png"); background-repeat: no-repeat; background-size: cover; + } .palyNowButton, @@ -94,16 +95,12 @@ height: auto; } -.boardSizeSelected { - // scale: 1.3; -} - .vectorContainer { position: absolute; width: 215px; top: 46.5%; left: 50%; - transform: translate(-50%, 0%); + transform: translate(-50.5%, 0%); z-index: 2; } @@ -128,4 +125,4 @@ .rightVector { right: 0; -} \ No newline at end of file +} diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index e87e05e..ce9e549 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -5,7 +5,7 @@ import classes from "./HomePage.module.scss"; const boardSizes = [3, 6, 9]; export function HomePage() { -const [selectedSize,setSelectedSize] = useState(6); +const [selectedSize,setSelectedSize] = useState(boardSizes[1]); function clickLeftVector() { selectedSize != 3 && setSelectedSize(selectedSize - 3); @@ -41,7 +41,7 @@ const [selectedSize,setSelectedSize] = useState(6);
{boardSizes.map((board, i) => ( - + ))}
From 191949e1775fae45cb3622b9e216031e3a8a561f Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Thu, 1 Jun 2023 23:29:31 +0430 Subject: [PATCH 09/22] Done === change names --- React/src/app/pages/game/PlayerVsBotPage.tsx | 34 +++++++++---------- .../src/app/pages/game/PlayerVsPlayerPage.tsx | 24 ++++++------- .../{isboardfull.ts => any-moves-left.ts} | 2 +- ...ot-move-logic.ts => find-best-bot-move.ts} | 12 +++---- 4 files changed, 34 insertions(+), 38 deletions(-) rename React/src/app/utils/{isboardfull.ts => any-moves-left.ts} (56%) rename React/src/app/utils/{bot-move-logic.ts => find-best-bot-move.ts} (88%) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index b693d41..98daa93 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -6,8 +6,8 @@ import { Header } from "./components/Header"; import { ResultModal } from "./components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; import classes from "./PlayerVsBotPage.module.scss"; -import { isBoardFull } from "~/utils/isboardfull"; -import { botMove } from "~/utils/bot-move-logic"; +import { anyMovesLeft } from "~/utils/any-moves-left"; +import { findBestBotMove } from "~/utils/find-best-bot-move"; import { Board } from "./components/Board"; const INITIAL_BOARD = Array(3) .fill(null) @@ -16,7 +16,7 @@ const INITIAL_BOARD = Array(3) export function PlayerVsBotPage() { const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); - const [result, setResult] = useState(); + const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); @@ -28,12 +28,12 @@ export function PlayerVsBotPage() { }, [isFirstMove.current]) const handleClick = (i: number, j: number) => { - if (boardData[i][j] || result) return; + if (boardData[i][j] || winResult) return; if (currentPlayer === P1) { boardData[i][j] = currentPlayer; setBoardData([...boardData]); if (checkWinner(P1)) return; - if (isBoardFull(boardData)) { + if (anyMovesLeft(boardData)) { setShowModal(true); return; } @@ -44,25 +44,23 @@ export function PlayerVsBotPage() { const handleBot = () => { - let move = botMove(boardData) - if (move) { - boardData[move.i][move.j] = P2; + let movement = findBestBotMove(boardData) + if (movement) { + boardData[movement.i][movement.j] = P2; } setBoardData([...boardData]); if (checkWinner(P2)) return; - if (isBoardFull(boardData)) { + if (anyMovesLeft(boardData)) { setShowModal(true); } setCurrentPlayer(P1); }; const checkWinner = (currentPlayer: string) => { - const winResult = checkBoard(boardData, currentPlayer); - if (!winResult) return false; - setResult(winResult); - setTimeout(() => { - setShowModal(true); - }, 500); + const result = checkBoard(boardData, currentPlayer); + if (!result) return false; + setWinResult(result); + setShowModal(true); return true; }; @@ -73,7 +71,7 @@ export function PlayerVsBotPage() { if (newRandomTurnGenerator === P2) { isFirstMove.current = true; } - setResult(undefined); + setWinResult(undefined); setShowModal(false); } @@ -91,12 +89,12 @@ export function PlayerVsBotPage() { boardData={boardData} onClick={handleClick} currentPlayer={currentPlayer} - result={result} + result={winResult} />
{showModal && } diff --git a/React/src/app/pages/game/PlayerVsPlayerPage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage.tsx index 2e4b8b3..d8711c7 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage.tsx @@ -7,7 +7,7 @@ import { Header } from "./components/Header"; import { ResultModal } from "./components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; import classes from "./PlayerVsPlayerPage.module.scss"; -import { isBoardFull } from "~/utils/isboardfull"; +import { anyMovesLeft } from "~/utils/any-moves-left"; const INITIAL_BOARD = Array(3) .fill(null) @@ -16,16 +16,16 @@ const INITIAL_BOARD = Array(3) export function PlayerVsPlayerPage() { const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); - const [result, setResult] = useState(); + const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const handleClick = (i: number, j: number) => { - if (boardData[i][j] || result) return; + if (boardData[i][j] || winResult) return; boardData[i][j] = currentPlayer; setBoardData([...boardData]); if (checkWinner()) return; - if (isBoardFull(boardData)) { + if (anyMovesLeft(boardData)) { setShowModal(true); return; } @@ -34,19 +34,17 @@ export function PlayerVsPlayerPage() { }; const checkWinner = () => { - const winResult = checkBoard(boardData, currentPlayer); - if (!winResult) return false; - setResult(winResult); - setTimeout(() => { - setShowModal(true); - }, 500); + const result = checkBoard(boardData, currentPlayer); + if (!result) return false; + setWinResult(winResult); + setShowModal(true); return true; }; const refreshBoard = () => { setBoardData(structuredClone(INITIAL_BOARD)); setCurrentPlayer(generateRandomTurn()); - setResult(undefined); + setWinResult(undefined); setShowModal(false); } @@ -64,12 +62,12 @@ export function PlayerVsPlayerPage() { boardData={boardData} onClick={handleClick} currentPlayer={currentPlayer} - result={result} + result={winResult} />
{showModal && } diff --git a/React/src/app/utils/isboardfull.ts b/React/src/app/utils/any-moves-left.ts similarity index 56% rename from React/src/app/utils/isboardfull.ts rename to React/src/app/utils/any-moves-left.ts index 278837c..5a80d18 100644 --- a/React/src/app/utils/isboardfull.ts +++ b/React/src/app/utils/any-moves-left.ts @@ -1,3 +1,3 @@ -export function isBoardFull(board: string[][]) { +export function anyMovesLeft(board: string[][]) { return !board.some(row => row.some(cell => cell == null)); } \ No newline at end of file diff --git a/React/src/app/utils/bot-move-logic.ts b/React/src/app/utils/find-best-bot-move.ts similarity index 88% rename from React/src/app/utils/bot-move-logic.ts rename to React/src/app/utils/find-best-bot-move.ts index 4953cab..7ba9eb9 100644 --- a/React/src/app/utils/bot-move-logic.ts +++ b/React/src/app/utils/find-best-bot-move.ts @@ -1,10 +1,10 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; -import { isBoardFull } from "./isboardfull"; +import { anyMovesLeft } from "./any-moves-left"; -export function botMove(board: any[][]) { +export function findBestBotMove(board: any[][]) { let bestScore = -Infinity; - let move; + let movement; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (board[i][j] == null) { @@ -13,12 +13,12 @@ export function botMove(board: any[][]) { board[i][j] = null; if (score > bestScore) { bestScore = score; - move = { i, j }; + movement = { i, j }; } } } } - return move; + return movement; } function minimax(board: any[][], depth: number, isMaximizing: boolean) { @@ -27,7 +27,7 @@ function minimax(board: any[][], depth: number, isMaximizing: boolean) { let winResult = checkBoard(board, current); if (winResult) return isMaximizing ? 1 : -1; - if (isBoardFull(board)) return 0; + if (anyMovesLeft(board)) return 0; if (isMaximizing) return findMaxMove(board, depth); return findMinMove(board, depth) From bfd357d5f9df0015df3be393590171c3465ce640 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Thu, 31 Aug 2023 10:49:07 +0330 Subject: [PATCH 10/22] Done add context --- React/src/app/App.tsx | 22 ++++++++++++++++--- React/src/app/pages/game/PlayerVsBotPage.tsx | 7 ++++-- .../src/app/pages/game/PlayerVsPlayerPage.tsx | 2 +- .../app/pages/game/components/Board/Board.tsx | 1 - .../Modal/ResultModal/ResultModal.tsx | 1 - React/src/app/pages/home/HomePage.tsx | 15 +++++++------ React/src/app/utils/globals.ts | 9 ++++++++ React/src/app/utils/winline-style-maker.ts | 5 +++-- 8 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 React/src/app/utils/globals.ts diff --git a/React/src/app/App.tsx b/React/src/app/App.tsx index 9f0906b..ea53c2a 100644 --- a/React/src/app/App.tsx +++ b/React/src/app/App.tsx @@ -1,11 +1,27 @@ +import { createContext, useState } from "react"; import classes from "./App.module.scss"; import { AppRouter } from "./AppRouter"; +interface IContextValue { + selectedSize: number; + setSelectedSize: React.Dispatch> +} + +export const boardSizeContext = createContext({ selectedSize: 3, setSelectedSize: () => { } }); + + function App() { + const [selectedSize, setSelectedSize] = useState(3); + const contextValue = { + selectedSize, + setSelectedSize + } return ( -
- -
+ +
+ +
+
); } diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index 98daa93..a7bf47b 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -1,4 +1,4 @@ -import { useState, useRef, useEffect } from "react"; +import { useState, useRef, useEffect, useContext } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; import { Footer } from "./components/Footer"; @@ -9,6 +9,9 @@ import classes from "./PlayerVsBotPage.module.scss"; import { anyMovesLeft } from "~/utils/any-moves-left"; import { findBestBotMove } from "~/utils/find-best-bot-move"; import { Board } from "./components/Board"; +import { globals } from "~/utils/globals"; +import { boardSizeContext } from "~/App"; + const INITIAL_BOARD = Array(3) .fill(null) .map(() => Array(3).fill(null)); @@ -19,7 +22,7 @@ export function PlayerVsBotPage() { const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); - + const {selectedSize} = useContext(boardSizeContext); useEffect(() => { if (isFirstMove.current && currentPlayer === P2) { handleBot(); diff --git a/React/src/app/pages/game/PlayerVsPlayerPage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage.tsx index d8711c7..81f30e6 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage.tsx @@ -36,7 +36,7 @@ export function PlayerVsPlayerPage() { const checkWinner = () => { const result = checkBoard(boardData, currentPlayer); if (!result) return false; - setWinResult(winResult); + setWinResult(result); setShowModal(true); return true; }; diff --git a/React/src/app/pages/game/components/Board/Board.tsx b/React/src/app/pages/game/components/Board/Board.tsx index f0fb5d3..867ce9d 100644 --- a/React/src/app/pages/game/components/Board/Board.tsx +++ b/React/src/app/pages/game/components/Board/Board.tsx @@ -9,7 +9,6 @@ interface Props { } export function Board({ boardData, onClick, currentPlayer, result }: Props) { - const winLineStyle = winLineStyleMaker(currentPlayer, result); return (
diff --git a/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx index dccf864..0466108 100644 --- a/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx +++ b/React/src/app/pages/game/components/Modal/ResultModal/ResultModal.tsx @@ -10,7 +10,6 @@ interface Props { } export function ResultModal({ winner, onRefresh, gameMode }: Props) { - let resultModalIconSrc = ""; let resultModalText = "Draw"; if (winner) { diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index 3bfa94d..8063c35 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -1,21 +1,22 @@ import { Link } from "@tanstack/react-router"; -import { useState } from "react"; +import { useContext } from "react"; import classes from "./HomePage.module.scss"; +import { globals } from "~/utils/globals"; +import { boardSizeContext } from "~/App"; -const boardSizes = [3, 6, 9]; export function HomePage() { -const [selectedSize,setSelectedSize] = useState(boardSizes[1]); + const { selectedSize, setSelectedSize } = useContext(boardSizeContext) function clickLeftVector() { selectedSize != 3 && setSelectedSize(selectedSize - 3); - } function clickRightVector() { selectedSize != 9 && setSelectedSize(selectedSize + 3); } + return ( <>
@@ -40,15 +41,15 @@ const [selectedSize,setSelectedSize] = useState(boardSizes[1]); rightVector
- {boardSizes.map((board, i) => ( - + {globals.boardSizes.map((board, i) => ( + ))}
Play Now! - + Play with bot diff --git a/React/src/app/utils/globals.ts b/React/src/app/utils/globals.ts new file mode 100644 index 0000000..e9db389 --- /dev/null +++ b/React/src/app/utils/globals.ts @@ -0,0 +1,9 @@ + +interface GlobalTypes { + boardSizes: number[]; + selectedSize: number; +} +export const globals:GlobalTypes = { + boardSizes : [3,6,9], + selectedSize : 3, +} \ No newline at end of file diff --git a/React/src/app/utils/winline-style-maker.ts b/React/src/app/utils/winline-style-maker.ts index bdf286c..9bcca7c 100644 --- a/React/src/app/utils/winline-style-maker.ts +++ b/React/src/app/utils/winline-style-maker.ts @@ -1,11 +1,12 @@ import React, { CSSProperties } from "react"; +import { globals } from "./globals"; import { P1 } from "./players"; const boardWidth = 312; const mainBorderSize = 1; -const boardSize = 3; -const winLineSize = 3; +const boardSize = globals.selectedSize; +const winLineSize = globals.selectedSize; const padding = 12; const cellWidth = (boardWidth - 2 * (padding + mainBorderSize)) / boardSize; From 9080176fc677f952209bd2340e74dda85cd7eea6 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Mon, 25 Sep 2023 20:33:31 +0330 Subject: [PATCH 11/22] add selected size context to game pages && set it to initial board --- React/src/app/pages/game/PlayerVsBotPage.tsx | 12 ++++-------- React/src/app/pages/game/PlayerVsPlayerPage.tsx | 13 ++++++------- .../pages/game/components/Board/Board.module.scss | 5 +++-- React/src/app/pages/game/components/Board/Board.tsx | 2 +- React/src/app/pages/home/HomePage.tsx | 5 +++-- React/src/app/utils/reset-board.ts | 6 ++++++ 6 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 React/src/app/utils/reset-board.ts diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index a7bf47b..f86c605 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -9,20 +9,16 @@ import classes from "./PlayerVsBotPage.module.scss"; import { anyMovesLeft } from "~/utils/any-moves-left"; import { findBestBotMove } from "~/utils/find-best-bot-move"; import { Board } from "./components/Board"; -import { globals } from "~/utils/globals"; import { boardSizeContext } from "~/App"; - -const INITIAL_BOARD = Array(3) - .fill(null) - .map(() => Array(3).fill(null)); +import { resetBoard } from "~/utils/reset-board"; export function PlayerVsBotPage() { - const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); + const { selectedSize } = useContext(boardSizeContext); + const [boardData, setBoardData] = useState(structuredClone(resetBoard(selectedSize))); const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); - const {selectedSize} = useContext(boardSizeContext); useEffect(() => { if (isFirstMove.current && currentPlayer === P2) { handleBot(); @@ -69,7 +65,7 @@ export function PlayerVsBotPage() { const refreshBoard = () => { let newRandomTurnGenerator = generateRandomTurn(); - setBoardData(structuredClone(INITIAL_BOARD)); + setBoardData(structuredClone(resetBoard(selectedSize))); setCurrentPlayer(newRandomTurnGenerator); if (newRandomTurnGenerator === P2) { isFirstMove.current = true; diff --git a/React/src/app/pages/game/PlayerVsPlayerPage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage.tsx index 81f30e6..b8745ad 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; import { Board } from "./components/Board"; @@ -8,13 +8,12 @@ import { ResultModal } from "./components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; import classes from "./PlayerVsPlayerPage.module.scss"; import { anyMovesLeft } from "~/utils/any-moves-left"; - -const INITIAL_BOARD = Array(3) - .fill(null) - .map(() => Array(3).fill(null)); +import { boardSizeContext } from "~/App"; +import { resetBoard } from "~/utils/reset-board"; export function PlayerVsPlayerPage() { - const [boardData, setBoardData] = useState(structuredClone(INITIAL_BOARD)); + const { selectedSize } = useContext(boardSizeContext); + const [boardData, setBoardData] = useState(structuredClone(resetBoard(selectedSize))); const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); @@ -42,7 +41,7 @@ export function PlayerVsPlayerPage() { }; const refreshBoard = () => { - setBoardData(structuredClone(INITIAL_BOARD)); + setBoardData(structuredClone(resetBoard(selectedSize))); setCurrentPlayer(generateRandomTurn()); setWinResult(undefined); setShowModal(false); diff --git a/React/src/app/pages/game/components/Board/Board.module.scss b/React/src/app/pages/game/components/Board/Board.module.scss index 2cbd245..45f7852 100644 --- a/React/src/app/pages/game/components/Board/Board.module.scss +++ b/React/src/app/pages/game/components/Board/Board.module.scss @@ -21,13 +21,14 @@ .row { display: flex; + height: 100%; } .cell { border: 1px dashed #d9d9d9; - height: 96px; + height: 100%; display: flex; - flex-basis: 96px; + flex-basis: 100%; justify-content: center; align-items: center; cursor: pointer; diff --git a/React/src/app/pages/game/components/Board/Board.tsx b/React/src/app/pages/game/components/Board/Board.tsx index 867ce9d..43f42a3 100644 --- a/React/src/app/pages/game/components/Board/Board.tsx +++ b/React/src/app/pages/game/components/Board/Board.tsx @@ -13,7 +13,7 @@ export function Board({ boardData, onClick, currentPlayer, result }: Props) { return (
-
+
{boardData.map((row, i) => (
{row.map((col, j) => ( diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index 8063c35..0d3a335 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -42,8 +42,9 @@ export function HomePage() {
{globals.boardSizes.map((board, i) => ( - - ))} + + // , scale: `${(i + 1) * 3 == selectedSize ? 1.3 : 1}` + ))}
diff --git a/React/src/app/utils/reset-board.ts b/React/src/app/utils/reset-board.ts new file mode 100644 index 0000000..0eeff7d --- /dev/null +++ b/React/src/app/utils/reset-board.ts @@ -0,0 +1,6 @@ +export function resetBoard(selectedSize: number) { + return (Array(selectedSize) + .fill(null) + .map(() => Array(selectedSize).fill(null)) + ) +} \ No newline at end of file From a6c04ec3a1fde35f1991aa94bb57b65f676fbb83 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Fri, 29 Sep 2023 10:37:54 +0330 Subject: [PATCH 12/22] fix cells borders and radius in any board size --- .../game/components/Board/Board.module.scss | 38 +++++++++---------- .../app/pages/game/components/Board/Board.tsx | 11 ++++-- React/src/app/utils/modifyBoardStyle.ts | 19 ++++++++++ 3 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 React/src/app/utils/modifyBoardStyle.ts diff --git a/React/src/app/pages/game/components/Board/Board.module.scss b/React/src/app/pages/game/components/Board/Board.module.scss index 45f7852..3d87afd 100644 --- a/React/src/app/pages/game/components/Board/Board.module.scss +++ b/React/src/app/pages/game/components/Board/Board.module.scss @@ -3,15 +3,13 @@ height: 312px; border: 1px solid #5570fd; backdrop-filter: blur(3px); - border-radius: 64px; padding: 12px; } -.container { +.template { display: flex; flex-direction: column; background-color: #191685; - border-radius: 56px; width: 100%; height: 100%; overflow: hidden; @@ -19,13 +17,20 @@ } +.container { + display: flex; + flex-direction: column; + height: 100%; +} + .row { display: flex; height: 100%; } .cell { - border: 1px dashed #d9d9d9; + border-top: 1px dashed #d9d9d9; + border-right: 1px dashed #d9d9d9; height: 100%; display: flex; flex-basis: 100%; @@ -35,28 +40,18 @@ -webkit-tap-highlight-color: transparent; } -.row:first-child :first-child, -.row:first-child :last-child { - border: none; -} - -.row:last-child :first-child, -.row:last-child :last-child { - border: none; -} - -.row:first-child :nth-child(2), -.row:last-child :nth-child(2) { +.container .row:first-child .cell { border-top: none; - border-bottom: none; } -.row:nth-child(2) :first-child, -.row:nth-child(2) :last-child { - border-left: none; +.container .row :last-child { border-right: none; } +.cell img { + width: 70%; +} + .winLine { border: 1px solid inherit; width: 4px; @@ -66,4 +61,5 @@ transform-origin: center top; transition: height 0.4s ease-in-out; visibility: hidden; -} \ No newline at end of file +} + diff --git a/React/src/app/pages/game/components/Board/Board.tsx b/React/src/app/pages/game/components/Board/Board.tsx index 43f42a3..0cf0444 100644 --- a/React/src/app/pages/game/components/Board/Board.tsx +++ b/React/src/app/pages/game/components/Board/Board.tsx @@ -1,5 +1,8 @@ import { winLineStyleMaker } from "~/utils/winline-style-maker"; import classes from "./Board.module.scss"; +import { boardSizeContext } from "~/App"; +import { useContext, useEffect, useState } from "react"; +import { modifyBoardStyle } from "~/utils/modifyBoardStyle"; interface Props { boardData: string[][]; @@ -10,10 +13,12 @@ interface Props { export function Board({ boardData, onClick, currentPlayer, result }: Props) { const winLineStyle = winLineStyleMaker(currentPlayer, result); + const { selectedSize } = useContext(boardSizeContext); + const [boardStyle] = useState(modifyBoardStyle(selectedSize)); return ( -
-
-
+
+
+
{boardData.map((row, i) => (
{row.map((col, j) => ( diff --git a/React/src/app/utils/modifyBoardStyle.ts b/React/src/app/utils/modifyBoardStyle.ts new file mode 100644 index 0000000..89f5fab --- /dev/null +++ b/React/src/app/utils/modifyBoardStyle.ts @@ -0,0 +1,19 @@ +interface BoardStyles { + mainRadius: string; + templateRadius: string; +} + +export function modifyBoardStyle(selectedSize: number) { + const boardStyles: BoardStyles = { mainRadius: "64px", templateRadius: "56px" }; + switch (selectedSize) { + case 6: + boardStyles.mainRadius = "42px"; + boardStyles.templateRadius = "30px"; + break; + case 9: + boardStyles.mainRadius = "36px"; + boardStyles.templateRadius = "20px"; + break; + } + return boardStyles;; +} \ No newline at end of file From c6ec610bc51121dad77c41927bd8bfa60bc6d944 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Fri, 29 Sep 2023 11:36:51 +0330 Subject: [PATCH 13/22] modify winlineStyle for any boardSize --- React/src/app/pages/game/PlayerVsBotPage.tsx | 9 ++++++++- React/src/app/pages/game/PlayerVsPlayerPage.tsx | 10 ++++++++-- .../src/app/pages/game/components/Board/Board.tsx | 4 ++-- React/src/app/utils/check-board.ts | 5 +---- React/src/app/utils/globals.ts | 12 ++++++++---- React/src/app/utils/winline-style-maker.ts | 14 ++++++-------- 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index f86c605..ddce1b2 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -11,6 +11,7 @@ import { findBestBotMove } from "~/utils/find-best-bot-move"; import { Board } from "./components/Board"; import { boardSizeContext } from "~/App"; import { resetBoard } from "~/utils/reset-board"; +import { createWinLines } from "~/utils/create-winlines"; export function PlayerVsBotPage() { const { selectedSize } = useContext(boardSizeContext); @@ -19,6 +20,12 @@ export function PlayerVsBotPage() { const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); + const [winLines, setWinlines] = useState() + + useEffect(() => { + setWinlines(createWinLines(selectedSize)); + }, []) + useEffect(() => { if (isFirstMove.current && currentPlayer === P2) { handleBot(); @@ -56,7 +63,7 @@ export function PlayerVsBotPage() { }; const checkWinner = (currentPlayer: string) => { - const result = checkBoard(boardData, currentPlayer); + const result = checkBoard(boardData, currentPlayer, winLines!); if (!result) return false; setWinResult(result); setShowModal(true); diff --git a/React/src/app/pages/game/PlayerVsPlayerPage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage.tsx index b8745ad..6e44015 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage.tsx @@ -1,4 +1,4 @@ -import { useContext, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; import { Board } from "./components/Board"; @@ -10,6 +10,7 @@ import classes from "./PlayerVsPlayerPage.module.scss"; import { anyMovesLeft } from "~/utils/any-moves-left"; import { boardSizeContext } from "~/App"; import { resetBoard } from "~/utils/reset-board"; +import { createWinLines } from "~/utils/create-winlines"; export function PlayerVsPlayerPage() { const { selectedSize } = useContext(boardSizeContext); @@ -17,6 +18,11 @@ export function PlayerVsPlayerPage() { const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); + const [winLines, setWinlines] = useState() + + useEffect(() => { + setWinlines(createWinLines(selectedSize)); + }, []) const handleClick = (i: number, j: number) => { if (boardData[i][j] || winResult) return; @@ -33,7 +39,7 @@ export function PlayerVsPlayerPage() { }; const checkWinner = () => { - const result = checkBoard(boardData, currentPlayer); + const result = checkBoard(boardData, currentPlayer,winLines!); if (!result) return false; setWinResult(result); setShowModal(true); diff --git a/React/src/app/pages/game/components/Board/Board.tsx b/React/src/app/pages/game/components/Board/Board.tsx index 0cf0444..1a8ca97 100644 --- a/React/src/app/pages/game/components/Board/Board.tsx +++ b/React/src/app/pages/game/components/Board/Board.tsx @@ -1,7 +1,7 @@ import { winLineStyleMaker } from "~/utils/winline-style-maker"; import classes from "./Board.module.scss"; import { boardSizeContext } from "~/App"; -import { useContext, useEffect, useState } from "react"; +import { useContext, useState } from "react"; import { modifyBoardStyle } from "~/utils/modifyBoardStyle"; interface Props { @@ -12,8 +12,8 @@ interface Props { } export function Board({ boardData, onClick, currentPlayer, result }: Props) { - const winLineStyle = winLineStyleMaker(currentPlayer, result); const { selectedSize } = useContext(boardSizeContext); + const winLineStyle = winLineStyleMaker(currentPlayer, selectedSize, result); const [boardStyle] = useState(modifyBoardStyle(selectedSize)); return (
diff --git a/React/src/app/utils/check-board.ts b/React/src/app/utils/check-board.ts index 46c6a70..da675d8 100644 --- a/React/src/app/utils/check-board.ts +++ b/React/src/app/utils/check-board.ts @@ -1,8 +1,5 @@ -import { createWinLines } from "./create-winlines"; -const boardSize = 3; -const winLines = createWinLines(boardSize); -export function checkBoard(board: string[][], currentPlayer: string): number[][] | void { +export function checkBoard(board: string[][], currentPlayer: string, winLines: number[][][]): number[][] | void { return winLines.find(line => line.every(cell => board[cell[0]][cell[1]] == currentPlayer)) diff --git a/React/src/app/utils/globals.ts b/React/src/app/utils/globals.ts index e9db389..d115317 100644 --- a/React/src/app/utils/globals.ts +++ b/React/src/app/utils/globals.ts @@ -1,9 +1,13 @@ interface GlobalTypes { boardSizes: number[]; - selectedSize: number; + padding: number; + boardWidth: number; + boardBorderWidth: number; } -export const globals:GlobalTypes = { - boardSizes : [3,6,9], - selectedSize : 3, +export const globals: GlobalTypes = { + boardSizes: [3, 6, 9], + padding: 12, + boardWidth: 312, + boardBorderWidth: 1 } \ No newline at end of file diff --git a/React/src/app/utils/winline-style-maker.ts b/React/src/app/utils/winline-style-maker.ts index 9bcca7c..b02b8f4 100644 --- a/React/src/app/utils/winline-style-maker.ts +++ b/React/src/app/utils/winline-style-maker.ts @@ -3,17 +3,14 @@ import { globals } from "./globals"; import { P1 } from "./players"; -const boardWidth = 312; -const mainBorderSize = 1; -const boardSize = globals.selectedSize; -const winLineSize = globals.selectedSize; -const padding = 12; -const cellWidth = (boardWidth - 2 * (padding + mainBorderSize)) / boardSize; -export function winLineStyleMaker(currentPlayer: string, result?: number[][]) { +export function winLineStyleMaker(currentPlayer: string, selectedSize: number, result?: number[][]) { if (!result) return; + const winLineSize = selectedSize; + const cellWidth = (globals.boardWidth - 2 * (globals.padding + globals.boardBorderWidth)) / selectedSize; + console.log(cellWidth); const winLineStyle = { visibility: "visible", top: "", @@ -37,7 +34,8 @@ export function winLineStyleMaker(currentPlayer: string, result?: number[][]) { winLineStyle.top = `${cellWidth * (lineStartY + 0.5)}px`; winLineStyle.transform = "rotate(-90deg)"; } else if (lineStartX == lineEndX) { - winLineStyle.left = `${cellWidth * (lineStartX + 0.5)}px`; + winLineStyle.left = `${cellWidth * (lineStartX + 0.5) - 2}px`; //minus 2 is half of windLine width + console.log(winLineStyle.left); winLineStyle.top = `0px`; winLineStyle.transform = "rotate(0deg)"; } From 87ecc24b34edf9d9ba51b811af86cb7fc757945a Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Tue, 3 Oct 2023 08:51:12 +0330 Subject: [PATCH 14/22] Done === all winline for 6x6 and 9x9 --- React/src/app/pages/game/PlayerVsBotPage.tsx | 7 ++----- React/src/app/pages/home/HomePage.module.scss | 17 ++++++++++----- React/src/app/pages/home/HomePage.tsx | 12 ++++++----- React/src/app/utils/check-board.ts | 2 +- React/src/app/utils/find-best-bot-move.ts | 21 ++++++++++++------- React/src/app/utils/winline-style-maker.ts | 4 +--- 6 files changed, 36 insertions(+), 27 deletions(-) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index ddce1b2..b535a5c 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -24,9 +24,6 @@ export function PlayerVsBotPage() { useEffect(() => { setWinlines(createWinLines(selectedSize)); - }, []) - - useEffect(() => { if (isFirstMove.current && currentPlayer === P2) { handleBot(); } @@ -49,11 +46,11 @@ export function PlayerVsBotPage() { }; const handleBot = () => { - - let movement = findBestBotMove(boardData) + let movement = findBestBotMove(boardData, winLines!) if (movement) { boardData[movement.i][movement.j] = P2; } + setBoardData([...boardData]); if (checkWinner(P2)) return; if (anyMovesLeft(boardData)) { diff --git a/React/src/app/pages/home/HomePage.module.scss b/React/src/app/pages/home/HomePage.module.scss index 596e76a..d018681 100644 --- a/React/src/app/pages/home/HomePage.module.scss +++ b/React/src/app/pages/home/HomePage.module.scss @@ -35,7 +35,7 @@ background-image: url("static/images/bg.png"); background-repeat: no-repeat; background-size: cover; - + } .palyNowButton, @@ -77,15 +77,22 @@ linear-gradient(to right, rgba(255, 255, 255, 0.5), #5570fd) border-box; } -.boardSizesContainer { +.boardSizesContainerBackDrop { position: absolute; top: 50%; - transform: translate3d(0%, -65%, 0); + display: flex; + align-items: center; + justify-content: center; width: 100%; + overflow: hidden; + transform: translateY(-65%); + height: 200px; +} + +.boardSizesContainer { gap: 85px; height: 200px; display: flex; - overflow: hidden; align-items: center; justify-content: center; } @@ -125,4 +132,4 @@ .rightVector { right: 0; -} +} \ No newline at end of file diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index 0d3a335..804998f 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -40,11 +40,13 @@ export function HomePage() { leftVector rightVector
-
- {globals.boardSizes.map((board, i) => ( - - // , scale: `${(i + 1) * 3 == selectedSize ? 1.3 : 1}` - ))} +
+
+ {globals.boardSizes.map((board, i) => ( + + // , scale: `${(i + 1) * 3 == selectedSize ? 1.3 : 1}` + ))} +
diff --git a/React/src/app/utils/check-board.ts b/React/src/app/utils/check-board.ts index da675d8..dad145b 100644 --- a/React/src/app/utils/check-board.ts +++ b/React/src/app/utils/check-board.ts @@ -1,6 +1,6 @@ export function checkBoard(board: string[][], currentPlayer: string, winLines: number[][][]): number[][] | void { - return winLines.find(line => line.every(cell => board[cell[0]][cell[1]] == currentPlayer)) + if (winLines) return winLines.find(line => line.every(cell => board[cell[0]][cell[1]] == currentPlayer)) } \ No newline at end of file diff --git a/React/src/app/utils/find-best-bot-move.ts b/React/src/app/utils/find-best-bot-move.ts index 7ba9eb9..e16b592 100644 --- a/React/src/app/utils/find-best-bot-move.ts +++ b/React/src/app/utils/find-best-bot-move.ts @@ -2,11 +2,14 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; import { anyMovesLeft } from "./any-moves-left"; -export function findBestBotMove(board: any[][]) { +let winLinesArray: number[][][]; + +export function findBestBotMove(board: any[][], winLines: number[][][]) { + winLinesArray = winLines; let bestScore = -Infinity; let movement; - for (let i = 0; i < 3; i++) { - for (let j = 0; j < 3; j++) { + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board.length; j++) { if (board[i][j] == null) { board[i][j] = P2; let score = minimax(board, 0, false); @@ -24,7 +27,7 @@ export function findBestBotMove(board: any[][]) { function minimax(board: any[][], depth: number, isMaximizing: boolean) { let current = isMaximizing ? P2 : P1; - let winResult = checkBoard(board, current); + let winResult = winLinesArray && checkBoard(board, current, winLinesArray); if (winResult) return isMaximizing ? 1 : -1; if (anyMovesLeft(board)) return 0; @@ -33,10 +36,12 @@ function minimax(board: any[][], depth: number, isMaximizing: boolean) { return findMinMove(board, depth) } + function findMaxMove(board: any[][], depth: number) { + let bestScore = -Infinity; - for (let i = 0; i < 3; i++) { - for (let j = 0; j < 3; j++) { + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board.length; j++) { if (board[i][j] == null) { board[i][j] = P2; let score = minimax(board, depth + 1, false); @@ -50,8 +55,8 @@ function findMaxMove(board: any[][], depth: number) { function findMinMove(board: any[][], depth: number) { let bestScore = Infinity; - for (let i = 0; i < 3; i++) { - for (let j = 0; j < 3; j++) { + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board.length; j++) { if (board[i][j] == null) { board[i][j] = P1; let score = minimax(board, depth + 1, true); diff --git a/React/src/app/utils/winline-style-maker.ts b/React/src/app/utils/winline-style-maker.ts index b02b8f4..4517ebf 100644 --- a/React/src/app/utils/winline-style-maker.ts +++ b/React/src/app/utils/winline-style-maker.ts @@ -10,7 +10,6 @@ export function winLineStyleMaker(currentPlayer: string, selectedSize: number, r const winLineSize = selectedSize; const cellWidth = (globals.boardWidth - 2 * (globals.padding + globals.boardBorderWidth)) / selectedSize; - console.log(cellWidth); const winLineStyle = { visibility: "visible", top: "", @@ -34,8 +33,7 @@ export function winLineStyleMaker(currentPlayer: string, selectedSize: number, r winLineStyle.top = `${cellWidth * (lineStartY + 0.5)}px`; winLineStyle.transform = "rotate(-90deg)"; } else if (lineStartX == lineEndX) { - winLineStyle.left = `${cellWidth * (lineStartX + 0.5) - 2}px`; //minus 2 is half of windLine width - console.log(winLineStyle.left); + winLineStyle.left = `${cellWidth * (lineStartX + 0.5) - 2}px`; //minus 2 is half of winLine width winLineStyle.top = `0px`; winLineStyle.transform = "rotate(0deg)"; } From 90aba3675e402b5612978d7fb2ee762819a359fc Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Tue, 3 Oct 2023 09:10:53 +0330 Subject: [PATCH 15/22] fix some type issues --- React/src/app/App.tsx | 1 - React/src/app/pages/game/PlayerVsBotPage.tsx | 4 ++-- React/src/app/pages/game/PlayerVsPlayerPage.tsx | 4 ++-- React/src/app/pages/game/components/Board/Board.module.scss | 4 +--- React/src/app/pages/home/HomePage.tsx | 2 -- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/React/src/app/App.tsx b/React/src/app/App.tsx index ea53c2a..e4946e2 100644 --- a/React/src/app/App.tsx +++ b/React/src/app/App.tsx @@ -9,7 +9,6 @@ interface IContextValue { export const boardSizeContext = createContext({ selectedSize: 3, setSelectedSize: () => { } }); - function App() { const [selectedSize, setSelectedSize] = useState(3); const contextValue = { diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index b535a5c..ae0a34f 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -20,7 +20,7 @@ export function PlayerVsBotPage() { const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); - const [winLines, setWinlines] = useState() + const [winLines, setWinlines] = useState(); useEffect(() => { setWinlines(createWinLines(selectedSize)); @@ -28,7 +28,7 @@ export function PlayerVsBotPage() { handleBot(); } isFirstMove.current = false; - }, [isFirstMove.current]) + }, [isFirstMove.current]); const handleClick = (i: number, j: number) => { if (boardData[i][j] || winResult) return; diff --git a/React/src/app/pages/game/PlayerVsPlayerPage.tsx b/React/src/app/pages/game/PlayerVsPlayerPage.tsx index 6e44015..14976be 100644 --- a/React/src/app/pages/game/PlayerVsPlayerPage.tsx +++ b/React/src/app/pages/game/PlayerVsPlayerPage.tsx @@ -18,11 +18,11 @@ export function PlayerVsPlayerPage() { const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); - const [winLines, setWinlines] = useState() + const [winLines, setWinlines] = useState(); useEffect(() => { setWinlines(createWinLines(selectedSize)); - }, []) + }, []); const handleClick = (i: number, j: number) => { if (boardData[i][j] || winResult) return; diff --git a/React/src/app/pages/game/components/Board/Board.module.scss b/React/src/app/pages/game/components/Board/Board.module.scss index 3d87afd..b84bce9 100644 --- a/React/src/app/pages/game/components/Board/Board.module.scss +++ b/React/src/app/pages/game/components/Board/Board.module.scss @@ -14,7 +14,6 @@ height: 100%; overflow: hidden; position: relative; - } .container { @@ -61,5 +60,4 @@ transform-origin: center top; transition: height 0.4s ease-in-out; visibility: hidden; -} - +} \ No newline at end of file diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index 804998f..ec2aaed 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -16,7 +16,6 @@ export function HomePage() { selectedSize != 9 && setSelectedSize(selectedSize + 3); } - return ( <>
@@ -44,7 +43,6 @@ export function HomePage() {
{globals.boardSizes.map((board, i) => ( - // , scale: `${(i + 1) * 3 == selectedSize ? 1.3 : 1}` ))}
From d37681dce43774cd0de49c8f12dd45f68e9358f6 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Thu, 12 Oct 2023 09:27:17 +0330 Subject: [PATCH 16/22] change var name --- .../src/app/pages/game/components/Header/Header.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/React/src/app/pages/game/components/Header/Header.tsx b/React/src/app/pages/game/components/Header/Header.tsx index 8d9f7f9..34152ef 100644 --- a/React/src/app/pages/game/components/Header/Header.tsx +++ b/React/src/app/pages/game/components/Header/Header.tsx @@ -12,14 +12,14 @@ interface Props { export function Header({ currentPlayer, gameMode, refreshBoard }: Props) { const { selectedSize, setSelectedSize } = useContext(boardSizeContext); - const [showSelectBox, setShowSelectBox] = useState(false); + const [isSelectBoxOpen, setIsSelectBoxOpen] = useState(false); function changeBoardSize(size: number) { if (selectedSize === size) return; setSelectedSize(size); - setShowSelectBox(false); + setIsSelectBoxOpen(false); refreshBoard(); - } + } return (
@@ -32,10 +32,10 @@ export function Header({ currentPlayer, gameMode, refreshBoard }: Props) {
-
-
setShowSelectBox(!showSelectBox)}> +
+
setIsSelectBoxOpen(!isSelectBoxOpen)}> {selectedSize} x {selectedSize} - arrow-down + arrow-down
changeBoardSize(3)}>3 x 3
changeBoardSize(6)}>6 x 6
From 4d9a4d5e1e23650182825590ac46bbebb7e8abeb Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Fri, 13 Oct 2023 17:39:42 +0330 Subject: [PATCH 17/22] winLine style for 3 modes --- React/src/app/utils/create-winlines.ts | 64 +++++++++++++++------- React/src/app/utils/winline-style-maker.ts | 9 ++- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/React/src/app/utils/create-winlines.ts b/React/src/app/utils/create-winlines.ts index ef780d3..3027a2e 100644 --- a/React/src/app/utils/create-winlines.ts +++ b/React/src/app/utils/create-winlines.ts @@ -1,28 +1,54 @@ export function createWinLines(boardSize: number) { + + let winLineSize = 3; + + switch (boardSize) { + case 3: + winLineSize = 3 + break; + case 6: + winLineSize = 4 + break; + case 9: + winLineSize = 5 + break; + } + let winLines = []; - let diagonalOne = []; - let diagonalTwo = []; - for (let row = 0; row < boardSize; row++) { - let horizontal = []; - for (let col = 0; col < boardSize; col++) { - horizontal.push([row, col]); + + for (let i = 0; i < boardSize; i++) { + for (let j = 0; j <= boardSize - winLineSize; j++) { + let horizontal = []; + for (let k = j; k < j + winLineSize; k++) { + horizontal.push([i, k]); + } + winLines.push(horizontal); } - winLines.push(horizontal) } - for (let col = 0; col < boardSize; col++) { - let vertical = []; - for (let row = 0; row < boardSize; row++) { - vertical.push([row, col]); + + for (let j = 0; j < boardSize; j++) { + for (let i = 0; i <= boardSize - winLineSize; i++) { + let vertical = []; + for (let k = i; k < i + winLineSize; k++) { + vertical.push([k, j]); + } + winLines.push(vertical); } - winLines.push(vertical) } - for (let i = 0; i < boardSize; i++) { - diagonalOne.push([i, i]); - diagonalTwo.push([i, boardSize - i - 1]); + for (let i = 0; i <= boardSize - winLineSize; i++) { + for (let j = 0; j <= boardSize - winLineSize; j++) { + let diagonalOne = []; + let diagonalTwo = []; + for (let k = 0; k < winLineSize; k++) { + diagonalOne.push([i + k, j + k]); + diagonalTwo.push([j + k, boardSize - k - i]); + } + winLines.push(diagonalOne); + winLines.push(diagonalTwo); + + } } - winLines.push(diagonalOne); - winLines.push(diagonalTwo); + return winLines; +} - return winLines -} \ No newline at end of file diff --git a/React/src/app/utils/winline-style-maker.ts b/React/src/app/utils/winline-style-maker.ts index 4517ebf..23af052 100644 --- a/React/src/app/utils/winline-style-maker.ts +++ b/React/src/app/utils/winline-style-maker.ts @@ -23,22 +23,21 @@ export function winLineStyleMaker(currentPlayer: string, selectedSize: number, r let lineStartY = result[0][0]; let lineEndX = result[result.length - 1][1]; let lineEndY = result[result.length - 1][0]; - let angelIndicater = (lineEndY - lineStartY) / (lineEndX - lineStartX); - let lineLength = winLineSize * cellWidth; + let lineLength = result.length * cellWidth; winLineStyle.height = `${lineLength}px`; if (lineStartY == lineEndY) { - winLineStyle.left = `0px`; + winLineStyle.left = `${cellWidth * (lineStartX) - 2}px`; //minus 2 is half of winLine width winLineStyle.top = `${cellWidth * (lineStartY + 0.5)}px`; winLineStyle.transform = "rotate(-90deg)"; } else if (lineStartX == lineEndX) { winLineStyle.left = `${cellWidth * (lineStartX + 0.5) - 2}px`; //minus 2 is half of winLine width - winLineStyle.top = `0px`; + winLineStyle.top = `${cellWidth * (lineStartY)}px`; winLineStyle.transform = "rotate(0deg)"; } else { - lineLength = Math.sqrt(2) * cellWidth * winLineSize; + lineLength = Math.sqrt(2) * cellWidth * result.length; winLineStyle.height = `${lineLength}px` winLineStyle.transform = `rotate(${angelIndicater > 0 ? -45 : 45}deg)`; winLineStyle.left = `${(lineStartX + (angelIndicater > 0 ? 0 : 1)) * cellWidth}px`; From 7d20604d9b74dd226daeb30c70bd75b5971949be Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 15 Oct 2023 19:29:15 +0330 Subject: [PATCH 18/22] Done === fix issues --- React/src/app/pages/game/PlayerVsBotPage.tsx | 21 ++++---- .../src/app/pages/game/PlayerVsPlayerPage.tsx | 18 +++---- .../app/pages/game/components/Board/Board.tsx | 11 ++-- ...module.scss => GamePageHeader.module.scss} | 0 .../Header/{Header.tsx => GamePageHeader.tsx} | 4 +- .../app/pages/game/components/Header/index.ts | 2 +- React/src/app/pages/home/HomePage.module.scss | 12 ++--- React/src/app/pages/home/HomePage.tsx | 6 +-- .../utils/{reset-board.ts => create-board.ts} | 2 +- React/src/app/utils/create-winlines.ts | 50 +++++++++---------- ...{modifyBoardStyle.ts => getBoardRadius.ts} | 2 +- React/src/app/utils/globals.ts | 8 +-- 12 files changed, 67 insertions(+), 69 deletions(-) rename React/src/app/pages/game/components/Header/{Header.module.scss => GamePageHeader.module.scss} (100%) rename React/src/app/pages/game/components/Header/{Header.tsx => GamePageHeader.tsx} (94%) rename React/src/app/utils/{reset-board.ts => create-board.ts} (67%) rename React/src/app/utils/{modifyBoardStyle.ts => getBoardRadius.ts} (89%) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index dc8705b..5f50488 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -2,7 +2,7 @@ import { useState, useRef, useEffect, useContext } from "react"; import { checkBoard } from "~/utils/check-board"; import { P1, P2, generateRandomTurn } from "~/utils/players"; import { Footer } from "./components/Footer"; -import { Header } from "./components/Header"; +import { GamePageHeader } from "./components/Header"; import { ResultModal } from "./components/Modal/ResultModal"; import { GameMode } from "~/utils/game-mode"; import classes from "./PlayerVsBotPage.module.scss"; @@ -10,21 +10,22 @@ import { anyMovesLeft } from "~/utils/any-moves-left"; import { findBestBotMove } from "~/utils/find-best-bot-move"; import { Board } from "./components/Board"; import { boardSizeContext } from "~/App"; -import { resetBoard } from "~/utils/reset-board"; +import { createBoard } from "~/utils/create-board"; import { createWinLines } from "~/utils/create-winlines"; +import { winLines } from "~/utils/create-winlines"; export function PlayerVsBotPage() { const { selectedSize } = useContext(boardSizeContext); - const [boardData, setBoardData] = useState(structuredClone(resetBoard(selectedSize))); + const [boardData, setBoardData] = useState(createBoard(selectedSize)); const [currentPlayer, setCurrentPlayer] = useState(generateRandomTurn()); const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); - const [winLines, setWinlines] = useState(); + useEffect(() => { - setWinlines(createWinLines(selectedSize)); - setBoardData(structuredClone(resetBoard(selectedSize))); + createWinLines(selectedSize); + setBoardData(createBoard(selectedSize)); if (isFirstMove.current && currentPlayer === P2) { handleBot(); } @@ -47,7 +48,7 @@ export function PlayerVsBotPage() { }; const handleBot = () => { - let movement = findBestBotMove(boardData, winLines!) + let movement = findBestBotMove(boardData, winLines[selectedSize]) if (movement) { boardData[movement.i][movement.j] = P2; } @@ -61,7 +62,7 @@ export function PlayerVsBotPage() { }; const checkWinner = (currentPlayer: string) => { - const result = checkBoard(boardData, currentPlayer, winLines!); + const result = checkBoard(boardData, currentPlayer, winLines[selectedSize]); if (!result) return false; setWinResult(result); setShowModal(true); @@ -70,7 +71,7 @@ export function PlayerVsBotPage() { const refreshBoard = () => { let newRandomTurnGenerator = generateRandomTurn(); - setBoardData(structuredClone(resetBoard(selectedSize))); + setBoardData(createBoard(selectedSize)); setCurrentPlayer(newRandomTurnGenerator); if (newRandomTurnGenerator === P2) { isFirstMove.current = true; @@ -81,7 +82,7 @@ export function PlayerVsBotPage() { return (
-
(); const [showModal, setShowModal] = useState(false); - const [winLines, setWinlines] = useState(); useEffect(() => { - setWinlines(createWinLines(selectedSize)); - setBoardData(structuredClone(resetBoard(selectedSize))); + createWinLines(selectedSize); + setBoardData(createBoard(selectedSize)); }, [selectedSize]); const handleClick = (i: number, j: number) => { @@ -40,7 +40,7 @@ export function PlayerVsPlayerPage() { }; const checkWinner = () => { - const result = checkBoard(boardData, currentPlayer, winLines!); + const result = checkBoard(boardData, currentPlayer, winLines[selectedSize]); if (!result) return false; setWinResult(result); setShowModal(true); @@ -48,7 +48,7 @@ export function PlayerVsPlayerPage() { }; const refreshBoard = () => { - setBoardData(structuredClone(resetBoard(selectedSize))); + setBoardData(createBoard(selectedSize)); setCurrentPlayer(generateRandomTurn()); setWinResult(undefined); setShowModal(false); @@ -56,7 +56,7 @@ export function PlayerVsPlayerPage() { return (
-
{ + setBoardStyle(getBoardRadius(selectedSize)); + }, [selectedSize]); + return (
diff --git a/React/src/app/pages/game/components/Header/Header.module.scss b/React/src/app/pages/game/components/Header/GamePageHeader.module.scss similarity index 100% rename from React/src/app/pages/game/components/Header/Header.module.scss rename to React/src/app/pages/game/components/Header/GamePageHeader.module.scss diff --git a/React/src/app/pages/game/components/Header/Header.tsx b/React/src/app/pages/game/components/Header/GamePageHeader.tsx similarity index 94% rename from React/src/app/pages/game/components/Header/Header.tsx rename to React/src/app/pages/game/components/Header/GamePageHeader.tsx index 34152ef..30d6cac 100644 --- a/React/src/app/pages/game/components/Header/Header.tsx +++ b/React/src/app/pages/game/components/Header/GamePageHeader.tsx @@ -1,5 +1,5 @@ import { P1, P2 } from "~/utils/players"; -import classes from "./Header.module.scss"; +import classes from "./GamePageHeader.module.scss"; import { GameMode } from "~/utils/game-mode"; import { boardSizeContext } from "~/App"; import { useContext, useState } from "react"; @@ -10,7 +10,7 @@ interface Props { refreshBoard: () => void; } -export function Header({ currentPlayer, gameMode, refreshBoard }: Props) { +export function GamePageHeader({ currentPlayer, gameMode, refreshBoard }: Props) { const { selectedSize, setSelectedSize } = useContext(boardSizeContext); const [isSelectBoxOpen, setIsSelectBoxOpen] = useState(false); diff --git a/React/src/app/pages/game/components/Header/index.ts b/React/src/app/pages/game/components/Header/index.ts index 2180af6..36a3d4a 100644 --- a/React/src/app/pages/game/components/Header/index.ts +++ b/React/src/app/pages/game/components/Header/index.ts @@ -1 +1 @@ -export * from "./Header" \ No newline at end of file +export * from "./GamePageHeader" \ No newline at end of file diff --git a/React/src/app/pages/home/HomePage.module.scss b/React/src/app/pages/home/HomePage.module.scss index d018681..f3ae4b4 100644 --- a/React/src/app/pages/home/HomePage.module.scss +++ b/React/src/app/pages/home/HomePage.module.scss @@ -38,9 +38,9 @@ } -.palyNowButton, -.palyBotButton, -.palyFriendsButton { +.playNowButton, +.playBotButton, +.playFriendsButton { width: 265px; height: 56px; border-radius: 24px; @@ -54,7 +54,7 @@ user-select: none; } -.palyNowButton { +.playNowButton { display: flex; justify-content: center; align-items: center; @@ -65,8 +65,8 @@ linear-gradient(to right, rgba(255, 255, 255, 0.33), #191685) border-box; } -.palyBotButton, -.palyFriendsButton { +.playBotButton, +.playFriendsButton { display: flex; align-items: center; justify-content: center; diff --git a/React/src/app/pages/home/HomePage.tsx b/React/src/app/pages/home/HomePage.tsx index ec2aaed..b866a90 100644 --- a/React/src/app/pages/home/HomePage.tsx +++ b/React/src/app/pages/home/HomePage.tsx @@ -47,14 +47,14 @@ export function HomePage() {
- + Play Now! - + Play with bot - diff --git a/React/src/app/utils/reset-board.ts b/React/src/app/utils/create-board.ts similarity index 67% rename from React/src/app/utils/reset-board.ts rename to React/src/app/utils/create-board.ts index 0eeff7d..3daa3a7 100644 --- a/React/src/app/utils/reset-board.ts +++ b/React/src/app/utils/create-board.ts @@ -1,4 +1,4 @@ -export function resetBoard(selectedSize: number) { +export function createBoard(selectedSize: number) { return (Array(selectedSize) .fill(null) .map(() => Array(selectedSize).fill(null)) diff --git a/React/src/app/utils/create-winlines.ts b/React/src/app/utils/create-winlines.ts index 3027a2e..ac027e2 100644 --- a/React/src/app/utils/create-winlines.ts +++ b/React/src/app/utils/create-winlines.ts @@ -1,54 +1,52 @@ +export const winLines: { [key: number]: number[][][] } = { + 3: [], + 6: [], + 9: [] +} + export function createWinLines(boardSize: number) { - let winLineSize = 3; - - switch (boardSize) { - case 3: - winLineSize = 3 - break; - case 6: - winLineSize = 4 - break; - case 9: - winLineSize = 5 - break; + const winLineSize: { [key: number]: number } = { + 3: 3, + 6: 4, + 9: 5 } - let winLines = []; + + if (winLines[boardSize].length != 0) return; for (let i = 0; i < boardSize; i++) { - for (let j = 0; j <= boardSize - winLineSize; j++) { + for (let j = 0; j <= boardSize - winLineSize[boardSize]; j++) { let horizontal = []; - for (let k = j; k < j + winLineSize; k++) { + for (let k = j; k < j + winLineSize[boardSize]; k++) { horizontal.push([i, k]); } - winLines.push(horizontal); + winLines[boardSize].push(horizontal); } } for (let j = 0; j < boardSize; j++) { - for (let i = 0; i <= boardSize - winLineSize; i++) { + for (let i = 0; i <= boardSize - winLineSize[boardSize]; i++) { let vertical = []; - for (let k = i; k < i + winLineSize; k++) { + for (let k = i; k < i + winLineSize[boardSize]; k++) { vertical.push([k, j]); } - winLines.push(vertical); + winLines[boardSize].push(vertical); } } - for (let i = 0; i <= boardSize - winLineSize; i++) { - for (let j = 0; j <= boardSize - winLineSize; j++) { + for (let i = 0; i <= boardSize - winLineSize[boardSize]; i++) { + for (let j = 0; j <= boardSize - winLineSize[boardSize]; j++) { let diagonalOne = []; let diagonalTwo = []; - for (let k = 0; k < winLineSize; k++) { + for (let k = 0; k < winLineSize[boardSize]; k++) { diagonalOne.push([i + k, j + k]); - diagonalTwo.push([j + k, boardSize - k - i]); + diagonalTwo.push([j + k, boardSize - k - i - 1]); } - winLines.push(diagonalOne); - winLines.push(diagonalTwo); + winLines[boardSize].push(diagonalOne); + winLines[boardSize].push(diagonalTwo); } } - return winLines; } diff --git a/React/src/app/utils/modifyBoardStyle.ts b/React/src/app/utils/getBoardRadius.ts similarity index 89% rename from React/src/app/utils/modifyBoardStyle.ts rename to React/src/app/utils/getBoardRadius.ts index 89f5fab..4dd65a0 100644 --- a/React/src/app/utils/modifyBoardStyle.ts +++ b/React/src/app/utils/getBoardRadius.ts @@ -3,7 +3,7 @@ interface BoardStyles { templateRadius: string; } -export function modifyBoardStyle(selectedSize: number) { +export function getBoardRadius(selectedSize: number) { const boardStyles: BoardStyles = { mainRadius: "64px", templateRadius: "56px" }; switch (selectedSize) { case 6: diff --git a/React/src/app/utils/globals.ts b/React/src/app/utils/globals.ts index d115317..0dc692a 100644 --- a/React/src/app/utils/globals.ts +++ b/React/src/app/utils/globals.ts @@ -1,11 +1,5 @@ -interface GlobalTypes { - boardSizes: number[]; - padding: number; - boardWidth: number; - boardBorderWidth: number; -} -export const globals: GlobalTypes = { +export const globals = { boardSizes: [3, 6, 9], padding: 12, boardWidth: 312, From 20c8213e2d8e81aa531ef24ce679153f91f2f23e Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 15 Oct 2023 20:38:24 +0330 Subject: [PATCH 19/22] Done === add font and optimize some code --- React/index.html | 5 +++++ .../components/Header/GamePageHeader.module.scss | 2 +- React/src/app/utils/winline-style-maker.ts | 13 ++++++++++--- React/src/main.scss | 3 ++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/React/index.html b/React/index.html index cae99fe..75551e4 100644 --- a/React/index.html +++ b/React/index.html @@ -4,6 +4,11 @@ + + + dooz (Tic Tac Toe) React diff --git a/React/src/app/pages/game/components/Header/GamePageHeader.module.scss b/React/src/app/pages/game/components/Header/GamePageHeader.module.scss index 3461a02..25bae94 100644 --- a/React/src/app/pages/game/components/Header/GamePageHeader.module.scss +++ b/React/src/app/pages/game/components/Header/GamePageHeader.module.scss @@ -16,7 +16,7 @@ .selectBox { font-weight: 400; - font-size: 18px; + font-size: 16px; border-radius: 16px; background-color: rgba(85, 112, 253, 0.2); height: 40px; diff --git a/React/src/app/utils/winline-style-maker.ts b/React/src/app/utils/winline-style-maker.ts index 23af052..75bf894 100644 --- a/React/src/app/utils/winline-style-maker.ts +++ b/React/src/app/utils/winline-style-maker.ts @@ -1,15 +1,22 @@ -import React, { CSSProperties } from "react"; +import React from "react"; import { globals } from "./globals"; import { P1 } from "./players"; +const allSizeCellWidth: { [key: number]: number } = { + 3: 0, + 6: 0, + 9: 0 +} +globals.boardSizes.map(size => { + allSizeCellWidth[size] = (globals.boardWidth - 2 * (globals.padding + globals.boardBorderWidth)) / size; +}) export function winLineStyleMaker(currentPlayer: string, selectedSize: number, result?: number[][]) { if (!result) return; - const winLineSize = selectedSize; - const cellWidth = (globals.boardWidth - 2 * (globals.padding + globals.boardBorderWidth)) / selectedSize; + const cellWidth = allSizeCellWidth[selectedSize]; const winLineStyle = { visibility: "visible", top: "", diff --git a/React/src/main.scss b/React/src/main.scss index 3b4b600..c157bdb 100644 --- a/React/src/main.scss +++ b/React/src/main.scss @@ -9,6 +9,7 @@ body, padding: 0; width: 100%; height: 100%; + font-family: 'Joti One', serif; } input, @@ -17,4 +18,4 @@ button, select, a { -webkit-tap-highlight-color: transparent; -} +} \ No newline at end of file From a33d3934e9cbfb1090dc2696d78f7fe21ee84984 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 15 Oct 2023 22:12:58 +0330 Subject: [PATCH 20/22] Done === fix issues --- React/src/app/pages/game/PlayerVsBotPage.tsx | 25 ++++++++++--------- .../src/app/pages/game/PlayerVsPlayerPage.tsx | 8 ++---- .../app/pages/game/components/Board/Board.tsx | 17 ++++++------- .../game/components/Header/GamePageHeader.tsx | 4 +-- React/src/app/utils/check-board.ts | 5 ++-- React/src/app/utils/find-best-bot-move.ts | 13 +++++----- .../{create-winlines.ts => get-winLines.ts} | 7 +++--- 7 files changed, 38 insertions(+), 41 deletions(-) rename React/src/app/utils/{create-winlines.ts => get-winLines.ts} (86%) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index 5f50488..2601647 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -11,8 +11,6 @@ import { findBestBotMove } from "~/utils/find-best-bot-move"; import { Board } from "./components/Board"; import { boardSizeContext } from "~/App"; import { createBoard } from "~/utils/create-board"; -import { createWinLines } from "~/utils/create-winlines"; -import { winLines } from "~/utils/create-winlines"; export function PlayerVsBotPage() { const { selectedSize } = useContext(boardSizeContext); @@ -23,14 +21,19 @@ export function PlayerVsBotPage() { const isFirstMove = useRef(true); + + + useEffect(() => { - createWinLines(selectedSize); - setBoardData(createBoard(selectedSize)); if (isFirstMove.current && currentPlayer === P2) { handleBot(); } isFirstMove.current = false; - }, [isFirstMove.current, selectedSize]); + }, [isFirstMove.current,selectedSize]); + + // useEffect(() => { + // refreshBoard(); + // }, [selectedSize]); const handleClick = (i: number, j: number) => { if (boardData[i][j] || winResult) return; @@ -48,11 +51,10 @@ export function PlayerVsBotPage() { }; const handleBot = () => { - let movement = findBestBotMove(boardData, winLines[selectedSize]) - if (movement) { - boardData[movement.i][movement.j] = P2; + let bestBotMove = findBestBotMove(boardData); + if (bestBotMove) { + boardData[bestBotMove.i][bestBotMove.j] = P2; } - setBoardData([...boardData]); if (checkWinner(P2)) return; if (anyMovesLeft(boardData)) { @@ -62,7 +64,7 @@ export function PlayerVsBotPage() { }; const checkWinner = (currentPlayer: string) => { - const result = checkBoard(boardData, currentPlayer, winLines[selectedSize]); + const result = checkBoard(boardData, currentPlayer); if (!result) return false; setWinResult(result); setShowModal(true); @@ -70,8 +72,8 @@ export function PlayerVsBotPage() { }; const refreshBoard = () => { - let newRandomTurnGenerator = generateRandomTurn(); setBoardData(createBoard(selectedSize)); + let newRandomTurnGenerator = generateRandomTurn(); setCurrentPlayer(newRandomTurnGenerator); if (newRandomTurnGenerator === P2) { isFirstMove.current = true; @@ -85,7 +87,6 @@ export function PlayerVsBotPage() {
{ - createWinLines(selectedSize); - setBoardData(createBoard(selectedSize)); + refreshBoard(); }, [selectedSize]); const handleClick = (i: number, j: number) => { @@ -40,7 +37,7 @@ export function PlayerVsPlayerPage() { }; const checkWinner = () => { - const result = checkBoard(boardData, currentPlayer, winLines[selectedSize]); + const result = checkBoard(boardData, currentPlayer); if (!result) return false; setWinResult(result); setShowModal(true); @@ -59,7 +56,6 @@ export function PlayerVsPlayerPage() {
{ - setBoardStyle(getBoardRadius(selectedSize)); - }, [selectedSize]); + setBoardRadius(getBoardRadius(boardData.length)); + }, [boardData.length]); return ( -
-
+
+
{boardData.map((row, i) => (
diff --git a/React/src/app/pages/game/components/Header/GamePageHeader.tsx b/React/src/app/pages/game/components/Header/GamePageHeader.tsx index 30d6cac..fcc1581 100644 --- a/React/src/app/pages/game/components/Header/GamePageHeader.tsx +++ b/React/src/app/pages/game/components/Header/GamePageHeader.tsx @@ -7,10 +7,9 @@ import { useContext, useState } from "react"; interface Props { currentPlayer: string; gameMode: GameMode; - refreshBoard: () => void; } -export function GamePageHeader({ currentPlayer, gameMode, refreshBoard }: Props) { +export function GamePageHeader({ currentPlayer, gameMode }: Props) { const { selectedSize, setSelectedSize } = useContext(boardSizeContext); const [isSelectBoxOpen, setIsSelectBoxOpen] = useState(false); @@ -18,7 +17,6 @@ export function GamePageHeader({ currentPlayer, gameMode, refreshBoard }: Props) if (selectedSize === size) return; setSelectedSize(size); setIsSelectBoxOpen(false); - refreshBoard(); } return ( diff --git a/React/src/app/utils/check-board.ts b/React/src/app/utils/check-board.ts index dad145b..6d2b4d9 100644 --- a/React/src/app/utils/check-board.ts +++ b/React/src/app/utils/check-board.ts @@ -1,6 +1,7 @@ +import { getWinLines } from "./get-winLines" -export function checkBoard(board: string[][], currentPlayer: string, winLines: number[][][]): number[][] | void { - +export function checkBoard(board: string[][], currentPlayer: string): number[][] | void { + const winLines = getWinLines(board.length); if (winLines) return winLines.find(line => line.every(cell => board[cell[0]][cell[1]] == currentPlayer)) } \ No newline at end of file diff --git a/React/src/app/utils/find-best-bot-move.ts b/React/src/app/utils/find-best-bot-move.ts index e16b592..0048620 100644 --- a/React/src/app/utils/find-best-bot-move.ts +++ b/React/src/app/utils/find-best-bot-move.ts @@ -1,13 +1,14 @@ import { P1, P2 } from "./players"; import { checkBoard } from "./check-board"; import { anyMovesLeft } from "./any-moves-left"; +import { getWinLines } from "./get-winLines"; let winLinesArray: number[][][]; -export function findBestBotMove(board: any[][], winLines: number[][][]) { - winLinesArray = winLines; +export function findBestBotMove(board: any[][]) { + winLinesArray = getWinLines(board.length); let bestScore = -Infinity; - let movement; + let bestBotMove; for (let i = 0; i < board.length; i++) { for (let j = 0; j < board.length; j++) { if (board[i][j] == null) { @@ -16,18 +17,18 @@ export function findBestBotMove(board: any[][], winLines: number[][][]) { board[i][j] = null; if (score > bestScore) { bestScore = score; - movement = { i, j }; + bestBotMove = { i, j }; } } } } - return movement; + return bestBotMove; } function minimax(board: any[][], depth: number, isMaximizing: boolean) { let current = isMaximizing ? P2 : P1; - let winResult = winLinesArray && checkBoard(board, current, winLinesArray); + let winResult = winLinesArray && checkBoard(board, current); if (winResult) return isMaximizing ? 1 : -1; if (anyMovesLeft(board)) return 0; diff --git a/React/src/app/utils/create-winlines.ts b/React/src/app/utils/get-winLines.ts similarity index 86% rename from React/src/app/utils/create-winlines.ts rename to React/src/app/utils/get-winLines.ts index ac027e2..c223b1e 100644 --- a/React/src/app/utils/create-winlines.ts +++ b/React/src/app/utils/get-winLines.ts @@ -1,10 +1,10 @@ -export const winLines: { [key: number]: number[][][] } = { +const winLines: { [key: number]: number[][][] } = { 3: [], 6: [], 9: [] } -export function createWinLines(boardSize: number) { +export function getWinLines(boardSize: number) { const winLineSize: { [key: number]: number } = { 3: 3, @@ -13,7 +13,7 @@ export function createWinLines(boardSize: number) { } - if (winLines[boardSize].length != 0) return; + if (winLines[boardSize].length != 0) return winLines[boardSize]; for (let i = 0; i < boardSize; i++) { for (let j = 0; j <= boardSize - winLineSize[boardSize]; j++) { @@ -48,5 +48,6 @@ export function createWinLines(boardSize: number) { } } + return winLines[boardSize]; } From b6a13729932337dfbe322aec300a160f610e100c Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Sun, 15 Oct 2023 22:37:42 +0330 Subject: [PATCH 21/22] handle strick mode for refresh in useEffect --- React/src/app/pages/game/PlayerVsBotPage.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index 2601647..71ef6cb 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -19,6 +19,7 @@ export function PlayerVsBotPage() { const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); + const strickModeInitialRenderCounter = useRef(0); @@ -29,11 +30,14 @@ export function PlayerVsBotPage() { handleBot(); } isFirstMove.current = false; - }, [isFirstMove.current,selectedSize]); + }, [isFirstMove.current]); - // useEffect(() => { - // refreshBoard(); - // }, [selectedSize]); + useEffect(() => { + strickModeInitialRenderCounter.current <= 2 ? strickModeInitialRenderCounter.current++ : strickModeInitialRenderCounter.current = 3; + if (strickModeInitialRenderCounter.current == 3) { + refreshBoard(); + } + }, [selectedSize]) const handleClick = (i: number, j: number) => { if (boardData[i][j] || winResult) return; From 3937108ae46559d8a9ab18d9f4abebe9d83bf4e1 Mon Sep 17 00:00:00 2001 From: Amirmasud Date: Mon, 16 Oct 2023 22:27:39 +0330 Subject: [PATCH 22/22] remove strickMode , fix handlebot useEffect --- React/src/app/pages/game/PlayerVsBotPage.tsx | 53 +++++++++---------- .../Header/GamePageHeader.module.scss | 1 - React/src/main.tsx | 4 +- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/React/src/app/pages/game/PlayerVsBotPage.tsx b/React/src/app/pages/game/PlayerVsBotPage.tsx index 71ef6cb..d26bd90 100644 --- a/React/src/app/pages/game/PlayerVsBotPage.tsx +++ b/React/src/app/pages/game/PlayerVsBotPage.tsx @@ -19,25 +19,21 @@ export function PlayerVsBotPage() { const [winResult, setWinResult] = useState(); const [showModal, setShowModal] = useState(false); const isFirstMove = useRef(true); - const strickModeInitialRenderCounter = useRef(0); - - - + useEffect(() => { + if (!isFirstMove.current) { + refreshBoard(); + } + }, [selectedSize]) useEffect(() => { - if (isFirstMove.current && currentPlayer === P2) { + if (currentPlayer === P2 && !winResult) { handleBot(); } isFirstMove.current = false; - }, [isFirstMove.current]); + }, [currentPlayer]); + - useEffect(() => { - strickModeInitialRenderCounter.current <= 2 ? strickModeInitialRenderCounter.current++ : strickModeInitialRenderCounter.current = 3; - if (strickModeInitialRenderCounter.current == 3) { - refreshBoard(); - } - }, [selectedSize]) const handleClick = (i: number, j: number) => { if (boardData[i][j] || winResult) return; @@ -50,21 +46,22 @@ export function PlayerVsBotPage() { return; } setCurrentPlayer(P2); - handleBot(); } }; - const handleBot = () => { - let bestBotMove = findBestBotMove(boardData); - if (bestBotMove) { - boardData[bestBotMove.i][bestBotMove.j] = P2; - } - setBoardData([...boardData]); - if (checkWinner(P2)) return; - if (anyMovesLeft(boardData)) { - setShowModal(true); - } - setCurrentPlayer(P1); + const handleBot = async () => { + setTimeout(() => { + let bestBotMove = findBestBotMove(boardData); + if (bestBotMove) { + boardData[bestBotMove.i][bestBotMove.j] = P2; + } + setBoardData([...boardData]); + if (checkWinner(P2)) return; + if (anyMovesLeft(boardData)) { + setShowModal(true); + } + setCurrentPlayer(P1); + }, 500); }; const checkWinner = (currentPlayer: string) => { @@ -77,11 +74,9 @@ export function PlayerVsBotPage() { const refreshBoard = () => { setBoardData(createBoard(selectedSize)); - let newRandomTurnGenerator = generateRandomTurn(); - setCurrentPlayer(newRandomTurnGenerator); - if (newRandomTurnGenerator === P2) { - isFirstMove.current = true; - } + let cp = generateRandomTurn(); + setCurrentPlayer(cp); + isFirstMove.current = true; setWinResult(undefined); setShowModal(false); } diff --git a/React/src/app/pages/game/components/Header/GamePageHeader.module.scss b/React/src/app/pages/game/components/Header/GamePageHeader.module.scss index 25bae94..ceb9030 100644 --- a/React/src/app/pages/game/components/Header/GamePageHeader.module.scss +++ b/React/src/app/pages/game/components/Header/GamePageHeader.module.scss @@ -11,7 +11,6 @@ height: 80px; transform: translateY(20px); width: 70px; - z-index: 10; } .selectBox { diff --git a/React/src/main.tsx b/React/src/main.tsx index f90dad9..05b9ca0 100644 --- a/React/src/main.tsx +++ b/React/src/main.tsx @@ -4,7 +4,7 @@ import App from './app/App' import './main.scss' ReactDOM.createRoot(document.getElementById('root')!).render( - + // - + // )