1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
use crate::coord::Coord; use std::collections::HashMap; #[derive(Copy, Clone, Serialize, Deserialize, Debug)] pub enum GridType { Cardinal, Hex, Intercardinal, } impl Default for GridType { fn default() -> GridType { GridType::Cardinal } } #[derive(Clone, Default, Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Grid { pub tiles: Vec<Vec<i32>>, pub walkable_tiles: Vec<i32>, pub unstoppable_tiles: Vec<i32>, #[serde(default = "HashMap::new")] pub costs: HashMap<i32, i32>, #[serde(default = "HashMap::new")] pub extra_costs: HashMap<i32, HashMap<i32, i32>>, #[serde(default = "HashMap::new")] pub unstoppable_coords: HashMap<i32, HashMap<i32, bool>>, #[serde(default = "HashMap::new")] pub unwalkable_coords: HashMap<i32, HashMap<i32, bool>>, #[serde(default = "default_grid_type")] pub grid_type: GridType, } fn default_grid_type() -> GridType { GridType::Cardinal } impl Grid { pub fn is_cardinal(&self) -> bool { match self.grid_type { GridType::Cardinal => true, _ => false, } } pub fn is_hex(&self) -> bool { match self.grid_type { GridType::Hex => true, _ => false, } } pub fn is_intercardinal(&self) -> bool { match self.grid_type { GridType::Intercardinal => true, _ => false, } } pub fn in_grid(&self, x: i32, y: i32) -> bool { match self { _grid if (x < 0) | (y < 0) => false, grid if (y as usize) < grid.tiles.len() => (x as usize) < grid.tiles[y as usize].len(), _ => false, } } pub fn is_coord_stoppable(&self, x: i32, y: i32) -> bool { let tile = self.tiles[y as usize][x as usize]; if self.unstoppable_tiles.contains(&tile) | get_nested_bool(&self.unstoppable_coords, x, y) { false } else { self.is_coord_walkable(x, y) } } pub fn is_coord_walkable(&self, x: i32, y: i32) -> bool { if get_nested_bool(&self.unwalkable_coords, x, y) { false } else { let tile = self.tiles[y as usize][x as usize]; self.walkable_tiles.contains(&tile) } } pub fn get_coord_cost(&self, x: i32, y: i32) -> i32 { match self.get_extra_cost(x, y) { Some(extra) => extra, _ => { let tile = self.tiles[y as usize][x as usize]; match self.costs.get(&tile) { None => 1, Some(cost) => *cost, } } } } pub fn get_adjacent(&self, coord: &Coord) -> Vec<Coord> { let mut adjacent = vec![]; if self.in_grid(coord.x, coord.y - 1) { adjacent.push(Coord::new(coord.x, coord.y - 1)); } if !self.is_cardinal() & self.in_grid(coord.x + 1, coord.y - 1) { adjacent.push(Coord::new(coord.x + 1, coord.y - 1)); } if self.in_grid(coord.x + 1, coord.y) { adjacent.push(Coord::new(coord.x + 1, coord.y)); } if self.is_intercardinal() & self.in_grid(coord.x + 1, coord.y + 1) { adjacent.push(Coord::new(coord.x + 1, coord.y + 1)); } if self.in_grid(coord.x, coord.y + 1) { adjacent.push(Coord::new(coord.x, coord.y + 1)); } if !self.is_cardinal() & self.in_grid(coord.x - 1, coord.y + 1) { adjacent.push(Coord::new(coord.x - 1, coord.y + 1)); } if self.in_grid(coord.x - 1, coord.y) { adjacent.push(Coord::new(coord.x - 1, coord.y)); } if self.is_intercardinal() & self.in_grid(coord.x - 1, coord.y - 1) { adjacent.push(Coord::new(coord.x - 1, coord.y - 1)); } adjacent } fn get_extra_cost(&self, x: i32, y: i32) -> Option<i32> { match self.extra_costs.get(&y) { Some(inner_hash) => inner_hash.get(&x).cloned(), _ => None, } } } fn get_nested_bool(map: &HashMap<i32, HashMap<i32, bool>>, x: i32, y: i32) -> bool { match map.get(&y) { Some(nested) => match nested.get(&x) { Some(_) => true, _ => false, }, _ => false, } }