1use std::{
8 any::Any,
9 collections::{HashMap, HashSet, VecDeque},
10 fmt::Debug,
11 ops::Deref,
12};
13
14pub mod base;
15pub mod core;
16pub mod utils;
17
18mod test;
19mod paradox;
20
21pub type ProvinceAbbr = String;
23
24pub type FleetLoc = (ProvinceAbbr, String);
26
27pub type ArmyLoc = ProvinceAbbr;
29
30use serde::{Deserialize, Serialize};
31
32#[derive(Clone, Serialize, Deserialize)]
34pub struct Province {
35 pub coasts: HashSet<String>,
36 pub is_sea: bool,
37}
38
39#[derive(Clone, Serialize, Deserialize)]
41pub struct Map {
42 pub provinces: HashMap<ProvinceAbbr, Province>,
43 pub fleet_adj: HashSet<(FleetLoc, FleetLoc)>,
44 pub army_adj: HashSet<(ArmyLoc, ArmyLoc)>,
45}
46
47impl Map {
48 pub fn classic() -> Self {
50 let default = include_str!("../data/classic.json");
51
52 serde_json::from_str(default).unwrap()
53 }
54}
55
56#[derive(Clone, Debug, Serialize, Deserialize)]
58pub struct MapState {
59 pub units: HashMap<String, Unit>,
60
61 pub ownership: HashMap<ProvinceAbbr, String>,
65}
66
67#[derive(Clone, Debug, Serialize, Deserialize)]
68#[serde(tag = "type", content = "data", rename_all = "lowercase")]
69pub enum Unit {
70 Army(String),
71 Fleet(String, String),
72}
73
74impl Unit {
75 pub fn nationality(&self) -> String {
76 match self {
77 Unit::Army(s) => s.clone(),
78 Unit::Fleet(s, _) => s.clone(),
79 }
80 }
81}
82
83pub type Orders = HashMap<String, Box<dyn Order>>;
86
87pub trait AsAny {
89 fn as_any(&self) -> &dyn Any;
90}
91
92impl<T: Any> AsAny for T {
93 fn as_any(&self) -> &dyn Any {
94 self
95 }
96}
97
98#[typetag::serde(tag = "type")]
102pub trait Order: 'static + Debug + AsAny + Send + Sync {
103 fn deps(
106 &self,
107 map: &Map,
108 state: &MapState,
109 orders: &Orders,
110 this_prov: &str,
111 ) -> HashSet<String>;
112
113 fn adjudicate(
116 &self,
117 map: &Map,
118 state: &MapState,
119 orders: &Orders,
120 this_prov: &str,
121 order_status: &HashMap<String, bool>,
122 ) -> Option<bool>;
123
124 fn as_owned(&self) -> Box<dyn Order>;
125}
126
127impl Deref for dyn Order {
128 type Target = dyn Any;
129 fn deref(&self) -> &Self::Target {
130 self.as_any()
131 }
132}
133
134impl Clone for Box<dyn Order> {
135 fn clone(&self) -> Self {
136 self.as_owned()
137 }
138}
139
140pub fn adjudicate(map: &Map, state: &MapState, orders: &Orders) -> HashMap<String, bool> {
142 let mut order_status: HashMap<String, bool> = HashMap::new();
143 loop {
144 if order_status.len() == orders.len() {
145 break;
146 }
147
148 let num_resolved = order_status.len();
149
150 for (prov, order) in orders.iter() {
151 if order_status.contains_key(prov) {
152 continue;
153 }
154
155 let deps = order.deps(&map, &state, &orders, prov);
156 let mut restricted_order_status = HashMap::new();
157 for dep_prov in deps {
158 if order_status.contains_key(&dep_prov) {
159 let status = order_status[&dep_prov];
160 restricted_order_status.insert(dep_prov, status);
161 }
162 }
163
164 match order.adjudicate(&map, &state, &orders, prov, &restricted_order_status) {
165 Some(status) => {
166 order_status.insert(prov.to_string(), status);
167 }
168 None => {}
169 }
170 }
171
172 if order_status.len() != num_resolved {
173 continue;
175 }
176
177 paradox::handle_cycles(map, state, orders, &mut order_status);
180 if order_status.len() != num_resolved {
181 continue;
182 }
183
184 paradox::handle_convoy(map, state, orders, &mut order_status);
185 if order_status.len() != num_resolved {
186 continue;
187 }
188
189 break;
190 }
191
192 order_status
193}