summaryrefslogtreecommitdiff
path: root/2020-overdrive/src/json.rs
diff options
context:
space:
mode:
Diffstat (limited to '2020-overdrive/src/json.rs')
-rw-r--r--2020-overdrive/src/json.rs185
1 files changed, 185 insertions, 0 deletions
diff --git a/2020-overdrive/src/json.rs b/2020-overdrive/src/json.rs
new file mode 100644
index 0000000..82fc9fc
--- /dev/null
+++ b/2020-overdrive/src/json.rs
@@ -0,0 +1,185 @@
+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<GameState> {
+ 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<Vec<JsonWorldMapCell>>,
+}
+
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct JsonPlayer {
+ // id: usize,
+ position: JsonPosition,
+ speed: u16,
+ // state: JsonPlayerState,
+ powerups: Vec<JsonPowerup>,
+ // 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<GameState> {
+ 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<Player> {
+ 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,
+ }
+ }
+}