Skip to main content

manabrew_protocol/prompts/
mod.rs

1use serde::{Deserialize, Serialize};
2use ts_rs::TS;
3
4pub mod common;
5
6pub mod choose_action;
7pub mod choose_attackers;
8pub mod choose_blockers;
9pub mod choose_board_targets;
10pub mod choose_boolean;
11pub mod choose_cards;
12pub mod choose_color;
13pub mod choose_combat_damage_assignment;
14pub mod choose_damage_assignment_order;
15pub mod choose_from_selection;
16pub mod choose_number;
17pub mod dice_rolled;
18pub mod game_over;
19pub mod mulligan;
20pub mod mulligan_put_back;
21pub mod pay_mana_cost;
22pub mod reorder;
23pub mod reveal;
24pub mod scry;
25
26pub use choose_action::{ChooseActionInput, ChooseActionOutput, PassUntil};
27pub use choose_attackers::{ChooseAttackersInput, ChooseAttackersOutput};
28pub use choose_blockers::{ChooseBlockersInput, ChooseBlockersOutput};
29pub use choose_board_targets::{ChooseBoardTargetsInput, ChooseBoardTargetsOutput};
30pub use choose_boolean::{ChooseBooleanInput, ChooseBooleanOutput};
31pub use choose_cards::{ChooseCardsInput, ChooseCardsOutput};
32pub use choose_color::{ChooseColorInput, ChooseColorOutput};
33pub use choose_combat_damage_assignment::{
34    ChooseCombatDamageAssignmentInput, ChooseCombatDamageAssignmentOutput,
35};
36pub use choose_damage_assignment_order::{
37    ChooseDamageAssignmentOrderInput, ChooseDamageAssignmentOrderOutput,
38};
39pub use choose_from_selection::{
40    ChooseFromSelectionInput, ChooseFromSelectionOutput, SelectionOption,
41};
42pub use choose_number::{ChooseNumberInput, ChooseNumberOutput};
43pub use common::{
44    ActivatableAbilityInfo, AlternativeCostKind, AvailableAction, AvailableActionKind,
45    PaymentAction, PaymentActionKind, PaymentResourceKind, PlayCardMode,
46};
47pub use dice_rolled::{DiceRollEntry, DiceRolledInput, DiceRolledOutput};
48pub use game_over::GameOverInput;
49pub use mulligan::{MulliganInput, MulliganOutput};
50pub use mulligan_put_back::{MulliganPutBackInput, MulliganPutBackOutput};
51pub use pay_mana_cost::{PayManaCostInput, PayManaCostOutput};
52pub use reorder::{ReorderInput, ReorderItem, ReorderOutput};
53pub use reveal::{RevealCardsInput, RevealCardsOutput};
54pub use scry::{ScryInput, ScryOutput};
55
56#[derive(Debug, Clone, Serialize, Deserialize, TS)]
57#[serde(tag = "type", rename_all = "camelCase")]
58#[ts(export, export_to = "prompts/promptInput.ts")]
59pub enum PromptInput {
60    Mulligan(mulligan::MulliganInput),
61    MulliganPutBack(mulligan_put_back::MulliganPutBackInput),
62    ChooseAction(choose_action::ChooseActionInput),
63    ChooseAttackers(choose_attackers::ChooseAttackersInput),
64    ChooseBlockers(choose_blockers::ChooseBlockersInput),
65    ChooseBoardTargets(choose_board_targets::ChooseBoardTargetsInput),
66    ChooseBoolean(choose_boolean::ChooseBooleanInput),
67    ChooseFromSelection(choose_from_selection::ChooseFromSelectionInput),
68    GameOver(game_over::GameOverInput),
69    RevealCards(reveal::RevealCardsInput),
70    Scry(scry::ScryInput),
71    ChooseColor(choose_color::ChooseColorInput),
72    ChooseNumber(choose_number::ChooseNumberInput),
73    ChooseDamageAssignmentOrder(choose_damage_assignment_order::ChooseDamageAssignmentOrderInput),
74    ChooseCombatDamageAssignment(
75        choose_combat_damage_assignment::ChooseCombatDamageAssignmentInput,
76    ),
77    PayManaCost(pay_mana_cost::PayManaCostInput),
78    ChooseCards(choose_cards::ChooseCardsInput),
79    Reorder(reorder::ReorderInput),
80    DiceRolled(dice_rolled::DiceRolledInput),
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize, TS)]
84#[serde(tag = "type", content = "output", rename_all = "camelCase")]
85#[ts(export, export_to = "prompts/promptOutput.ts")]
86pub enum PromptOutput {
87    Mulligan(mulligan::MulliganOutput),
88    MulliganPutBack(mulligan_put_back::MulliganPutBackOutput),
89    ChooseAction(choose_action::ChooseActionOutput),
90    ChooseAttackers(choose_attackers::ChooseAttackersOutput),
91    ChooseBlockers(choose_blockers::ChooseBlockersOutput),
92    ChooseBoardTargets(choose_board_targets::ChooseBoardTargetsOutput),
93    ChooseBoolean(choose_boolean::ChooseBooleanOutput),
94    ChooseFromSelection(choose_from_selection::ChooseFromSelectionOutput),
95    RevealCards(reveal::RevealCardsOutput),
96    Scry(scry::ScryOutput),
97    ChooseColor(choose_color::ChooseColorOutput),
98    ChooseNumber(choose_number::ChooseNumberOutput),
99    ChooseDamageAssignmentOrder(choose_damage_assignment_order::ChooseDamageAssignmentOrderOutput),
100    ChooseCombatDamageAssignment(
101        choose_combat_damage_assignment::ChooseCombatDamageAssignmentOutput,
102    ),
103    PayManaCost(pay_mana_cost::PayManaCostOutput),
104    ChooseCards(choose_cards::ChooseCardsOutput),
105    Reorder(reorder::ReorderOutput),
106    DiceRolled(dice_rolled::DiceRolledOutput),
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub enum ResponseViolation {
111    WrongPromptType,
112    UnknownActionId(String),
113}
114
115impl PromptInput {
116    /// The formal prompt/response contract: a response is valid only if its
117    /// output family matches this prompt and every echoed action id was
118    /// advertised by it. Engines reject anything else with a `ProtocolError`.
119    pub fn validate_response(&self, output: &PromptOutput) -> Result<(), ResponseViolation> {
120        use PromptInput as I;
121        use PromptOutput as O;
122        match (self, output) {
123            (I::ChooseAction(input), O::ChooseAction(out)) => match out {
124                ChooseActionOutput::Act { action_id }
125                    if !input.actions.iter().any(|a| a.id == *action_id) =>
126                {
127                    Err(ResponseViolation::UnknownActionId(action_id.clone()))
128                }
129                _ => Ok(()),
130            },
131            (I::PayManaCost(input), O::PayManaCost(out)) => match out {
132                PayManaCostOutput::Act { action_id }
133                    if !input.actions.iter().any(|a| a.id == *action_id) =>
134                {
135                    Err(ResponseViolation::UnknownActionId(action_id.clone()))
136                }
137                _ => Ok(()),
138            },
139            (I::Mulligan(_), O::Mulligan(_))
140            | (I::MulliganPutBack(_), O::MulliganPutBack(_))
141            | (I::ChooseAttackers(_), O::ChooseAttackers(_))
142            | (I::ChooseBlockers(_), O::ChooseBlockers(_))
143            | (I::ChooseBoardTargets(_), O::ChooseBoardTargets(_))
144            | (I::ChooseBoolean(_), O::ChooseBoolean(_))
145            | (I::ChooseFromSelection(_), O::ChooseFromSelection(_))
146            | (I::RevealCards(_), O::RevealCards(_))
147            | (I::Scry(_), O::Scry(_))
148            | (I::ChooseColor(_), O::ChooseColor(_))
149            | (I::ChooseNumber(_), O::ChooseNumber(_))
150            | (I::ChooseDamageAssignmentOrder(_), O::ChooseDamageAssignmentOrder(_))
151            | (I::ChooseCombatDamageAssignment(_), O::ChooseCombatDamageAssignment(_))
152            | (I::ChooseCards(_), O::ChooseCards(_))
153            | (I::Reorder(_), O::Reorder(_))
154            | (I::DiceRolled(_), O::DiceRolled(_)) => Ok(()),
155            _ => Err(ResponseViolation::WrongPromptType),
156        }
157    }
158}