1use std::collections::VecDeque;
2
3use serde::{Deserialize, Serialize};
4
5use crate::db::CardId;
6use crate::effects::ReplacementSpec;
7use crate::error::StateError;
8use crate::util::Rng64;
9
10use super::{
11 AttackContext, CardInstance, CardInstanceId, ChoiceState, CostPaymentState, DerivedAttackState,
12 EncoreRequest, GrantedAbilityInstance, ModifierInstance, PendingTrigger, Phase, PlayerState,
13 PriorityState, RevealHistory, StackItem, StackOrderState, TargetSelectionState, TimingWindow,
14 TriggerOrderState,
15};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
19pub enum TerminalResult {
20 Win {
22 winner: u8,
24 },
25 Draw,
27 Timeout,
29}
30
31#[derive(Clone, Debug, Hash)]
33pub struct TurnState {
34 pub active_player: u8,
36 pub starting_player: u8,
38 pub turn_number: u32,
40 pub phase: Phase,
42 pub mulligan_done: [bool; 2],
44 pub mulligan_selected: [u64; 2],
46 pub main_passed: bool,
48 pub main_move_used: bool,
50 pub decision_count: u32,
52 pub tick_count: u32,
54 pub attack: Option<AttackContext>,
56 pub attack_subphase_count: u8,
58 pub pending_level_up: Option<u8>,
60 pub encore_queue: Vec<EncoreRequest>,
62 pub encore_step_player: Option<u8>,
64 pub pending_triggers: Vec<PendingTrigger>,
66 pub pending_triggers_sorted: bool,
68 pub active_window: Option<TimingWindow>,
70 pub end_phase_window_done: bool,
72 pub end_phase_discard_done: bool,
74 pub end_phase_climax_done: bool,
76 pub end_phase_cleanup_done: bool,
78 pub encore_window_done: bool,
80 pub pending_losses: [bool; 2],
82 pub damage_resolution_target: Option<u8>,
84 pub cost_payment_depth: u8,
86 pub pending_resolution_cleanup: Vec<(u8, CardInstanceId)>,
88 pub cannot_use_auto_encore: [bool; 2],
90 pub rule_overrides: Vec<crate::effects::RuleOverrideKind>,
92 pub granted_abilities: Vec<GrantedAbilityInstance>,
94 pub next_grant_id: u64,
96 pub phase_step: u8,
98 pub attack_phase_begin_done: bool,
100 pub attack_decl_check_done: bool,
102 pub encore_begin_done: bool,
104 pub trigger_order: Option<TriggerOrderState>,
106 pub choice: Option<ChoiceState>,
108 pub target_selection: Option<TargetSelectionState>,
110 pub pending_cost: Option<CostPaymentState>,
112 pub priority: Option<PriorityState>,
114 pub stack: Vec<StackItem>,
116 pub pending_stack_groups: VecDeque<StackOrderState>,
118 pub stack_order: Option<StackOrderState>,
120 pub derived_attack: Option<DerivedAttackState>,
122 pub next_trigger_id: u32,
124 pub next_trigger_group_id: u32,
126 pub next_choice_id: u32,
128 pub next_stack_group_id: u32,
130 pub next_damage_event_id: u32,
132 pub next_effect_instance_id: u32,
134 pub end_phase_pending: bool,
136}
137
138#[derive(Clone, Debug, Hash)]
140pub struct GameState {
141 pub players: [PlayerState; 2],
143 pub reveal_history: [RevealHistory; 2],
145 pub turn: TurnState,
147 pub rng: Rng64,
149 pub modifiers: Vec<ModifierInstance>,
151 pub next_modifier_id: u32,
153 pub replacements: Vec<ReplacementSpec>,
155 pub next_replacement_insertion: u32,
157 pub terminal: Option<TerminalResult>,
159}
160
161impl GameState {
162 pub fn new(
164 deck_a: Vec<CardId>,
165 deck_b: Vec<CardId>,
166 seed: u64,
167 starting_player: u8,
168 ) -> Result<Self, StateError> {
169 if starting_player > 1 {
170 return Err(StateError::InvalidStartingPlayer {
171 got: starting_player,
172 });
173 }
174 if deck_a.len() != crate::encode::MAX_DECK {
175 return Err(StateError::DeckLength {
176 owner: 0,
177 got: deck_a.len(),
178 expected: crate::encode::MAX_DECK,
179 });
180 }
181 if deck_b.len() != crate::encode::MAX_DECK {
182 return Err(StateError::DeckLength {
183 owner: 1,
184 got: deck_b.len(),
185 expected: crate::encode::MAX_DECK,
186 });
187 }
188 let rng = Rng64::new(seed);
189 let mut next_instance_id: CardInstanceId = 1;
190 let deck_a = Self::build_deck(deck_a, 0, &mut next_instance_id);
191 let deck_b = Self::build_deck(deck_b, 1, &mut next_instance_id);
192 Ok(Self {
193 players: [PlayerState::new(deck_a), PlayerState::new(deck_b)],
194 reveal_history: [RevealHistory::new(), RevealHistory::new()],
195 turn: TurnState {
196 active_player: starting_player,
197 starting_player,
198 turn_number: 0,
199 phase: Phase::Mulligan,
200 mulligan_done: [false; 2],
201 mulligan_selected: [0; 2],
202 main_passed: false,
203 main_move_used: false,
204 decision_count: 0,
205 tick_count: 0,
206 attack: None,
207 attack_subphase_count: 0,
208 pending_level_up: None,
209 encore_queue: Vec::new(),
210 encore_step_player: None,
211 pending_triggers: Vec::new(),
212 pending_triggers_sorted: true,
213 trigger_order: None,
214 choice: None,
215 target_selection: None,
216 pending_cost: None,
217 priority: None,
218 stack: Vec::new(),
219 pending_stack_groups: VecDeque::new(),
220 stack_order: None,
221 derived_attack: None,
222 next_trigger_id: 1,
223 next_trigger_group_id: 1,
224 next_choice_id: 1,
225 next_stack_group_id: 1,
226 next_damage_event_id: 1,
227 next_effect_instance_id: 1,
228 active_window: None,
229 end_phase_window_done: false,
230 end_phase_discard_done: false,
231 end_phase_climax_done: false,
232 end_phase_cleanup_done: false,
233 encore_window_done: false,
234 pending_losses: [false; 2],
235 damage_resolution_target: None,
236 cost_payment_depth: 0,
237 pending_resolution_cleanup: Vec::new(),
238 cannot_use_auto_encore: [false; 2],
239 rule_overrides: Vec::new(),
240 granted_abilities: Vec::new(),
241 next_grant_id: 1,
242 phase_step: 0,
243 attack_phase_begin_done: false,
244 attack_decl_check_done: false,
245 encore_begin_done: false,
246 end_phase_pending: false,
247 },
248 rng,
249 modifiers: Vec::new(),
250 next_modifier_id: 1,
251 replacements: Vec::new(),
252 next_replacement_insertion: 1,
253 terminal: None,
254 })
255 }
256
257 pub fn new_or_panic(
259 deck_a: Vec<CardId>,
260 deck_b: Vec<CardId>,
261 seed: u64,
262 starting_player: u8,
263 ) -> Self {
264 Self::new(deck_a, deck_b, seed, starting_player).expect("GameState::new_or_panic failed")
265 }
266
267 fn build_deck(
268 deck: Vec<CardId>,
269 owner: u8,
270 next_instance_id: &mut CardInstanceId,
271 ) -> Vec<CardInstance> {
272 deck.into_iter()
273 .map(|id| {
274 let instance_id = *next_instance_id;
275 *next_instance_id = next_instance_id.wrapping_add(1);
276 CardInstance::new(id, owner, instance_id)
277 })
278 .collect()
279 }
280}