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; return result;
}; };
const challengeTypes: Array<DailyChallengeType> = [ const progressionChallengeTypes: Array<DailyChallengeType> = [
"clicks",
"bossesDefeated", "bossesDefeated",
"questsCompleted", "questsCompleted",
"prestige", "prestige",
@@ -80,7 +79,8 @@ const challengeTypes: Array<DailyChallengeType> = [
/** /**
* Generates 3 daily challenges for the given date string, deterministically. * 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. * @param dateString - The date string (YYYY-MM-DD) to generate challenges for.
* @returns An array of 3 DailyChallenge objects. * @returns An array of 3 DailyChallenge objects.
*/ */
@@ -88,8 +88,10 @@ const generateDailyChallenges = (
dateString: string, dateString: string,
): Array<DailyChallenge> => { ): Array<DailyChallenge> => {
const seed = dateSeed(dateString); const seed = dateSeed(dateString);
const selectedTypes = shuffleWithSeed([ ...challengeTypes ], seed). const selectedTypes: Array<DailyChallengeType> = [
slice(0, 3); "clicks",
...shuffleWithSeed([ ...progressionChallengeTypes ], seed).slice(0, 2),
];
return selectedTypes.map((type, index) => { return selectedTypes.map((type, index) => {
const templates = dailyChallengeTemplates.filter((template) => { 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)); 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 () => { it("generates different challenges for different dates", async () => {
vi.setSystemTime(LA_MIDNIGHT_2024_01_15); vi.setSystemTime(LA_MIDNIGHT_2024_01_15);
const { generateDailyChallenges } = await import("../../src/services/dailyChallenges.js"); const { generateDailyChallenges } = await import("../../src/services/dailyChallenges.js");
const day1 = generateDailyChallenges("2024-01-15"); const day1 = generateDailyChallenges("2024-01-15");
const day2 = generateDailyChallenges("2024-01-16"); const day2 = generateDailyChallenges("2024-01-16");
// They should differ in at least one challenge ID (types vary by seed) // The 2 non-clicks types should vary by seed between dates
expect(day1.map((c) => c.type)).not.toEqual(day2.map((c) => c.type)); 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);
}); });
}); });