feedback1 WB: R11 bounty drafts as groups + tier-I fill (matches 1 and 6 share a group); solo R11 weights marked assumed

The official R11 bounty drafts are not a free draw under the old rule: matches 1
and 6 show the same 特异III giant and the same four tier-II cards and differ only
in their one tier-I card; 15_7 + 13_8 come together in 3 of the 5 drafts; 10_8,
11_8 and 12_8 never show. A uniform draw under the old rule repeats 5 of 6 cards
in some pair of 5 drafts in about 2.5 % of samples.

- tools/build-data.mjs: BOUNTY_HUNTER_TEMPLATES (the 4 seen R11 groups: giant +
  tier-II cards, fill = the 5 tier-I cards seen) and BOUNTY_HUNTER (the shape an
  unseen slot draws: one giant + 1-4 tier-II cards + tier-I fill, one card per
  faction series 10-15). choices.json bountyDrafts.hunter gains slots (15),
  templates and rule. The R9 note now names the per-match explanation (leader,
  map) beside two versions. Solo 绝境 / 终极 R11 family weights are marked as
  extrapolated from co-op.
- server/match/choices.js: the hunter draft picks one of the 15 event slots: a
  seen group, or a rule group of that shape, then tier-I fill.
- test/match/feedback1-bounty.test.js: each official R11 bounty draft fits
  exactly one seen group and the rule shape; matches 1 / 6 share 5 cards;
  generated drafts: a seen group in about 4 of 15, every seen group and every
  R11 card offered.
- docs/DATA.md, docs/META.md: the R11 structure, the solo weights and the R9
  open question.
This commit is contained in:
sganggs committed 2026-10-03 05:08:25 +08:00
1 parent e60067a9f3
commit 7c13e38422
6 files changed
+134 -43

No files matched your search

+21 -3
View File
@@ -11,7 +11,9 @@
// set, or for an unseen slot one card from each of 6 of the series 10–15 / 20 with the
// tiers I I I II II III;
// boss (R9): a seen group of named bosses + the group's cheap boss bounties / 源石虫·特训 to 6;
// hunter (R11): one 特异III giant + 5 "下场战斗" cards, at most one per faction series;
// hunter (R11): one of the 15 official events — a seen group (a 特异III giant + its tier-II
// "下场战斗" cards, always together) or for an unseen slot a group of that shape
// [ASSUMED] — filled to 6 with tier-I cards, at most one card per faction series;
// only `draft` cards of that `draftPool` (never 战术特训 — 法术教鞭 only —, the 鸭爵 set, the 7
// multi-round cards or the pre-series cards: no official draft shows them); positions shuffled; the
// mode's inactive enemy list does not apply (PRTS 卫戍协议:盟约 11/18 note "以上调整仅针对战术特训敌人,
@@ -232,9 +234,25 @@ function structuredBounty(rng, kind, spec, byId) {
return [...featured, ...drawDistinct(rng, get(t.fill), count - featured.length, taken)].slice(0, count);
}
if (kind === 'hunter') {
// one of the official events: a seen group, or for an unseen slot a group of the same shape; then tier-I fill to 6
const onePer = new Set(Array.isArray(spec.onePerSeries) ? spec.onePerSeries : []);
const anchors = drawDistinct(rng, get(spec.anchors), Number.isInteger(spec.anchorCount) ? spec.anchorCount : 1, taken);
return [...anchors, ...drawDistinct(rng, get(spec.rest), count - anchors.length, taken, onePer)];
const templates = Array.isArray(spec.templates) ? spec.templates : [];
const slots = Math.max(templates.length, Number.isInteger(spec.slots) ? spec.slots : 0);
const slot = slots > 0 ? rng.int(slots) : 0;
let group;
let fill;
if (slot < templates.length) {
group = get(templates[slot].featured);
group.forEach((c) => taken.add(c));
fill = get(templates[slot].fill);
} else {
const r = spec.rule || {};
const sizes = Array.isArray(r.groupSizes) && r.groupSizes.length ? r.groupSizes : [1];
const giant = drawDistinct(rng, get(r.giants), 1, taken);
group = [...giant, ...drawDistinct(rng, get(r.groupCards), rng.pick(sizes), taken, onePer)];
fill = get(r.fill);
}
return [...group, ...drawDistinct(rng, fill, count - group.length, taken, onePer)];
}
return [];
}