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 pub(crate) fn gold_mut(&mut self) -> &mut Gold {
103 &mut self.gold
104 }
105
106 #[inline]
107 pub fn influence(&self) -> Influence {
108 self.influence
109 }
110}
111
112#[derive(
113 Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, Deserialize, Serialize,
114)]
115#[from(String, &str, Arc<str>, Box<str>, Cow<'_, str>)]
116#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
117pub struct BotId(Arc<str>);
118
119impl Clone for BotId {
120 fn clone(&self) -> Self {
121 Self(Arc::clone(&self.0))
122 }
123}
124
125impl AsRef<str> for BotId {
126 fn as_ref(&self) -> &str {
127 self.0.as_str()
128 }
129}
130
131impl Deref for BotId {
132 type Target = str;
133
134 fn deref(&self) -> &Self::Target {
135 self.0.as_str()
136 }
137}
138
139impl Borrow<str> for BotId {
140 fn borrow(&self) -> &str {
141 self.0.as_str()
142 }
143}
144
145impl From<BotId> for String {
146 fn from(value: BotId) -> Self {
147 String::from(value.0.as_ref())
148 }
149}
150
151impl PartialEq<Ruler> for BotId {
152 fn eq(&self, other: &Ruler) -> bool {
153 if let Ruler::Bot { id } = other { self.eq(id) } else { false }
154 }
155}
156
157#[derive(Clone, Debug, Deserialize, Serialize)]
158#[serde(rename_all = "camelCase")]
159#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
160pub struct PublicBot {
161 id: BotId,
162}
163
164impl From<&Bot> for PublicBot {
165 fn from(bot: &Bot) -> Self {
166 Self { id: bot.id.clone() }
167 }
168}