use std::fs::File; use std::io::prelude::*; use anyhow::Result; use serde::{Deserialize, Serialize}; use serde_json; use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::state::*; pub fn read_state_from_json_file(filename: &str) -> Result { let mut file = File::open(filename)?; let mut content = String::new(); file.read_to_string(&mut content)?; let json_state: JsonState = serde_json::from_str(content.as_ref())?; Ok(json_state.to_game_state()) } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct JsonState { pub current_round: usize, pub max_rounds: usize, pub player: JsonPlayer, pub opponent: JsonOpponent, pub world_map: Vec>, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct JsonPlayer { id: usize, position: JsonPosition, speed: usize, state: JsonPlayerState, powerups: Vec, boosting: bool, boost_counter: usize, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct JsonOpponent { id: usize, position: JsonPosition, speed: usize, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct JsonWorldMapCell { position: JsonPosition, surface_object: JsonSurfaceObject, occupied_by_player_id: usize, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct JsonPosition { x: usize, y: usize, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum JsonPlayerState { Ready, Nothing, TurningLeft, TurningRight, Accelerating, Decelarating, PickedUpPowerup, UsedBoost, UsedOil, HitMud, Finishing, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum JsonPowerup { Boost, Oil, } #[derive(Serialize_repr, Deserialize_repr, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] #[repr(u8)] pub enum JsonSurfaceObject { Empty = 0, Mud = 1, OilSpill = 2, OilItem = 3, FinishLine = 4, Boost = 5, } impl JsonState { fn to_game_state(&self) -> GameState { GameState { status: GameStatus::Continue, players: [self.player.to_player(), self.opponent.to_player()], obstacles: self .world_map .iter() .flatten() .filter(|cell| { cell.surface_object == JsonSurfaceObject::Mud || cell.surface_object == JsonSurfaceObject::OilSpill }) .map(|cell| cell.position.to_position()) .collect(), powerup_oils: self .world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::OilItem) .map(|cell| cell.position.to_position()) .collect(), powerup_boosts: self .world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::Boost) .map(|cell| cell.position.to_position()) .collect(), finish_lines: self .world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::FinishLine) .map(|cell| cell.position.to_position()) .collect(), } } } impl JsonPlayer { fn to_player(&self) -> Player { Player { position: self.position.to_position(), next_position: self.position.to_position(), speed: self.speed, boost_remaining: self.boost_counter, oils: self .powerups .iter() .filter(|powerup| **powerup == JsonPowerup::Oil) .count(), boosts: self .powerups .iter() .filter(|powerup| **powerup == JsonPowerup::Boost) .count(), finished: false, } } } impl JsonOpponent { // TODO: Track opponent powerups from round to round? fn to_player(&self) -> Player { Player { position: self.position.to_position(), next_position: self.position.to_position(), speed: self.speed, boost_remaining: 0, oils: 0, boosts: 0, finished: false, } } } impl JsonPosition { fn to_position(&self) -> Position { Position { x: self.x, y: self.y, } } }