|
@@ -3,7 +3,7 @@ import { readFileSync, existsSync } from 'fs';
|
|
|
import { resolve, dirname } from 'path';
|
|
import { resolve, dirname } from 'path';
|
|
|
import { fileURLToPath } from 'url';
|
|
import { fileURLToPath } from 'url';
|
|
|
import type { WordBank } from '@wordle/shared';
|
|
import type { WordBank } from '@wordle/shared';
|
|
|
-import { computeDifficulty } from '@wordle/shared';
|
|
|
|
|
|
|
+import type { CachedResult } from '@wordle/shared';
|
|
|
import { createDailyRouter } from './routes/daily.js';
|
|
import { createDailyRouter } from './routes/daily.js';
|
|
|
import { createGuessRouter } from './routes/guess.js';
|
|
import { createGuessRouter } from './routes/guess.js';
|
|
|
import { createPlayAgainRouter } from './routes/play-again.js';
|
|
import { createPlayAgainRouter } from './routes/play-again.js';
|
|
@@ -16,37 +16,34 @@ function loadBank(filename: string): WordBank {
|
|
|
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/** Pre-compute difficulty scores for all targets at startup (used by Play Again). */
|
|
|
|
|
-function buildDifficultyMap(bank: WordBank): Map<number, number> {
|
|
|
|
|
- const map = new Map<number, number>();
|
|
|
|
|
- for (const t of bank.targets) {
|
|
|
|
|
- map.set(t.id, computeDifficulty(t.word, bank.guessable));
|
|
|
|
|
- }
|
|
|
|
|
- return map;
|
|
|
|
|
|
|
+// Lazy cache — empty at startup, populated on first API hit for each word.
|
|
|
|
|
+// Background computation upgrades entries from 3-solver to full 4-solver results.
|
|
|
|
|
+function createCache(): Map<number, CachedResult> {
|
|
|
|
|
+ return new Map();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function mountApi(prefix: string, bank: WordBank, difficultyMap: Map<number, number>) {
|
|
|
|
|
|
|
+function mountApi(prefix: string, bank: WordBank, cache: Map<number, CachedResult>) {
|
|
|
return [
|
|
return [
|
|
|
[prefix + '/daily', createDailyRouter(bank)],
|
|
[prefix + '/daily', createDailyRouter(bank)],
|
|
|
[prefix + '/validate', createValidateRouter(bank)],
|
|
[prefix + '/validate', createValidateRouter(bank)],
|
|
|
- [prefix + '/guess', createGuessRouter(bank)],
|
|
|
|
|
- [prefix + '/play-again', createPlayAgainRouter(bank, difficultyMap)],
|
|
|
|
|
|
|
+ [prefix + '/guess', createGuessRouter(bank, cache)],
|
|
|
|
|
+ [prefix + '/play-again', createPlayAgainRouter(bank, cache)],
|
|
|
] as const;
|
|
] as const;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const enBank = loadBank('word-bank.json');
|
|
const enBank = loadBank('word-bank.json');
|
|
|
const ruBank = loadBank('word-bank-ru.json');
|
|
const ruBank = loadBank('word-bank-ru.json');
|
|
|
|
|
|
|
|
-const enDifficulty = buildDifficultyMap(enBank);
|
|
|
|
|
-const ruDifficulty = buildDifficultyMap(ruBank);
|
|
|
|
|
|
|
+const enCache = createCache();
|
|
|
|
|
+const ruCache = createCache();
|
|
|
|
|
|
|
|
const app = express();
|
|
const app = express();
|
|
|
app.use(express.json());
|
|
app.use(express.json());
|
|
|
|
|
|
|
|
// Mount API routes for both languages
|
|
// Mount API routes for both languages
|
|
|
for (const [path, router] of [
|
|
for (const [path, router] of [
|
|
|
- ...mountApi('/api', enBank, enDifficulty),
|
|
|
|
|
- ...mountApi('/ru/api', ruBank, ruDifficulty),
|
|
|
|
|
|
|
+ ...mountApi('/api', enBank, enCache),
|
|
|
|
|
+ ...mountApi('/ru/api', ruBank, ruCache),
|
|
|
]) {
|
|
]) {
|
|
|
app.use(path, router);
|
|
app.use(path, router);
|
|
|
}
|
|
}
|