From e586fd671d2cada1924aa7d8868542cdde80079c Mon Sep 17 00:00:00 2001 From: Mateush Date: Sun, 1 Sep 2024 10:00:35 +0400 Subject: [PATCH] feat: support game wins (#16) * feat: support game wins * chore: clean up --- components/board.tsx | 4 +++- components/splash.tsx | 18 ++++++++++++++++++ constants.ts | 5 +++++ context/game-context.tsx | 20 +++++++++++++++++++- reducers/game-reducer.ts | 15 ++++++++++++++- styles/globals.css | 1 + styles/splash.module.css | 38 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 components/splash.tsx create mode 100644 styles/splash.module.css diff --git a/components/board.tsx b/components/board.tsx index 6a6b851..8dff80f 100644 --- a/components/board.tsx +++ b/components/board.tsx @@ -4,9 +4,10 @@ import styles from "@/styles/board.module.css"; import Tile from "./tile"; import { GameContext } from "@/context/game-context"; import MobileSwiper, { SwipeInput } from "./mobile-swiper"; +import Splash from "./splash"; export default function Board() { - const { getTiles, moveTiles, startGame } = useContext(GameContext); + const { getTiles, moveTiles, startGame, status } = useContext(GameContext); const initialized = useRef(false); const handleKeyDown = useCallback( @@ -86,6 +87,7 @@ export default function Board() { return (
+ {status === "won" && }
{renderTiles()}
{renderGrid()}
diff --git a/components/splash.tsx b/components/splash.tsx new file mode 100644 index 0000000..227c0b0 --- /dev/null +++ b/components/splash.tsx @@ -0,0 +1,18 @@ +import { GameContext } from "@/context/game-context"; +import styles from "@/styles/splash.module.css"; +import { useContext } from "react"; + +export default function Splash({ heading = "You won!" }) { + const { startGame } = useContext(GameContext); + + return ( +
+
+

{heading}

+ +
+
+ ); +} diff --git a/constants.ts b/constants.ts index 34b0fe5..053a40f 100644 --- a/constants.ts +++ b/constants.ts @@ -13,3 +13,8 @@ export const tileCountPerDimension = 4; export const mergeAnimationDuration = 100; // ms export const moveAnimationDuration = 200; // ms + +/** + * Game setup + */ +export const gameWinTileValue = 2048; diff --git a/context/game-context.tsx b/context/game-context.tsx index 017453b..11cdbdc 100644 --- a/context/game-context.tsx +++ b/context/game-context.tsx @@ -6,7 +6,11 @@ import { useReducer, } from "react"; import { isNil, throttle } from "lodash"; -import { mergeAnimationDuration, tileCountPerDimension } from "@/constants"; +import { + gameWinTileValue, + mergeAnimationDuration, + tileCountPerDimension, +} from "@/constants"; import { Tile } from "@/models/tile"; import gameReducer, { initialState } from "@/reducers/game-reducer"; @@ -14,6 +18,7 @@ type MoveDirection = "move_up" | "move_down" | "move_left" | "move_right"; export const GameContext = createContext({ score: 0, + status: "ongoing", moveTiles: (_: MoveDirection) => {}, getTiles: () => [] as Tile[], startGame: () => {}, @@ -61,15 +66,27 @@ export default function GameProvider({ children }: PropsWithChildren) { ); const startGame = () => { + dispatch({ type: "reset_game" }); dispatch({ type: "create_tile", tile: { position: [0, 1], value: 2 } }); dispatch({ type: "create_tile", tile: { position: [0, 2], value: 2 } }); }; + const checkGameState = () => { + const isWon = + Object.values(gameState.tiles).filter((t) => t.value === gameWinTileValue) + .length > 0; + + if (isWon) { + dispatch({ type: "update_status", status: "won" }); + } + }; + useEffect(() => { if (gameState.hasChanged) { setTimeout(() => { dispatch({ type: "clean_up" }); appendRandomTile(); + checkGameState(); }, mergeAnimationDuration); } }, [gameState.hasChanged]); @@ -78,6 +95,7 @@ export default function GameProvider({ children }: PropsWithChildren) { div { + margin: 0 auto; +} + +.splash > div > button { + margin: calc(var(--pixel-size) * 3) auto; +} + +.button { + background: var(--button-background); + border: calc(var(--pixel-size) * 0.5) solid var(--button-background); + border-radius: calc(var(--pixel-size) * 0.5); + font-size: calc(var(--pixel-size) * 2); + line-height: calc(var(--pixel-size) * 4); + font-weight: bold; + color: var(--tile-text-color); + cursor: pointer; +}