weiss_core/encode/
constants.rs

1//! Encoding constants for observations and action ids.
2//!
3//! These values are part of the stable encoding contract. See docs/encodings.md.
4
5use crate::state::REVEAL_HISTORY_LEN;
6
7/// Observation encoding version.
8/// Changelog: <https://github.com/victorwp288/weiss-schwarz-simulator/blob/main/docs/encodings_changelog.md#obs_encoding_version-2>
9pub const OBS_ENCODING_VERSION: u32 = 2;
10/// Action encoding version.
11/// Changelog: <https://github.com/victorwp288/weiss-schwarz-simulator/blob/main/docs/encodings_changelog.md#action_encoding_version-1>
12pub const ACTION_ENCODING_VERSION: u32 = 1;
13/// Policy version used in spec hash composition.
14pub const POLICY_VERSION: u32 = 2;
15/// Combined encoding spec hash.
16pub const SPEC_HASH: u64 = ((OBS_ENCODING_VERSION as u64) << 32)
17    | ((ACTION_ENCODING_VERSION as u64) << 16)
18    | (POLICY_VERSION as u64);
19
20/// Sentinel for missing actor.
21pub const ACTOR_NONE: i8 = -1;
22/// Sentinel for no decision.
23pub const DECISION_KIND_NONE: i8 = -1;
24
25/// Maximum hand size encoded in observations.
26pub const MAX_HAND: usize = 50;
27/// Deck size per player.
28pub const MAX_DECK: usize = 50;
29/// Number of stage slots per player.
30pub const MAX_STAGE: usize = 5;
31/// Maximum number of abilities encoded per card (padding beyond this is ignored).
32pub const MAX_ABILITIES_PER_CARD: usize = 4;
33/// Number of attack slots encoded/considered (front row).
34pub const ATTACK_SLOT_COUNT: usize = 3;
35/// Maximum number of cards encoded in the level zone.
36pub const MAX_LEVEL: usize = 4;
37/// Number of top cards encoded from the clock zone.
38pub const TOP_CLOCK: usize = 7;
39/// Number of top cards encoded from the waiting room zone.
40pub const TOP_WAITING_ROOM: usize = 5;
41/// Number of top cards encoded from the stock zone.
42pub const TOP_STOCK: usize = 5;
43/// Number of top cards encoded from the resolution zone.
44pub const TOP_RESOLUTION: usize = 5;
45
46/// Action id for "confirm mulligan".
47pub const MULLIGAN_CONFIRM_ID: usize = 0;
48/// Base action id for "mulligan select" (hand index offset).
49pub const MULLIGAN_SELECT_BASE: usize = MULLIGAN_CONFIRM_ID + 1;
50/// Number of mulligan select actions (one per possible hand index).
51pub const MULLIGAN_SELECT_COUNT: usize = MAX_HAND;
52
53/// Action id for "pass".
54pub const PASS_ACTION_ID: usize = MULLIGAN_SELECT_BASE + MULLIGAN_SELECT_COUNT;
55/// Base action id for "clock from hand" (hand index offset).
56pub const CLOCK_HAND_BASE: usize = PASS_ACTION_ID + 1;
57/// Number of clock-from-hand actions (one per possible hand index).
58pub const CLOCK_HAND_COUNT: usize = MAX_HAND;
59
60/// Base action id for "main: play character" (hand index and slot offsets).
61pub const MAIN_PLAY_CHAR_BASE: usize = CLOCK_HAND_BASE + CLOCK_HAND_COUNT;
62/// Number of main play character actions.
63pub const MAIN_PLAY_CHAR_COUNT: usize = MAX_HAND * MAX_STAGE;
64/// Base action id for "main: play event" (hand index offset).
65pub const MAIN_PLAY_EVENT_BASE: usize = MAIN_PLAY_CHAR_BASE + MAIN_PLAY_CHAR_COUNT;
66/// Number of main play event actions.
67pub const MAIN_PLAY_EVENT_COUNT: usize = MAX_HAND;
68/// Base action id for "main: move" (from/to slot offsets).
69pub const MAIN_MOVE_BASE: usize = MAIN_PLAY_EVENT_BASE + MAIN_PLAY_EVENT_COUNT;
70/// Number of main move actions.
71pub const MAIN_MOVE_COUNT: usize = MAX_STAGE * (MAX_STAGE - 1);
72
73/// Base action id for "climax: play climax" (hand index offset).
74pub const CLIMAX_PLAY_BASE: usize = MAIN_MOVE_BASE + MAIN_MOVE_COUNT;
75/// Number of climax play actions.
76pub const CLIMAX_PLAY_COUNT: usize = MAX_HAND;
77
78/// Base action id for "attack" (slot and attack-type offsets).
79pub const ATTACK_BASE: usize = CLIMAX_PLAY_BASE + CLIMAX_PLAY_COUNT;
80/// Number of attack actions.
81pub const ATTACK_COUNT: usize = ATTACK_SLOT_COUNT * 3;
82
83/// Base action id for "level up" (index offset).
84pub const LEVEL_UP_BASE: usize = ATTACK_BASE + ATTACK_COUNT;
85/// Number of level-up actions.
86pub const LEVEL_UP_COUNT: usize = 7;
87
88/// Base action id for "encore: pay" (slot offset).
89pub const ENCORE_PAY_BASE: usize = LEVEL_UP_BASE + LEVEL_UP_COUNT;
90/// Number of encore pay actions.
91pub const ENCORE_PAY_COUNT: usize = MAX_STAGE;
92/// Base action id for "encore: decline" (slot offset).
93pub const ENCORE_DECLINE_BASE: usize = ENCORE_PAY_BASE + ENCORE_PAY_COUNT;
94/// Number of encore decline actions.
95pub const ENCORE_DECLINE_COUNT: usize = MAX_STAGE;
96
97/// Base action id for "trigger order" (index offset).
98pub const TRIGGER_ORDER_BASE: usize = ENCORE_DECLINE_BASE + ENCORE_DECLINE_COUNT;
99/// Number of trigger-order actions.
100pub const TRIGGER_ORDER_COUNT: usize = 10;
101
102/// Base action id for "choice select" (index offset).
103pub const CHOICE_BASE: usize = TRIGGER_ORDER_BASE + TRIGGER_ORDER_COUNT;
104/// Number of choice select actions per page.
105pub const CHOICE_COUNT: usize = 16;
106/// Action id for "previous choice page".
107pub const CHOICE_PREV_ID: usize = CHOICE_BASE + CHOICE_COUNT;
108/// Action id for "next choice page".
109pub const CHOICE_NEXT_ID: usize = CHOICE_PREV_ID + 1;
110
111/// Action id for "concede".
112pub const CONCEDE_ID: usize = CHOICE_NEXT_ID + 1;
113/// Total action space size.
114pub const ACTION_SPACE_SIZE: usize = CONCEDE_ID + 1;
115// Action ids are tracked as u16 in sparse mask caches.
116const _: [(); 1] = [(); (ACTION_SPACE_SIZE <= u16::MAX as usize) as usize];
117/// Number of u64 words required to represent the action mask.
118pub const ACTION_SPACE_WORDS: usize = ACTION_SPACE_SIZE.div_ceil(64);
119
120/// Observation header length.
121pub const OBS_HEADER_LEN: usize = 16;
122/// Length of the per-observation "reason" slice.
123pub const OBS_REASON_LEN: usize = 8;
124/// Reason bit/index: in main phase.
125pub const OBS_REASON_IN_MAIN: usize = 0;
126/// Reason bit/index: in climax phase.
127pub const OBS_REASON_IN_CLIMAX: usize = 1;
128/// Reason bit/index: in attack phase.
129pub const OBS_REASON_IN_ATTACK: usize = 2;
130/// Reason bit/index: in counter window.
131pub const OBS_REASON_IN_COUNTER_WINDOW: usize = 3;
132/// Reason bit/index: no stock available.
133pub const OBS_REASON_NO_STOCK: usize = 4;
134/// Reason bit/index: missing color requirement.
135pub const OBS_REASON_NO_COLOR: usize = 5;
136/// Reason bit/index: no cards in hand.
137pub const OBS_REASON_NO_HAND: usize = 6;
138/// Reason bit/index: no valid targets.
139pub const OBS_REASON_NO_TARGETS: usize = 7;
140/// Length of the "reveal history" slice.
141pub const OBS_REVEAL_LEN: usize = REVEAL_HISTORY_LEN;
142/// Length of the "context" slice.
143pub const OBS_CONTEXT_LEN: usize = 4;
144/// Context bit/index: priority window active.
145pub const OBS_CONTEXT_PRIORITY_WINDOW: usize = 0;
146/// Context bit/index: choice selection active.
147pub const OBS_CONTEXT_CHOICE_ACTIVE: usize = 1;
148/// Context bit/index: stack is non-empty.
149pub const OBS_CONTEXT_STACK_NONEMPTY: usize = 2;
150/// Context bit/index: encore is pending.
151pub const OBS_CONTEXT_ENCORE_PENDING: usize = 3;
152/// Number of scalar count slots per player block.
153pub const PER_PLAYER_COUNTS: usize = 9;
154/// Scalars encoded per stage slot.
155pub const PER_STAGE_SLOT: usize = 7;
156/// Total per-player stage slice length.
157pub const PER_PLAYER_STAGE: usize = MAX_STAGE * PER_STAGE_SLOT;
158/// Cards encoded from the climax zone top.
159pub const PER_PLAYER_CLIMAX_TOP: usize = 1;
160/// Cards encoded from the level zone.
161pub const PER_PLAYER_LEVEL: usize = MAX_LEVEL;
162/// Cards encoded from the clock zone top.
163pub const PER_PLAYER_CLOCK_TOP: usize = TOP_CLOCK;
164/// Cards encoded from the waiting room top.
165pub const PER_PLAYER_WAITING_TOP: usize = TOP_WAITING_ROOM;
166/// Cards encoded from the resolution top.
167pub const PER_PLAYER_RESOLUTION_TOP: usize = TOP_RESOLUTION;
168/// Cards encoded from the stock top.
169pub const PER_PLAYER_STOCK_TOP: usize = TOP_STOCK;
170/// Cards encoded from the hand.
171pub const PER_PLAYER_HAND: usize = MAX_HAND;
172/// Cards encoded from the deck.
173pub const PER_PLAYER_DECK: usize = MAX_DECK;
174/// Per-player observation block length.
175pub const PER_PLAYER_BLOCK_LEN: usize = PER_PLAYER_COUNTS
176    + PER_PLAYER_STAGE
177    + PER_PLAYER_CLIMAX_TOP
178    + PER_PLAYER_LEVEL
179    + PER_PLAYER_CLOCK_TOP
180    + PER_PLAYER_WAITING_TOP
181    + PER_PLAYER_RESOLUTION_TOP
182    + PER_PLAYER_STOCK_TOP
183    + PER_PLAYER_HAND
184    + PER_PLAYER_DECK;
185/// Base index of the observation reason slice.
186pub const OBS_REASON_BASE: usize = OBS_HEADER_LEN + 2 * PER_PLAYER_BLOCK_LEN;
187/// Base index of the reveal history slice.
188pub const OBS_REVEAL_BASE: usize = OBS_REASON_BASE + OBS_REASON_LEN;
189/// Base index of the context slice.
190pub const OBS_CONTEXT_BASE: usize = OBS_REVEAL_BASE + OBS_REVEAL_LEN;
191/// Total observation vector length.
192pub const OBS_LEN: usize = OBS_CONTEXT_BASE + OBS_CONTEXT_LEN;