Add Void difficulty and publish changelogs
Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 3m40s

This commit is contained in:
2026-10-20 14:05:01 +05:00
parent 3ba398a838
commit de0e891b62
37 changed files with 995 additions and 65 deletions

View File

@@ -1,6 +1,12 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { customDifficultySchema, scoreGuess } from "../shared/protocol";
import {
customDifficultySchema,
difficulties,
scoreGuess,
} from "../shared/protocol";
import { createRoomSchema } from "../shared/multiplayer";
import { tournamentSettings } from "../shared/tournaments";
import { mergeDifficultyPresets } from "../shared/difficulty-presets";
const rules = { seconds: 90, zoom: true };
@@ -12,6 +18,8 @@ test("expanded difficulty rules preserve defaults and validate controls", () =>
compass: preset.compass,
coordinates: preset.coordinates,
mapZoom: preset.mapZoom,
mapPan: preset.mapPan,
timerVisible: preset.timerVisible,
scoring: preset.scoring,
},
{
@@ -19,10 +27,19 @@ test("expanded difficulty rules preserve defaults and validate controls", () =>
compass: true,
coordinates: true,
mapZoom: true,
mapPan: true,
timerVisible: true,
scoring: "normal",
},
);
for (const key of ["pan", "compass", "coordinates", "mapZoom"])
for (const key of [
"pan",
"compass",
"coordinates",
"mapZoom",
"mapPan",
"timerVisible",
])
assert.equal(
customDifficultySchema.safeParse({
name: "Fixture",
@@ -96,13 +113,13 @@ test("difficulty names accept normal text and count Unicode characters consisten
});
test("difficulty rules enforce their supported range and strict request shape", () => {
for (const seconds of [15, 90, 600])
for (const seconds of [5, 10, 15, 20, 90, 600])
assert.equal(
customDifficultySchema.safeParse({ name: "Fixture", ...rules, seconds })
.success,
true,
);
for (const seconds of [0, 14, 16, 601, 15.5, NaN, Infinity, "90"])
for (const seconds of [0, 4, 14, 16, 601, 15.5, NaN, Infinity, "90"])
assert.equal(
customDifficultySchema.safeParse({ name: "Fixture", ...rules, seconds })
.success,
@@ -118,6 +135,59 @@ test("difficulty rules enforce their supported range and strict request shape",
);
});
test("Void is the shortest built-in challenge and disables navigation aids", () => {
assert.ok(
Object.entries(difficulties).every(
([id, rule]) => id === "void" || difficulties.void.seconds < rule.seconds,
),
);
for (const rule of [
"zoom",
"pan",
"compass",
"coordinates",
"mapZoom",
"mapPan",
] as const)
assert.equal(difficulties.void[rule], false);
assert.equal(difficulties.void.scoring, "strict");
assert.equal(
createRoomSchema.safeParse({
datasetId: "11111111-1111-4111-8111-111111111111",
difficulty: "void",
playerLimit: 4,
}).success,
true,
);
});
test("Void tournaments preserve ten seconds per mini-round", () => {
const settings = {
name: "Void event",
datasetId: "11111111-1111-4111-8111-111111111111",
difficulty: "void",
playerLimit: 4,
roundCount: 3,
roundTimeSeconds: 10,
timerMode: "perMini",
startsAt: "2026-10-25T12:00:00Z",
announceDiscord: false,
};
assert.equal(tournamentSettings.safeParse(settings).success, true);
assert.equal(
tournamentSettings.safeParse({ ...settings, roundTimeSeconds: 90 }).success,
false,
);
assert.equal(
tournamentSettings.safeParse({ ...settings, timerMode: "shared" }).success,
false,
);
assert.equal(
tournamentSettings.safeParse({ ...settings, difficulty: "normal" }).success,
false,
);
});
test("a delayed preset listing cannot erase a newly saved preset or duplicate it", async () => {
const old = { id: "old", name: "Old", ...rules };
const saved = { id: "saved", name: "New", ...rules };