Skip to content

Commit

Permalink
Limit level generation
Browse files Browse the repository at this point in the history
  • Loading branch information
matthijsgroen committed Sep 12, 2024
1 parent 1135556 commit 363a791
Show file tree
Hide file tree
Showing 14 changed files with 323 additions and 252 deletions.
104 changes: 58 additions & 46 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified .yarn/install-state.gz
Binary file not shown.
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
"test": "vitest"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "19.0.0-rc-d6cb4e77-20240911",
"react-dom": "19.0.0-rc-d6cb4e77-20240911"
},
"devDependencies": {
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^7.8.0",
"@vite-pwa/assets-generator": "^0.2.4",
Expand All @@ -39,5 +39,9 @@
"sharp": "0.32.6",
"sharp-ico": "0.1.5"
},
"overrides": {
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc"
},
"packageManager": "[email protected]"
}
6 changes: 3 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { LevelTrack } from "./modules/LevelTrack/index.tsx";
import PWABadge from "./PWABadge.tsx";
import { Level } from "./modules/Level/index.tsx";
import { LevelLoader } from "./modules/Level/index.tsx";
import { generateNewSeed, mulberry32 } from "./support/random.ts";
import {
getHardSettings,
Expand All @@ -13,7 +13,7 @@ import { isHard, isSpecial } from "./modules/LevelTrack/levelType.ts";
const BASE_SEED = 12345678901234;

export const App: React.FC = () => {
const [levelNr, setLevelNr] = useState(0);
const [levelNr, setLevelNr] = useState(7);

const [levelSeed, setLevelSeed] = useState(() =>
generateNewSeed(BASE_SEED, levelNr)
Expand Down Expand Up @@ -46,7 +46,7 @@ export const App: React.FC = () => {
/>
)}
{inLevel && (
<Level
<LevelLoader
onComplete={(won) => {
setInLevel(false);
if (won) {
Expand Down
2 changes: 1 addition & 1 deletion src/game/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const shapeMapping: Record<BlockColor, string> = {
brown: "🍄",
darkgreen: "🟢",
yellow: "🟡",
aqua: "⚡️ ",
aqua: "⚡️",
pink: "🐾",
purple: "️⭐️",
blue: "🌙",
Expand Down
25 changes: 13 additions & 12 deletions src/game/generateLevel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ describe(generateLevel, () => {
});

describe(generatePlayableLevel, () => {
it("generates a simple level", () => {
it("generates a simple level", async () => {
const random = mulberry32(TEST_SEED);
const level = generatePlayableLevel(random, {
const level = await generatePlayableLevel(random, {
amountColors: 2,
stackSize: 4,
extraPlacementStacks: 2,
Expand All @@ -94,9 +94,9 @@ describe(generatePlayableLevel, () => {
});
});

it("generates a complex level", () => {
it("generates a complex level", async () => {
const random = mulberry32(TEST_SEED);
const level = generatePlayableLevel(random, {
const level = await generatePlayableLevel(random, {
amountColors: 7,
stackSize: 4,
extraPlacementStacks: 2,
Expand All @@ -105,9 +105,9 @@ describe(generatePlayableLevel, () => {
expect(level.movesNeeded).toEqual(39);
});

it("generates a complex level (buffers / force)", () => {
it("generates a complex level (buffers / force)", async () => {
const random = mulberry32(TEST_SEED);
const level = generatePlayableLevel(random, {
const level = await generatePlayableLevel(random, {
amountColors: 4,
stackSize: 16,
extraPlacementStacks: 1,
Expand All @@ -121,11 +121,12 @@ describe(generatePlayableLevel, () => {

it("throws an error if it can't generate a playable level", () => {
const random = mulberry32(TEST_SEED);
expect(() =>
generatePlayableLevel(random, {
amountColors: 1,
extraPlacementStacks: 0,
})
).toThrowError("Can't generate playable level");
expect(
async () =>
await generatePlayableLevel(random, {
amountColors: 1,
extraPlacementStacks: 0,
})
).rejects.toThrow("Can't generate playable level");
});
});
29 changes: 21 additions & 8 deletions src/game/generateLevel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ export type LevelSettings = {
bufferSizes?: number;
};

export const generatePlayableLevel = (
const MAX_PLAY_ATTEMPTS = 20;
const MAX_GENERATE_ATTEMPTS = 50;
const MAX_LEVEL_MOVES = 1000;

const delay = async (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));

export const generatePlayableLevel = async (
random: () => number,
settings: LevelSettings
): LevelState => {
): Promise<LevelState> => {
let attempt = 0;

while (attempt < 10) {
while (attempt < MAX_GENERATE_ATTEMPTS) {
attempt++;
const level = generateLevel(random, settings);
if (isStuck(level)) {
Expand All @@ -46,7 +52,7 @@ const isBeatable = (
): [beatable: boolean, moves: number] => {
let attempt = 0;

while (attempt < 10) {
while (attempt < MAX_PLAY_ATTEMPTS) {
let playLevel = level;
let moves = 0;

Expand All @@ -56,6 +62,9 @@ const isBeatable = (
break;
} else {
moves++;
if (moves > MAX_LEVEL_MOVES) {
break;
}
playLevel = moveBlocks(playLevel, nextMove[0], nextMove[1]);
}
if (hasWon(playLevel)) {
Expand Down Expand Up @@ -86,10 +95,14 @@ const getMove = (
const destinations = level.columns.reduce<number[]>((r, c, destination) => {
if (destination === source) return r;
const destBlock = c.blocks[0];

// TODO: Needs refactor for readability
if (destBlock?.color === block.color && c.columnSize > c.blocks.length) {
return r.concat(destination);
}
if (
(destBlock?.color === block.color ||
(destBlock === undefined &&
(c.limitColor === undefined || c.limitColor === block.color))) &&
destBlock === undefined &&
(c.limitColor === undefined || c.limitColor === block.color) &&
c.columnSize > c.blocks.length
) {
return r.concat(destination);
Expand Down
2 changes: 1 addition & 1 deletion src/game/levelSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const getNormalSettings = (
random: () => number,
levelNr: number
): LevelSettings => {
const amountColors = levelNr === 0 ? 2 : getSetting(levelNr, 3, 9, 0, 1); // 3, 9, 4, 4
const amountColors = levelNr === 0 ? 2 : getSetting(levelNr, 3, 7, 4, 4);
const stackSize = 4;

return {
Expand Down
Loading

0 comments on commit 363a791

Please sign in to comment.