XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

fix: ensure nightwave daily challenges are unique (#2422)

When generating a daily challenge, we now use sequentiallyUniqueRandomElement with a lookbehind of 2 to ensure the 2 previous (and still active) daily challenges are not duplicated. Re #2411 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2422 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

3d8c1d03
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

2 个文件 +55 -3
Modified src/services/rngService.ts +53 -0
@@ -151,4 +151,57 @@ export class SRng {
151 151 arr[lastIdx] = tmp;
152 152 }
153 153 }
154
155 shuffledArray<T>(inarr: readonly T[]): T[] {
156 const arr = [...inarr];
157 this.shuffleArray(arr);
158 return arr;
159 }
154 160 }
161
162 export const sequentiallyUniqueRandomElement = <T>(
163 deck: readonly T[],
164 idx: number,
165 lookbehind: number,
166 seed: number = 0
167 ): T | undefined => {
168 // This algorithm may modify a shuffle up to index `lookbehind + 1`. It assumes that the last `lookbehind` cards are not adjusted.
169 if (lookbehind + 1 >= deck.length - lookbehind) {
170 throw new Error(
171 `this algorithm cannot guarantee ${lookbehind} unique cards in a row with a deck of size ${deck.length}`
172 );
173 }
174
175 const iteration = Math.trunc(idx / deck.length);
176 const card = idx % deck.length;
177 const currentShuffle = new SRng(mixSeeds(new SRng(iteration).randomInt(0, 100_000), seed)).shuffledArray(deck);
178 if (card < currentShuffle.length - lookbehind) {
179 // We are indexing before the end of the deck, so adjustments may be needed to achieve uniqueness.
180 const window: T[] = [];
181 {
182 const previousShuffle = new SRng(
183 mixSeeds(new SRng(iteration - 1).randomInt(0, 100_000), seed)
184 ).shuffledArray(deck);
185 for (let i = previousShuffle.length - lookbehind; i != previousShuffle.length; ++i) {
186 window.push(previousShuffle[i]);
187 }
188 }
189 // From this point on, `window.length == lookbehind` should hold.
190 for (let i = 0; i != lookbehind; ++i) {
191 if (window.indexOf(currentShuffle[i]) != -1) {
192 for (let j = i; ; ++j) {
193 // `j < currentShuffle.length - lookbehind` should hold.
194 if (window.indexOf(currentShuffle[j]) == -1) {
195 const tmp = currentShuffle[j];
196 currentShuffle[j] = currentShuffle[i];
197 currentShuffle[i] = tmp;
198 break;
199 }
200 }
201 }
202 window.splice(0, 1);
203 window.push(currentShuffle[i]);
204 }
205 }
206 return currentShuffle[card];
207 };
Modified src/services/worldStateService.ts +2 -3
@@ -9,7 +9,7 @@ import darvoDeals from "@/static/fixed_responses/worldState/darvoDeals.json";
9 9 import { buildConfig } from "@/src/services/buildConfigService";
10 10 import { unixTimesInMs } from "@/src/constants/timeConstants";
11 11 import { config } from "@/src/services/configService";
12 import { getRandomElement, getRandomInt, SRng } from "@/src/services/rngService";
12 import { getRandomElement, getRandomInt, sequentiallyUniqueRandomElement, SRng } from "@/src/services/rngService";
13 13 import { eMissionType, ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus";
14 14 import {
15 15 ICalendarDay,
@@ -385,13 +385,12 @@ const getSeasonChallengePools = (syndicateTag: string): IRotatingSeasonChallenge
385 385 const getSeasonDailyChallenge = (pools: IRotatingSeasonChallengePools, day: number): ISeasonChallenge => {
386 386 const dayStart = EPOCH + day * 86400000;
387 387 const dayEnd = EPOCH + (day + 3) * 86400000;
388 const rng = new SRng(new SRng(day).randomInt(0, 100_000));
389 388 return {
390 389 _id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") },
391 390 Daily: true,
392 391 Activation: { $date: { $numberLong: dayStart.toString() } },
393 392 Expiry: { $date: { $numberLong: dayEnd.toString() } },
394 Challenge: rng.randomElement(pools.daily)!
393 Challenge: sequentiallyUniqueRandomElement(pools.daily, day, 2, 605732938)!
395 394 };
396 395 };
397 396