use std::convert::TryInto; use std::fs::File; use std::io::prelude::*; use std::rc::Rc; 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())?; 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: u16, // state: JsonPlayerState, powerups: Vec, // boosting: bool, boost_counter: u8, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct JsonOpponent { // id: usize, position: JsonPosition, speed: u16, } #[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 { y: u8, x: u16, } // #[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, // HitOil, // 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) -> Result { Ok(GameState { status: GameStatus::Continue, players: [self.player.to_player()?, self.opponent.to_player()], muds: Rc::new( self.world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::Mud) .map(|cell| cell.position.to_position()) .collect(), ), oil_spills: Rc::new( self.world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::OilSpill) .map(|cell| cell.position.to_position()) .collect(), ), powerup_oils: Rc::new( self.world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::OilItem) .map(|cell| cell.position.to_position()) .collect(), ), powerup_boosts: Rc::new( self.world_map .iter() .flatten() .filter(|cell| cell.surface_object == JsonSurfaceObject::Boost) .map(|cell| cell.position.to_position()) .collect(), ), }) } } impl JsonPlayer { fn to_player(&self) -> Result { Ok(Player { position: self.position.to_position(), speed: self.speed, boost_remaining: self.boost_counter, oils: self .powerups .iter() .filter(|powerup| **powerup == JsonPowerup::Oil) .count() .try_into()?, boosts: self .powerups .iter() .filter(|powerup| **powerup == JsonPowerup::Boost) .count() .try_into()?, }) } } impl JsonOpponent { // TODO: Track opponent powerups from round to round? fn to_player(&self) -> Player { Player { position: self.position.to_position(), speed: self.speed, boost_remaining: 0, oils: 0, boosts: 0, } } } impl JsonPosition { fn to_position(&self) -> Position { Position { x: self.x, y: self.y, } } }