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