feedback1 WB: R11 bounty list drawn from the 7 seen lists; R9 group sizes stated as they are; official 机密商店 composition only at R11

- R11 悬赏决策: the list is one of the 7 seen lists, uniform (slots 7, taken as the events
  bounty_hunter_1..7, one block of effectChoiceInfoDict). No list is built from nothing any more;
  the rule only completes the 4 lists seen with 6 cards, so 12_8 / 16_2 / 16_6 come in about
  1 R11 bounty draft in 15 (14 drafts without one: about 39 %).
- R9: the groups hold 9, 9, 9, 9, 8 and 6 cards (comments, docs, test); match 4's base-only
  group may be a draft of another group (open). 58 -> 59 bounty drafts in the build-data note.
- 机密商店: shopDraft.rounds [11]. The official composition (VI, VI, V, 盟约之币 + 2) applies at
  R11 (绝境 / 终极, where the screenshots are); the earlier 标准 / 险境 shops keep the previous draw,
  any tier I-VI per card with replacement (repeats still possible, about 26 %).
- Tests: R11 slots / block order / never-shown rate, R9 group sizes, the non-R11 shop draw.
This commit is contained in:
sganggs committed 2026-10-03 08:09:39 +08:00
1 parent c50dc8666c
commit 3b18376eb7
9 files changed
+153 -58

No files matched your search

+43 -3
View File
@@ -2,9 +2,10 @@
// "机密商店按官方改成可以重复吧"). The 4 official 机密商店 (R11 of matches 2, 4, 5 and 8 in
// test/fixtures/official-bounty-drafts.json) offer the same item twice (盟约之币 ×2 in 4 and 5, 变形同构体 ×2 in 8) and
// share one composition: exactly two tier-VI items, at least one tier V, at least one 盟约之币, no other tier-I / II item.
// choices.json `shopDraft` (tools/build-data.mjs SHOP_DRAFT) draws six slots on their own, with replacement; picking one
// of two identical cards is in test/content/choices.test.js (E2E), the overlay with two identical cards in
// test/ui/feedback1-secret-shop.test.js.
// choices.json `shopDraft` (tools/build-data.mjs SHOP_DRAFT) draws six slots on their own, with replacement, at R11 (the
// round of the screenshots; 绝境 / 终极 only); the earlier 机密商店 of 标准 / 险境 (no screenshot) keep the previous draw,
// any tier I–VI with replacement. Picking one of two identical cards is in test/content/choices.test.js (E2E), the
// overlay with two identical cards in test/ui/feedback1-secret-shop.test.js.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
@@ -47,6 +48,7 @@ test('机密商店 (4 official shops): six free items, two of them tier VI, a ti
assert.deepEqual(rest, { 3: 1, 4: 2, 5: 3, coin: 2 });
for (const s of SHOP.slots.slice(4)) assert.deepEqual(s, rest);
assert.equal(SHOP.slots.length, 6);
assert.deepEqual(SHOP.rounds, [11], 'the composition where the screenshots are: R11 (绝境 / 终极)');
// an item's weight within its tier: 1 + the official cards it showed on
const seen = {};
for (const { cards } of SHOPS) for (const [n] of cards) if (n !== '盟约之币') seen[itemByName(n).id] = (seen[itemByName(n).id] || 0) + 1;
@@ -100,3 +102,41 @@ test('机密商店 generated (co-op 绝境 R11): the official composition, drawn
assert.ok(d.cards.every((c) => c.id === COIN || DATA.items[c.id].tier >= 3));
}
});
test('机密商店 outside R11 (标准 R3 / R9, 险境 R3 / R6 / R9 — no screenshot): the previous draw, any tier I–VI per card, with replacement', () => {
// the data's shop events sit in three blocks (artifact_paid_1 by the R3 events, _2 / _3 by the R9 ones, _4 / _5 by
// hardbuff_select), so an early 机密商店 need not look like the R11 one [ASSUMED: keep the previous draw]
const all = new Set([1, 2, 3, 4, 5, 6].flatMap((t) => new GameData(DATA, 'mode_multi_funny').shopItemsByTier[t] || []));
for (const [modeId, rounds] of [['mode_multi_funny', [3, 9]], ['mode_multi_normal', [3, 6, 9]]]) {
assert.deepEqual(DATA.choices.schedule[modeId].spRounds, rounds);
const gd = new GameData(DATA, modeId);
for (const round of rounds) {
let shops = 0;
let dup = 0;
let twoVI = 0;
let lowTier = 0;
const tiers = new Set();
for (let seed = 1; shops < 300 && seed < 40000; seed++) {
const d = generateDraft(gd, createRng(seed * 7717 + round), round, { stageId: 'act2autochess_m01' });
if (d.family !== 'shop') continue;
shops++;
assert.equal(d.cards.length, 6);
assert.deepEqual(d.cards.map((c) => c.idx), [0, 1, 2, 3, 4, 5]);
for (const c of d.cards) {
assert.ok(all.has(c.id), `${modeId} R${round}: ${c.name} is a normal shop item`);
assert.equal(cardView(c).price, 0);
tiers.add(DATA.items[c.id].tier);
}
const ids = d.cards.map((c) => c.id);
if (new Set(ids).size < ids.length) dup++;
if (count(ids, (id) => DATA.items[id].tier === 6) === 2) twoVI++;
if (ids.some((id) => id !== COIN && DATA.items[id].tier <= 2)) lowTier++;
}
assert.equal(shops, 300, `${modeId} R${round}`);
assert.deepEqual([...tiers].sort(), [1, 2, 3, 4, 5, 6], `${modeId} R${round}: every tier`);
assert.ok(twoVI / shops < 0.4, `${modeId} R${round}: two tier-VI items in ${(100 * twoVI / shops).toFixed(0)} % (R11: always)`);
assert.ok(lowTier / shops > 0.5, `${modeId} R${round}: a tier-I / II item besides 盟约之币 in ${(100 * lowTier / shops).toFixed(0)} %`);
assert.ok(dup / shops > 0.12 && dup / shops < 0.42, `${modeId} R${round}: a repeat in ${(100 * dup / shops).toFixed(0)} % (6 of 51, with replacement: about 26 %)`);
}
}
});