Explorar o código

TileIndex now uses Vec for keeping order

TileIndex can also be used with 'for tile in TileIndex' to iterate over all tiles within the TileIndex

The secret TileIndexIter is not public but is exposed for the for loop's IntoIterator
david hai 1 mes
pai
achega
89e05eebfd
Modificáronse 3 ficheiros con 108 adicións e 88 borrados
  1. 28 8
      src/main.rs
  2. 6 3
      src/tile.rs
  3. 74 77
      src/tile_index.rs

+ 28 - 8
src/main.rs

@@ -12,21 +12,41 @@ use rmmo::*;
 
 fn main() -> Result<(), anyhow::Error> {
     println!("Hello, World!");
-    if let Ok(content) = fs::read_to_string(PathBuf::from("tiles.json")) {
-        let index = serde_json::from_str::<TileIndex>(&content)?;
-        println!("Located {} tiles", index.tiles.len());
-        for (k, t) in index.tiles.iter() {
+    if let Ok(index) = TileIndex::load(PathBuf::from("tiles.json")) {
+        println!("Located {} tiles", index.len());
+        let mut idx: usize = 0;
+        for t in index {
             if let Some(desc) = &t.description {
-                println!("\"{}\" = '{}' {} \"{}\"", k, t.symbol, t.color, desc);
+                println!("{}] \"{}\" = '{}' {} \"{}\"", idx, t.name, t.symbol, t.color, desc);
             } else {
-                println!("\"{}\" = '{}' {}", k, t.symbol, t.color);
+                println!("{}] \"{}\" = '{}' {}", idx, t.name, t.symbol, t.color);
             }
+            idx += 1;
         }
     } else {
-        let index = TileIndex::new();
+        let mut index = TileIndex::new();
+        // index.define(Tile::with_description("", "", "", ""));
+        index.define(Tile::with_description("void", "", "", "You can fly over it, or fall into it"));
+        index.define(Tile::with_description("player", "@", "bright green", "You"));
+        index.define(Tile::with_description("player-neutral", "@", "bright white", "Somebody else"));
+        index.define(Tile::with_description("player-enemy", "@", "bright red", "Somebody else, that's mean"));
+        index.define(Tile::with_description("player-ally", "@", "green", "Somebody else, that's nice"));
+        index.define(Tile::with_description("ground-stone", ".", "white", "A stone path"));
+        index.define(Tile::with_description("ground-grass", ".", "green", "A grassy path"));
+        index.define(Tile::with_description("wall-v-stone", "|", "white", "A stone wall"));
+        index.define(Tile::with_description("wall-h-stone", "-", "white", "A stone wall"));
+        index.define(Tile::with_description("door-c-wood", "+", "brown", "A closed door"));
+        index.define(Tile::with_description("door-o-wood", "-", "brown", "A open door, you can move thru it"));
+        index.define(Tile::with_description("water-shallow", "~", "cyan", "Shallow water, you can wade thru it"));
+        index.define(Tile::with_description("water-deep", "~", "bright blue", "Deep water, you can swim thru it"));
+        index.define(Tile::with_description("gold", "$", "bright yellow", "Gold, a common currency"));
+        index.define(Tile::with_description("gem-blue", "*", "bright cyan", "Sapphire, a rare currency"));
+        index.define(Tile::with_description("gem-red", "*", "red", "Ruby, a rare currency"));
+        index.define(Tile::with_description("gem-green", "*", "bright green", "Emerald, a rare currency"));
+        index.define(Tile::with_description("gem-magenta", "*", "bright magenta", "Amethyst, a rare currency"));
         let content = serde_json::to_string_pretty(&index)?;
         fs::write(PathBuf::from("tiles.json"), content)?;
-        println!("Created {} tiles", index.tiles.len());
+        println!("Created {} tiles", index.len());
     }
     Ok(())
 }

+ 6 - 3
src/tile.rs

@@ -3,21 +3,24 @@ use serde::{Deserialize, Serialize};
 
 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
 pub struct Tile {
+    pub name: String,
     pub description: Option<String>,
     pub symbol: String,
     pub color: String,
 }
 
 impl Tile {
-    pub fn new(sym: &str, col: &str) -> Self {
+    pub fn new(name: &str, sym: &str, col: &str) -> Self {
         Self {
+            name: name.to_string(),
             description: None,
             symbol: sym.to_string(),
             color: col.to_string(),
         }
     }
-    pub fn with_description(sym: &str, col: &str, desc: &str) -> Self {
+    pub fn with_description(name: &str, sym: &str, col: &str, desc: &str) -> Self {
         Self {
+            name: name.to_string(),
             description: Some(desc.to_string()),
             symbol: sym.to_string(),
             color: col.to_string(),
@@ -27,7 +30,7 @@ impl Tile {
         if self.described() {
             return false;
         }
-        self.symbol.is_empty() && self.color.is_empty()
+        self.name.is_empty() && self.symbol.is_empty() && self.color.is_empty()
     }
     pub fn described(&self) -> bool {
         if let Some(desc) = &self.description {

+ 74 - 77
src/tile_index.rs

@@ -1,108 +1,105 @@
-use std::collections::HashMap;
+use std::{fs, path::PathBuf, iter::Iterator};
+
 use serde::{Deserialize, Serialize};
 
 use crate::Tile;
 
 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
 pub struct TileIndex {
-    pub tiles: HashMap<String, Tile>
+    tiles: Vec<Tile>
 }
 
 impl TileIndex {
-    pub fn has(&self, name: &str) -> bool {
-        self.tiles.contains_key(&name.to_string())
+    pub fn new() -> Self {
+        Self { tiles: Vec::new() }
     }
-    pub fn get_index(&self, name: &str) -> Option<usize> {
-        if !self.tiles.contains_key(&name.to_string()) {
-            return None;
-        }
-        let mut index: usize = 0;
-        for (k, _v) in self.tiles.iter() {
-            if k == &name.to_string() {
-                return Some(index);
-            }
-            index += 1;
-        }
-        None
+    pub fn load(path: PathBuf) -> Result<Self, anyhow::Error> {
+        let content = fs::read_to_string(path)?;
+        let index = serde_json::from_str::<TileIndex>(&content)?;
+        Ok(index)
     }
-    pub fn has_index(&self, index: usize) -> bool {
-        if self.tiles.len() < index {
-            return false;
-        }
+    pub fn save(&self, path: PathBuf) -> Result<(), anyhow::Error> {
+        let content = serde_json::to_string_pretty(self)?;
+        fs::write(path, content)?;
+        Ok(())
+    }
+    pub fn len(&self) -> usize {
+        self.tiles.len()
+    }
+    pub fn lookup_index(&self, name: &str) -> Option<usize> {
         let mut idx: usize = 0;
-        for (_k, _v) in self.tiles.iter() {
-            if idx == index {
-                return true;
+        for t in self.tiles.iter() {
+            if t.name == name.to_string() {
+                return Some(idx);
             }
             idx += 1;
         }
-        false
+        None
     }
-    pub fn set_index(&mut self, index: usize, t: Tile) {
-        if self.tiles.len() < index {
-            return;
-        }
-        let mut idx: usize = 0;
-        for (k, _v) in self.tiles.iter() {
-            if idx == index {
-                self.tiles.insert(k.clone(), t);
-                return;
+    pub fn get_name(&self, name: &str) -> Option<&Tile> {
+        for t in self.tiles.iter() {
+            if t.name == name.to_string() {
+                return Some(t);
             }
-            idx += 1;
         }
+        None
     }
-    pub fn get(&self, name: &str) -> Option<&Tile> {
-        if !self.tiles.contains_key(&name.to_string()) {
+    pub fn get_index(&self, index: usize) -> Option<&Tile> {
+        if index >= self.tiles.len() {
             return None;
         }
-        self.tiles.get(&name.to_string())
+        Some(&self.tiles[index])
     }
-    pub fn get_mut(&mut self, name: &str) -> Option<&mut Tile> {
-        if !self.tiles.contains_key(&name.to_string()) {
-            return None;
+    pub fn set(&mut self, t: Tile) -> usize {
+        if let Some(idx) = self.lookup_index(&t.name) {
+            self.tiles[idx] = t;
+            return idx;
         }
-        self.tiles.get_mut(&name.to_string())
+        self.tiles.push(t);
+        self.tiles.len()
     }
-    pub fn set(&mut self, name: &str, t: Tile) {
-        self.tiles.insert(name.to_string(), t);
-    }
-
-    pub fn new() -> Self {
-        let mut s: Self = Self { tiles: HashMap::with_capacity(24) };
-        // s.set("", Tile::with_description("", "", ""));
-        // s.set("", Tile::new("", ""));
-        s.set("void", Tile::with_description("", "", "You can fly over the void, or fall into it"));
-        s.set("player", Tile::with_description("@", "lime", "You"));
-        s.set("player-ally", Tile::with_description("@", "green", "Another Player, an ally to you"));
-        s.set("player-neutral", Tile::with_description("@", "silver", "Another Player, neutral to you"));
-        s.set("player-enemy", Tile::with_description("@", "red", "Another Player, an enemy to you"));
-        s.set("ground-stone", Tile::with_description(".", "gray", "A stone path, you can walk over it"));
-        s.set("ground-grass", Tile::with_description(".", "green", "A grassy path, you can walk over it"));
-        s.set("ground-sand", Tile::with_description(".", "yellow", "A sandy path, you can walk over it"));
-        s.set("wall-v-stone", Tile::with_description("|", "gray", "A stone wall"));
-        s.set("wall-h-stone", Tile::with_description("-", "gray", "A stone wall"));
-        s.set("wall-v-wood", Tile::with_description("|", "brown", "A wooden wall, flammable"));
-        s.set("wall-h-wood", Tile::with_description("-", "brown", "A wooden wall, flammable"));
-        s.set("door-wood-closed", Tile::with_description("x", "brown", "A wooden door, flammable"));
-        s.set("door-wood-open", Tile::with_description("+", "brown", "A wooden door, flammable, you can walk thru it"));
-        s.set("door-stone-closed", Tile::with_description("x", "gray", "A stone door"));
-        s.set("door-stone-open", Tile::with_description("+", "gray", "A stone door, you can walk thru it"));
-        s.set("door-golden-closed", Tile::with_description("x", "gold", "A golden door, find a gold key to open"));
-        s.set("door-golden-open", Tile::with_description("+", "gold", "A golden door, you can walk thru it"));
-        s.set("gold", Tile::with_description("$", "yellow", "Gold, a common currency"));
-        s.set("gem-blue", Tile::with_description("*", "cyan", "Sapphire, a rare currency"));
-        s.set("gem-red", Tile::with_description("*", "bright red", "Ruby, a rare currency"));
-        s.set("gem-green", Tile::with_description("*", "green", "Emerald, a rare currency"));
-        s.set("gem-purple", Tile::with_description("*", "magenta", "Amethyst, a rare currency"));
-        s.set("gem-white", Tile::with_description("*", "bright white", "Quartz, a rare currency"));
-        s
+    pub fn define(&mut self, t: Tile) -> bool {
+        if let Some(_idx) = self.lookup_index(&t.name) {
+            return false;
+        }
+        self.tiles.push(t);
+        true
     }
 }
 
 impl Default for TileIndex {
     fn default() -> Self {
-        let mut s = Self { tiles: HashMap::with_capacity(1) };
-        s.set("void", Tile::with_description("", "", "You can fly over the void, or fall into it"));
-        s
+        Self::new()
+    }
+}
+
+pub struct TileIndexIter {
+    tile_index: TileIndex,
+    index: usize,
+}
+
+impl TileIndexIter {
+    pub fn new(index: TileIndex) -> Self {
+        Self { tile_index: index, index: 0 }
+    }
+}
+
+impl Iterator for TileIndexIter {
+    type Item = Tile;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.index += 1;
+        if let Some(t) = self.tile_index.get_index(self.index-1) {
+            Some(t.clone())
+        } else {
+            None
+        }
+    }
+}
+
+impl IntoIterator for TileIndex {
+    type IntoIter = TileIndexIter;
+    type Item = Tile;
+    fn into_iter(self) -> Self::IntoIter {
+        TileIndexIter::new(self)
     }
 }