1use crate::capital::{Capital, PublicCapital};
5use crate::error::{Error, Result};
6use crate::ethic::Ethics;
7use crate::resources::Resources;
8use crate::resources::gold::Gold;
9use crate::resources::influence::Influence;
10use crate::ruler::Ruler;
11use derive_more::{Display, From, Into};
12use serde::{Deserialize, Serialize};
13use std::borrow::{Borrow, Cow};
14use std::collections::HashMap;
15use std::ops::Deref;
16use std::sync::Arc;
17
18#[derive(Clone, Debug, Default, Deserialize, Serialize)]
19#[serde(rename_all = "camelCase")]
20pub struct BotManager(HashMap<BotId, Bot>);
21
22impl BotManager {
23 pub(crate) fn manage(&mut self, id: BotId) -> Result<()> {
24 if self.0.contains_key(&id) {
25 return Err(Error::BotAlreadySpawned(id));
26 }
27
28 self.0.insert(id.clone(), Bot::new(id));
29
30 Ok(())
31 }
32
33 pub fn bot(&self, id: &BotId) -> Result<&Bot> {
34 self
35 .0
36 .get(id)
37 .ok_or_else(|| Error::BotNotFound(id.clone()))
38 }
39
40 pub(crate) fn bot_mut(&mut self, id: &BotId) -> Result<&mut Bot> {
41 self
42 .0
43 .get_mut(id)
44 .ok_or_else(|| Error::BotNotFound(id.clone()))
45 }
46
47 pub fn bots(&self) -> impl Iterator<Item = &Bot> {
48 self.0.values()
49 }
50}
51
52#[derive(Clone, Debug, Deserialize, Serialize)]
53#[serde(rename_all = "camelCase")]
54#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
55pub struct Bot {
56 id: BotId,
57 pub(crate) ethics: Ethics,
58 pub(crate) capital: Capital,
59 pub(crate) resources: Resources,
60 pub(crate) gold: Gold,
61 pub(crate) influence: Influence,
62}
63
64impl Bot {
65 pub fn new(id: BotId) -> Self {
66 Self {
67 id,
68 ethics: Ethics::random(),
69 capital: Capital::default(),
70 resources: Resources::BOT,
71 gold: Gold::MIN,
72 influence: Influence::MIN,
73 }
74 }
75
76 #[inline]
77 pub fn id(&self) -> BotId {
78 self.id.clone()
79 }
80
81 #[inline]
82 pub fn ethics(&self) -> Ethics {
83 self.ethics
84 }
85
86 #[inline]
87 pub fn capital(&self) -> &Capital {
88 &self.capital
89 }
90
91 #[inline]
92 pub fn resources(&self) -> Resources {
93 self.resources
94 }
95
96 #[inline]
97 pub fn gold(&self) -> Gold {
98 self.gold
99 }
100
101 #[inline]
102 pub fn influence(&self) -> Influence {
103 self.influence
104 }
105}
106
107#[derive(
108 Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, Deserialize, Serialize,
109)]
110#[from(String, &str, Arc<str>, Box<str>, Cow<'_, str>)]
111#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
112pub struct BotId(Arc<str>);
113
114impl Clone for BotId {
115 fn clone(&self) -> Self {
116 Self(Arc::clone(&self.0))
117 }
118}
119
120impl AsRef<str> for BotId {
121 fn as_ref(&self) -> &str {
122 self.0.as_str()
123 }
124}
125
126impl Deref for BotId {
127 type Target = str;
128
129 fn deref(&self) -> &Self::Target {
130 self.0.as_str()
131 }
132}
133
134impl Borrow<str> for BotId {
135 fn borrow(&self) -> &str {
136 self.0.as_str()
137 }
138}
139
140impl From<BotId> for String {
141 fn from(value: BotId) -> Self {
142 String::from(value.0.as_ref())
143 }
144}
145
146impl PartialEq<Ruler> for BotId {
147 fn eq(&self, other: &Ruler) -> bool {
148 if let Ruler::Bot { id } = other { self.eq(id) } else { false }
149 }
150}
151
152#[derive(Clone, Debug, Deserialize, Serialize)]
153#[serde(rename_all = "camelCase")]
154#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
155pub struct PublicBot {
156 id: BotId,
157 capital: PublicCapital,
158}
159
160impl From<&Bot> for PublicBot {
161 fn from(bot: &Bot) -> Self {
162 Self {
163 id: bot.id.clone(),
164 capital: PublicCapital::from(&bot.capital),
165 }
166 }
167}