From 917457080069742fa938e590274dc461b93c5ddd Mon Sep 17 00:00:00 2001 From: Ivan Quirino Date: Wed, 20 Sep 2023 18:46:09 -0300 Subject: [PATCH] score multiplier, level progression, speed progression --- src/blockpuzzle/components/TopUI.tsx | 6 +++-- src/blockpuzzle/constants.ts | 2 ++ src/blockpuzzle/game.ts | 32 ++++++++++++++++++++++++-- src/blockpuzzle/store.ts | 22 ++++++++++++++---- src/blockpuzzle/tests/getLevel.test.ts | 14 +++++++++++ 5 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 src/blockpuzzle/tests/getLevel.test.ts diff --git a/src/blockpuzzle/components/TopUI.tsx b/src/blockpuzzle/components/TopUI.tsx index 45d72bf..c95783a 100644 --- a/src/blockpuzzle/components/TopUI.tsx +++ b/src/blockpuzzle/components/TopUI.tsx @@ -43,14 +43,16 @@ export const PieceDisplay = ({ const TopUI = () => { const score = useGameStore((state) => state.score); + const level = useGameStore(state => state.level) const next = useGameStore((state) => state.spawnBag[0]); - const nextPiece = pieces[next] ?? []; const input = useGameStore((state) => state.input); + const nextPiece = pieces[next] ?? []; + return (
SCORE {score}
-
LV 1
+
LV {level}
{nextPiece.length > 0 && ( diff --git a/src/blockpuzzle/constants.ts b/src/blockpuzzle/constants.ts index bf0e037..ca4e167 100644 --- a/src/blockpuzzle/constants.ts +++ b/src/blockpuzzle/constants.ts @@ -18,3 +18,5 @@ export const idleInput: KeyboardInput = { export const acceptedKeys = ["ArrowDown", "ArrowLeft", "ArrowRight", "Enter", "ArrowUp"]; export const scorePerRow = 100; + +export const initialTimeStep = 1000; diff --git a/src/blockpuzzle/game.ts b/src/blockpuzzle/game.ts index 11ab608..7cdb990 100644 --- a/src/blockpuzzle/game.ts +++ b/src/blockpuzzle/game.ts @@ -1,5 +1,5 @@ import { State } from "./store"; -import { scorePerRow, ROWS, COLS } from "./constants"; +import { scorePerRow, ROWS, COLS, initialTimeStep } from "./constants"; import { KeyboardInput, CurrentPiece, Grid, PieceId } from "./types"; export const pieceO = [ @@ -369,7 +369,7 @@ export function clearCompleteRows(state: State) { return { grid: newGrid, - score: state.score + scorePerRow * fullRows.length, + score: state.score + scorePerRow * fullRows.length * fullRows. length, }; } @@ -458,3 +458,31 @@ export const isGameOver = (state: State) => { return false; }; + +export const getScoreForNextLevel = (level = 1) => { + let sum = 0; + + for (let i = 0; i <= level; i++) { + sum = i * 1000 + sum; + } + + return sum; +}; + +export const updateLevel = (state: State) => { + const { score, level } = state; + + if (score >= getScoreForNextLevel(level)) { + return { level: level + 1 }; + } + + return state; +}; + +export const getTimeStep = (score: number) => { + if (score > 1000) { + const lvl = score; + } + + return initialTimeStep; +}; diff --git a/src/blockpuzzle/store.ts b/src/blockpuzzle/store.ts index 101bddf..6a32bc4 100644 --- a/src/blockpuzzle/store.ts +++ b/src/blockpuzzle/store.ts @@ -12,11 +12,13 @@ import { rotateClockwise, generateRandomPieceSet, isGameOver, + updateLevel, } from "./game"; export interface State { status: "loading" | "idle" | "started" | "paused" | "gameover"; score: number; + level: number; grid: Grid; current: CurrentPiece | null; currentPieceId: PieceId | null; @@ -36,12 +38,15 @@ export interface Actions { const getInitialState = (): State => ({ status: "loading", score: 0, + level: 1, grid: createGrid(), current: null, currentPieceId: null, spawnBag: [], }); +const timeout = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms)); + const store: StateCreator = (set, get) => { let interval: any; @@ -89,17 +94,20 @@ const store: StateCreator = (set, get) => { get().move(input); }, - start: () => { + start: async () => { set({ status: "started" }); generatePieceSet(); set(spawn); // game loop - interval = setInterval(() => { + + while (get().status === "started") { set(placeCurrentBlock); set(clearCompleteRows); + set(updateLevel) + if (isGameOver(get())) { set({ status: "gameover" }); clearInterval(interval); @@ -111,7 +119,13 @@ const store: StateCreator = (set, get) => { set(spawn); generatePieceSet(); - }, 1000); + + const level = get().level; + let timeStep = 1000 - ((level -1) * 100); + if (timeStep < 100) timeStep = 100; + + await timeout(timeStep); + } }, move: (input) => { if (get().status !== "started") return; @@ -120,7 +134,7 @@ const store: StateCreator = (set, get) => { }, rotateClockwise: () => { if (get().status !== "started") return; - + set(rotateClockwise); }, pause: () => { diff --git a/src/blockpuzzle/tests/getLevel.test.ts b/src/blockpuzzle/tests/getLevel.test.ts new file mode 100644 index 0000000..8fb3939 --- /dev/null +++ b/src/blockpuzzle/tests/getLevel.test.ts @@ -0,0 +1,14 @@ +import { getScoreForNextLevel } from "../game"; + +describe("getLevel", () => { + test("getScoreForNextLevel", () => { + const levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const scores = [ + 1000, 3000, 6000, 10000, 15000, 21000, 28000, 36000, 45000, 55000, + ]; + + const expectedScores = levels.map(getScoreForNextLevel); + + expect(expectedScores).toEqual(scores); + }); +});