fix: guarantee clicks challenge in daily set (#167)
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m7s
CI / Lint, Build & Test (pull_request) Successful in 1m12s

Players blocked on zone progression had days where all three daily
challenges (bossesDefeated, questsCompleted, prestige) required
progression they couldn't make. Always including a clicks challenge
ensures at least one challenge is completable regardless of where
the player is in the game.
This commit is contained in:
2026-03-31 12:48:34 -07:00
committed by Naomi Carrigan
parent ec0763819e
commit 7d1126e8ad
2 changed files with 20 additions and 7 deletions
+7 -5
View File
@@ -71,8 +71,7 @@ const shuffleWithSeed = <T>(array: Array<T>, seed: number): Array<T> => {
return result;
};
const challengeTypes: Array<DailyChallengeType> = [
"clicks",
const progressionChallengeTypes: Array<DailyChallengeType> = [
"bossesDefeated",
"questsCompleted",
"prestige",
@@ -80,7 +79,8 @@ const challengeTypes: Array<DailyChallengeType> = [
/**
* Generates 3 daily challenges for the given date string, deterministically.
* Picks one challenge from 3 different randomly-selected types.
* Always includes a "clicks" challenge (always completable regardless of
* progression), then picks 2 more from the remaining types.
* @param dateString - The date string (YYYY-MM-DD) to generate challenges for.
* @returns An array of 3 DailyChallenge objects.
*/
@@ -88,8 +88,10 @@ const generateDailyChallenges = (
dateString: string,
): Array<DailyChallenge> => {
const seed = dateSeed(dateString);
const selectedTypes = shuffleWithSeed([ ...challengeTypes ], seed).
slice(0, 3);
const selectedTypes: Array<DailyChallengeType> = [
"clicks",
...shuffleWithSeed([ ...progressionChallengeTypes ], seed).slice(0, 2),
];
return selectedTypes.map((type, index) => {
const templates = dailyChallengeTemplates.filter((template) => {
+13 -2
View File
@@ -46,13 +46,24 @@ describe("generateDailyChallenges", () => {
expect(a.map((c) => c.id)).toEqual(b.map((c) => c.id));
});
it("always includes a clicks challenge regardless of date", async () => {
vi.setSystemTime(LA_MIDNIGHT_2024_01_15);
const { generateDailyChallenges } = await import("../../src/services/dailyChallenges.js");
const day1 = generateDailyChallenges("2024-01-15");
const day2 = generateDailyChallenges("2024-01-16");
expect(day1.some((c) => c.type === "clicks")).toBe(true);
expect(day2.some((c) => c.type === "clicks")).toBe(true);
});
it("generates different challenges for different dates", async () => {
vi.setSystemTime(LA_MIDNIGHT_2024_01_15);
const { generateDailyChallenges } = await import("../../src/services/dailyChallenges.js");
const day1 = generateDailyChallenges("2024-01-15");
const day2 = generateDailyChallenges("2024-01-16");
// They should differ in at least one challenge ID (types vary by seed)
expect(day1.map((c) => c.type)).not.toEqual(day2.map((c) => c.type));
// The 2 non-clicks types should vary by seed between dates
const day1NonClicks = day1.filter((c) => c.type !== "clicks").map((c) => c.type);
const day2NonClicks = day2.filter((c) => c.type !== "clicks").map((c) => c.type);
expect(day1NonClicks).not.toEqual(day2NonClicks);
});
});