1use std::collections::HashSet;
2
3#[macro_use]
4extern crate serde_derive;
5
6#[macro_use]
7extern crate eventsourcing_derive;
8pub extern crate eventsourcing;
9
10pub use radar::RadarPing;
11
12pub mod commands;
13pub mod events;
14pub mod leaderboard;
15mod radar;
16pub mod state;
17
18pub(crate) const DOMAIN_VERSION: &str = "1.0";
19
20const DEFAULT_BOARD_HEIGHT: u32 = 100;
21const DEFAULT_BOARD_WIDTH: u32 = 100;
22
23pub const EAX: u32 = 0;
25pub const ECX: u32 = 1;
27pub const EBX: u32 = 2;
29
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
32pub struct Point {
33 pub x: i32,
34 pub y: i32,
35}
36
37impl Point {
38 pub fn new(x: i32, y: i32) -> Point {
39 Point { x, y }
40 }
41
42 pub fn bearing(&self, target: &Point) -> GridDirection {
43 let dx = (target.x - self.x) as f64;
44 let dy = (target.y - self.y) as f64;
45 let mut angle = 90.0 - dy.atan2(dx).to_degrees();
46
47 if angle < 0.0 {
48 angle = angle + 360.0;
49 }
50
51 println!("Angle: {}", angle);
52 let idx = angle.trunc() as usize / 45;
53 ALL_DIRECTIONS[idx]
54 }
55
56 pub fn adjacent_points(&self, board: &GameBoard) -> Vec<Point> {
57 let mut points = Vec::new();
58 for direction in &ALL_DIRECTIONS {
59 if let Some(target) = self.relative_point(board, direction, 1) {
60 points.push(target)
61 }
62 }
63 points
64 }
65
66 pub fn gather_points(
67 &self,
68 board: &GameBoard,
69 direction: &GridDirection,
70 count: usize,
71 ) -> Vec<(Point, usize)> {
72 let mut points = Vec::new();
73 let mut p = Self::relative_point(&self, board, direction, 1);
74 for i in 0..count {
75 match p {
76 Some(point) => {
77 points.push((point.clone(), i + 1));
78 p = Self::relative_point(&point, board, direction, 1);
79 }
80 None => break,
81 }
82 }
83 points
84 }
85
86 pub fn relative_point(
88 &self,
89 board: &GameBoard,
90 direction: &GridDirection,
91 length: i32,
92 ) -> Option<Point> {
93 let destination = match direction {
94 GridDirection::North => Point {
95 x: self.x,
96 y: self.y + length,
97 },
98 GridDirection::NorthEast => Point {
99 x: self.x + length,
100 y: self.y + length,
101 },
102 GridDirection::East => Point {
103 x: self.x + length,
104 y: self.y,
105 },
106 GridDirection::SouthEast => Point {
107 x: self.x + length,
108 y: self.y - length,
109 },
110 GridDirection::South => Point {
111 x: self.x,
112 y: self.y - length,
113 },
114 GridDirection::SouthWest => Point {
115 x: self.x - length,
116 y: self.y - length,
117 },
118 GridDirection::West => Point {
119 x: self.x - length,
120 y: self.y,
121 },
122 GridDirection::NorthWest => Point {
123 x: self.x - length,
124 y: self.y + length,
125 },
126 };
127 if !destination.is_on_board(board) {
128 None
129 } else {
130 Some(destination)
131 }
132 }
133
134 pub fn is_on_board(&self, board: &GameBoard) -> bool {
135 self.x <= board.width as _ && self.y <= board.height as _ && self.x >= 0 && self.y >= 0
136 }
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize, Copy)]
143pub struct GameBoard {
144 pub width: u32,
145 pub height: u32,
146}
147
148impl Default for GameBoard {
149 fn default() -> Self {
150 GameBoard {
151 width: DEFAULT_BOARD_WIDTH,
152 height: DEFAULT_BOARD_HEIGHT,
153 }
154 }
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub enum WeaponType {
159 Primary = 0,
160 Secondary = 1,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
166pub enum RegisterValue {
167 Number(u64),
168 Text(String),
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub enum RegisterOperation {
174 Accumulate(u64),
175 Decrement(u64),
176 Set(RegisterValue),
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq)]
181pub enum GridDirection {
182 North = 0,
183 NorthEast = 1,
184 East = 2,
185 SouthEast = 3,
186 South = 4,
187 SouthWest = 5,
188 West = 6,
189 NorthWest = 7,
190}
191
192static ALL_DIRECTIONS: [GridDirection; 8] = [
193 GridDirection::North,
194 GridDirection::NorthEast,
195 GridDirection::East,
196 GridDirection::SouthEast,
197 GridDirection::South,
198 GridDirection::SouthWest,
199 GridDirection::West,
200 GridDirection::NorthWest,
201];
202
203#[derive(Debug, Clone, Serialize, Deserialize, Default)]
205pub struct MatchParameters {
206 pub match_id: String,
207 pub width: u32,
208 pub height: u32,
209 pub actors: Vec<String>,
210 pub max_turns: u32,
211 pub aps_per_turn: u32,
212}
213
214impl MatchParameters {
215 pub fn new(
216 match_id: String,
217 width: u32,
218 height: u32,
219 max_turns: u32,
220 aps_per_turn: u32,
221 actors: Vec<String>,
222 ) -> Self {
223 MatchParameters {
224 match_id,
225 width,
226 height,
227 actors,
228 max_turns,
229 aps_per_turn,
230 }
231 }
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize, Default)]
235pub struct TurnStatus {
236 pub current: u32,
237 pub taken: HashSet<String>,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub enum DamageSource {
242 Wall,
243 MechWeapon(String),
244 MechCollision(String),
245}
246
247#[cfg(test)]
248mod test {
249 use super::*;
250
251 #[test]
252 fn gather_points() {
253 let board = GameBoard::default();
254 let origin = Point::new(6, 6);
255
256 let points = origin
257 .gather_points(&board, &GridDirection::NorthEast, 6)
258 .into_iter()
259 .map(|(p, _d)| p)
260 .collect::<Vec<_>>();
261 assert_eq!(
262 points,
263 vec![
264 Point::new(7, 7),
265 Point::new(8, 8),
266 Point::new(9, 9),
267 Point::new(10, 10),
268 Point::new(11, 11),
269 Point::new(12, 12)
270 ]
271 );
272
273 let truncated_points = origin
274 .gather_points(&board, &GridDirection::SouthWest, 20)
275 .into_iter()
276 .map(|(p, _d)| p)
277 .collect::<Vec<_>>();
278 assert_eq!(
279 truncated_points,
280 vec![
281 Point::new(5, 5),
282 Point::new(4, 4),
283 Point::new(3, 3),
284 Point::new(2, 2),
285 Point::new(1, 1),
286 Point::new(0, 0),
287 ]
288 );
289 }
290
291 #[test]
292 fn adjacent_points() {
293 let board = GameBoard::default();
294 let origin = Point::new(10, 5);
295 let points = origin.adjacent_points(&board);
296 assert_eq!(
297 points,
298 vec![
299 Point::new(10, 6), Point::new(11, 6),
301 Point::new(11, 5), Point::new(11, 4),
303 Point::new(10, 4), Point::new(9, 4),
305 Point::new(9, 5), Point::new(9, 6),
307 ]
308 )
309 }
310
311 #[test]
312 fn compute_bearing() {
313 let me = Point::new(0, 0);
315 let them = Point::new(5, 5);
316 assert_eq!(me.bearing(&them), GridDirection::NorthEast);
317
318 assert_eq!(
319 Point::new(0, 0).bearing(&Point::new(5, 0)),
320 GridDirection::East
321 );
322 assert_eq!(
323 Point::new(0, 0).bearing(&Point::new(0, -5)),
324 GridDirection::South
325 );
326 assert_eq!(
327 Point::new(1, 1).bearing(&Point::new(-1, -1)),
328 GridDirection::SouthWest
329 );
330 assert_eq!(
331 Point::new(5, 10).bearing(&Point::new(1, 6)),
332 GridDirection::SouthWest
333 );
334 assert_eq!(
335 Point::new(0, 0).bearing(&Point::new(0, 5)),
336 GridDirection::North
337 );
338 assert_eq!(
339 Point::new(6, 8).bearing(&Point::new(10, 4)),
340 GridDirection::SouthEast
341 );
342 assert_eq!(
343 Point::new(9, 11).bearing(&Point::new(4, 11)),
344 GridDirection::West
345 );
346 }
347}