Changed other bitwise stuff to use constants
[entelect-challenge-tower-defence.git] / src / input / json.rs
1 use std::fs::File;
2 use std::io::prelude::*;
3 use serde_json;
4 use std::error::Error;
5
6 use engine;
7 use engine::command;
8 use engine::expressive_engine;
9 use engine::bitwise_engine;
10 use engine::constants::*;
11
12 pub fn read_expressive_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, expressive_engine::ExpressiveGameState), Box<Error>> {
13     let mut file = File::open(filename)?;
14     let mut content = String::new();
15     file.read_to_string(&mut content)?;
16     let state: State = serde_json::from_str(content.as_ref())?;
17
18     let engine_settings = state.to_engine_settings();
19     let engine_state = state.to_expressive_engine(&engine_settings);
20     Ok((engine_settings, engine_state))
21 }
22
23 pub fn read_bitwise_state_from_file(filename: &str) -> Result<(engine::settings::GameSettings, bitwise_engine::BitwiseGameState), Box<Error>> {
24     let mut file = File::open(filename)?;
25     let mut content = String::new();
26     file.read_to_string(&mut content)?;
27     let state: State = serde_json::from_str(content.as_ref())?;
28
29     let engine_settings = state.to_engine_settings();
30     let engine_state = state.to_bitwise_engine();
31     Ok((engine_settings, engine_state))
32 }
33
34 #[derive(Deserialize)]
35 #[serde(rename_all = "camelCase")]
36 struct State {
37     game_details: GameDetails,
38     players: Vec<Player>,
39     game_map: Vec<Vec<GameCell>>,
40 }
41
42 #[derive(Deserialize)]
43 #[serde(rename_all = "camelCase")]
44 struct GameDetails {
45     //round: u16,
46     //max_rounds: u16,
47     map_width: u8,
48     map_height: u8,
49     round_income_energy: u16,
50     buildings_stats: BuildingStats
51 }
52
53 #[derive(Deserialize)]
54 #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
55 struct BuildingStats {
56     energy: BuildingBlueprint,
57     defense: BuildingBlueprint,
58     attack: BuildingBlueprint,
59     tesla: BuildingBlueprint,
60 }
61
62 #[derive(Deserialize)]
63 #[serde(rename_all = "camelCase")]
64 struct BuildingBlueprint {
65     price: u16,
66     health: u8,
67     construction_time: u8,
68     weapon_damage: u8,
69     weapon_speed: u8,
70     weapon_cooldown_period: u8,
71     energy_generated_per_turn: u16,
72 //    destroy_multiplier: u16,
73 //    construction_score: u16
74 }
75
76 #[derive(Deserialize)]
77 #[serde(rename_all = "camelCase")]
78 struct Player {
79     player_type: char,
80     energy: u16,
81     health: u8,
82     //hits_taken: u32,
83     //score: u32
84 }
85
86 #[derive(Deserialize)]
87 #[serde(rename_all = "camelCase")]
88 struct GameCell {
89     x: u8,
90     y: u8,
91     buildings: Vec<BuildingState>,
92     missiles: Vec<MissileState>,
93     //cell_owner: char
94 }
95
96 #[derive(Deserialize)]
97 #[serde(rename_all = "camelCase")]
98 struct BuildingState {
99     health: u8,
100     construction_time_left: i8,
101     //price: u16,
102     weapon_damage: u8,
103     weapon_speed: u8,
104     weapon_cooldown_time_left: u8,
105     weapon_cooldown_period: u8,
106     //destroy_multiplier: u32,
107     //construction_score: u32,
108     energy_generated_per_turn: u16,
109     building_type: String,
110     x: u8,
111     y: u8,
112     player_type: char
113 }
114
115 #[derive(Deserialize)]
116 #[serde(rename_all = "camelCase")]
117 struct MissileState {
118     damage: u8,
119     speed: u8,
120     x: u8,
121     y: u8,
122     player_type: char
123 }
124
125
126 impl State {
127     fn to_engine_settings(&self) -> engine::settings::GameSettings {
128         engine::settings::GameSettings::new(
129             engine::geometry::Point::new(self.game_details.map_width, self.game_details.map_height),
130             self.game_details.round_income_energy,
131             self.game_details.buildings_stats.energy.to_engine(),
132             self.game_details.buildings_stats.defense.to_engine(),
133             self.game_details.buildings_stats.attack.to_engine(),
134             self.game_details.buildings_stats.tesla.to_engine(),
135         )
136     }
137     
138     fn to_expressive_engine(&self, settings: &engine::settings::GameSettings) -> expressive_engine::ExpressiveGameState {
139         let player_buildings = self.buildings_to_expressive_engine('A');
140         let opponent_buildings = self.buildings_to_expressive_engine('B');
141         expressive_engine::ExpressiveGameState::new(
142             self.player().to_engine(settings, &player_buildings),
143             self.opponent().to_engine(settings, &opponent_buildings),
144             self.unconstructed_buildings_to_expressive_engine('A'),
145             player_buildings,
146             self.unconstructed_buildings_to_expressive_engine('B'),
147             opponent_buildings,
148             self.missiles_to_expressive_engine('A'),
149             self.missiles_to_expressive_engine('B'),
150             settings
151         )
152     }
153
154     fn to_bitwise_engine(&self) -> bitwise_engine::BitwiseGameState {
155         let mut player = self.player().to_bitwise_engine();
156         let mut opponent = self.opponent().to_bitwise_engine();
157         let mut player_buildings = bitwise_engine::PlayerBuildings::empty();
158         let mut opponent_buildings = bitwise_engine::PlayerBuildings::empty();
159         for row in &self.game_map {
160             for cell in row {
161                 let point = engine::geometry::Point::new(cell.x, cell.y);
162                 for building in &cell.buildings {
163                     let building_type = building.convert_building_type();
164                     
165                     let (mut engine_player, mut bitwise_buildings, bitfield) = if building.player_type == 'A' {
166                         (&mut player, &mut player_buildings, point.to_left_bitfield())
167                     } else {
168                         (&mut opponent, &mut opponent_buildings, point.to_right_bitfield())
169                     };
170
171                     bitwise_buildings.occupied |= bitfield;
172                     if building.construction_time_left >= 0 {
173                         bitwise_buildings.unconstructed.push(building.to_bitwise_engine_unconstructed());
174                     } else {
175                         for health_tier in 0..DEFENCE_HEALTH {
176                             if building.health > health_tier as u8 * MISSILE_DAMAGE {
177                                 bitwise_buildings.buildings[health_tier] |= bitfield;
178                             }
179                         }
180                         if building_type == command::BuildingType::Energy {
181                             bitwise_buildings.energy_towers |= bitfield;
182                             engine_player.energy_generated += building.energy_generated_per_turn;
183                         }
184                         if building_type == command::BuildingType::Attack {
185                             for cooldown_tier in 0..MISSILE_COOLDOWN + 1 {
186                                 if building.weapon_cooldown_time_left == cooldown_tier as u8 {
187                                     bitwise_buildings.missile_towers[cooldown_tier] |= bitfield;
188                                 }
189                             }
190                         }
191                         if building_type == command::BuildingType::Tesla {
192                             let ref mut tesla_cooldown = if bitwise_buildings.tesla_cooldowns[0].active {
193                                 bitwise_buildings.tesla_cooldowns[1]
194                             } else {
195                                 bitwise_buildings.tesla_cooldowns[0]
196                             };
197                             tesla_cooldown.active = true;
198                             tesla_cooldown.pos = point;
199                             tesla_cooldown.cooldown = building.weapon_cooldown_time_left;
200                         }
201                     }
202                 }
203                 for missile in &cell.missiles {
204                     let mut bitwise_buildings = if missile.player_type == 'A' {
205                         &mut player_buildings
206                     } else {
207                         &mut opponent_buildings
208                     };
209                     let (mut left, mut right) = point.to_bitfield();
210
211                     for mut tier in bitwise_buildings.missiles.iter_mut() {
212                         let setting = (!tier.0 & left, !tier.1 & right);
213                         tier.0 |= setting.0;
214                         tier.1 |= setting.1;
215                         left &= !setting.0;
216                         right &= !setting.1;
217                     }
218                 }
219             }
220         }
221             
222         bitwise_engine::BitwiseGameState::new(
223             player, opponent,
224             player_buildings, opponent_buildings
225         )
226     }
227
228     fn player(&self) -> &Player {
229         self.players.iter()
230             .find(|p| p.player_type == 'A')
231             .expect("Player character did not appear in state.json")
232     }
233
234     fn opponent(&self) -> &Player {
235         self.players.iter()
236             .find(|p| p.player_type == 'B')
237             .expect("Opponent character did not appear in state.json")
238     }
239
240     fn unconstructed_buildings_to_expressive_engine(&self, player_type: char) -> Vec<expressive_engine::UnconstructedBuilding> {
241         self.game_map.iter()
242             .flat_map(|row| row.iter()
243                       .flat_map(|cell| cell.buildings.iter()
244                                 .filter(|b| b.player_type == player_type && b.construction_time_left >= 0)
245                                 .map(|b| b.to_expressive_engine_unconstructed())
246                       )
247             )
248             .collect()
249     }
250    
251     fn buildings_to_expressive_engine(&self, player_type: char) -> Vec<expressive_engine::Building> {
252         self.game_map.iter()
253             .flat_map(|row| row.iter()
254                       .flat_map(|cell| cell.buildings.iter()
255                                 .filter(|b| b.player_type == player_type && b.construction_time_left < 0)
256                                 .map(|b| b.to_expressive_engine())
257                       )
258             )
259             .collect()
260     }
261
262     fn missiles_to_expressive_engine(&self, player_type: char) -> Vec<expressive_engine::Missile> {
263         self.game_map.iter()
264             .flat_map(|row| row.iter()
265                       .flat_map(|cell| cell.missiles.iter()
266                                 .filter(|b| b.player_type == player_type)
267                                 .map(|b| b.to_expressive_engine())
268                       )
269             )
270             .collect()
271     }
272 }
273
274 impl BuildingBlueprint {
275     fn to_engine(&self) -> engine::settings::BuildingSettings {
276         engine::settings::BuildingSettings {
277             price: self.price,
278             health: self.health,
279             construction_time: self.construction_time-1,
280             weapon_damage: self.weapon_damage,
281             weapon_speed: self.weapon_speed,
282             weapon_cooldown_period: self.weapon_cooldown_period,
283             energy_generated_per_turn: self.energy_generated_per_turn,
284         }
285     }
286 }
287
288 impl Player {
289     fn to_engine(&self, settings: &engine::settings::GameSettings, buildings: &[expressive_engine::Building]) -> engine::Player {
290         engine::Player {
291             energy: self.energy,
292             health: self.health,
293             energy_generated: settings.energy_income + buildings.iter().map(|b| b.energy_generated_per_turn).sum::<u16>()
294         }
295     }
296     fn to_bitwise_engine(&self) -> engine::Player {
297         engine::Player {
298             energy: self.energy,
299             health: self.health,
300             energy_generated: ENERGY_GENERATED_BASE
301         }
302     }
303 }
304
305 impl BuildingState {
306     fn to_expressive_engine(&self) -> expressive_engine::Building {
307         expressive_engine::Building {
308             pos: engine::geometry::Point::new(self.x, self.y),
309             health: self.health,
310             weapon_damage: self.weapon_damage,
311             weapon_speed: self.weapon_speed,
312             weapon_cooldown_time_left: self.weapon_cooldown_time_left,
313             weapon_cooldown_period: self.weapon_cooldown_period,
314             energy_generated_per_turn: self.energy_generated_per_turn,
315         }
316     }
317
318     fn to_expressive_engine_unconstructed(&self) -> expressive_engine::UnconstructedBuilding {
319         expressive_engine::UnconstructedBuilding {
320             pos: engine::geometry::Point::new(self.x, self.y),
321             health: self.health,
322             construction_time_left: self.construction_time_left as u8, // > 0 check already happened
323             weapon_damage: self.weapon_damage,
324             weapon_speed: self.weapon_speed,
325             weapon_cooldown_period: self.weapon_cooldown_period,
326             energy_generated_per_turn: self.energy_generated_per_turn,
327         }
328     }
329
330     fn to_bitwise_engine_unconstructed(&self) -> bitwise_engine::UnconstructedBuilding {
331         bitwise_engine::UnconstructedBuilding {
332             pos: engine::geometry::Point::new(self.x, self.y),
333             construction_time_left: self.construction_time_left as u8, // > 0 check already happened
334             building_type: self.convert_building_type()
335         }
336     }
337
338     fn convert_building_type(&self) -> command::BuildingType {
339         match self.building_type.as_ref() {
340             "ATTACK" => command::BuildingType::Attack,
341             "ENERGY" => command::BuildingType::Energy,
342             "TESLA" => command::BuildingType::Tesla,
343             _ => command::BuildingType::Defence,
344         }
345     }
346 }
347
348 impl MissileState {
349     fn to_expressive_engine(&self) -> expressive_engine::Missile {
350         expressive_engine::Missile {
351             pos: engine::geometry::Point::new(self.x, self.y),
352             damage: self.damage,
353             speed: self.speed,
354         }
355     }
356 }