1use std::borrow::Borrow;
2use std::collections::HashMap;
3use std::rc::{Rc};
4use std::cell::{RefCell};
5use smallvec::SmallVec;
6use num::{Bounded, Zero};
7use serde::{Deserialize, Serialize};
8use crate::adjacency::{AdjacencyGenerator};
9use crate::sampler::{DistributionKey, MultinomialDistribution};
10use crate::map2dnode::{Map2DNode, MapNodeState, ThreadsafeNodeRef};
11use crate::position::{MapPosition};
12
13#[derive(Serialize, Deserialize, Clone)]
14pub struct Map2D<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> {
15 pub tiles: Vec<ThreadsafeNodeRef<AG, K, MP>>,
16 position_index: HashMap<MP, ThreadsafeNodeRef<AG, K, MP>>,
17 pub undecided_tiles: HashMap<MP, ThreadsafeNodeRef<AG, K, MP>>,
18 pub(crate) min_pos: MP,
19 pub(crate) max_pos: MP,
20}
21
22impl<AG: AdjacencyGenerator<2, Input = MP>, K: DistributionKey, MP: MapPosition<2>> Map2D<AG, K, MP> {
23 pub fn from_tiles<I: IntoIterator<Item=Map2DNode<AG, K, MP>>>(tiles: I) -> Map2D<AG, K, MP> {
24 let iterator = tiles.into_iter();
25 let size_estimate = iterator.size_hint().0;
26
27 let mut tile_vec: Vec<ThreadsafeNodeRef<AG, K, MP>> = Vec::with_capacity(size_estimate);
28 let mut position_hashmap: HashMap<MP, ThreadsafeNodeRef<AG, K, MP>> = HashMap::with_capacity(size_estimate);
29 let mut undecided_hashmap: HashMap<MP, ThreadsafeNodeRef<AG, K, MP>> = HashMap::with_capacity(size_estimate);
30 let mut minx = None;
31 let mut miny = None;
32 let mut maxx = None;
33 let mut maxy = None;
34
35 for tile in iterator {
36 let cast_tile: Map2DNode<AG, K, MP> = tile;
37 let tile_pos = cast_tile.position.get_dims();
38
39 let tile_pos_x = tile_pos.get(0).unwrap().to_owned();
40 let tile_pos_y = tile_pos.get(1).unwrap().to_owned();
41
42 let tile_arc = Rc::new(RefCell::new(cast_tile));
43 let tile_arc_reader = tile_arc.try_borrow().unwrap();
44 let tile_pos = tile_arc_reader.position;
45
46 if tile_pos_x < minx.unwrap_or(MP::Key::max_value()) { minx = Some(tile_pos_x)};
47 if tile_pos_y < miny.unwrap_or(MP::Key::max_value()) { miny = Some(tile_pos_y)};
48 if tile_pos_x > maxx.unwrap_or(MP::Key::min_value()) { maxx = Some(tile_pos_x)};
49 if tile_pos_y > maxy.unwrap_or(MP::Key::min_value()) { maxy = Some(tile_pos_y)};
50
51 tile_vec.push(tile_arc.to_owned());
52 position_hashmap.insert(tile_pos, tile_arc.to_owned());
53
54 if !tile_arc_reader.state.is_assigned() {
55 undecided_hashmap.insert(tile_pos, tile_arc.to_owned());
56 }
57 }
58
59 Self {
60 tiles: tile_vec,
61 position_index: position_hashmap,
62 undecided_tiles: undecided_hashmap,
63 min_pos: MP::from_dims([
64 minx.unwrap_or(maxx.unwrap_or(MP::Key::zero())).to_owned(),
65 miny.unwrap_or(maxy.unwrap_or(MP::Key::zero())).to_owned()
66 ]),
67 max_pos: MP::from_dims([
68 maxx.unwrap_or(minx.unwrap_or(MP::Key::zero())).to_owned(),
69 maxy.unwrap_or(miny.unwrap_or(MP::Key::zero())).to_owned()
70 ])
71 }
72 }
73
74 pub fn get<BMP: Borrow<MP>>(&self, key: BMP) -> Option<&ThreadsafeNodeRef<AG, K, MP>> {
75 self.position_index.get(key.borrow())
76 }
77
78 pub fn finalize_tile<'n>(&'n mut self, tile: &'n ThreadsafeNodeRef<AG, K, MP>, assignment: K) -> Option<&ThreadsafeNodeRef<AG, K, MP>> {
79 let tile_writer = tile.try_borrow_mut();
80 match tile_writer {
81 Ok(mut writeable) => {
82 writeable.state = MapNodeState::finalized(assignment);
83 let removed = self.undecided_tiles.remove(&writeable.position);
84 match removed {
85 Some(_) => Some(tile),
86 None => None
87 }
88 },
89 Err(_) => None
90 }
91 }
92
93 pub fn unassign_tile<'n>(&'n mut self, tile: &'n ThreadsafeNodeRef<AG, K, MP>, distribution: &'n MultinomialDistribution<K>) -> Option<&ThreadsafeNodeRef<AG, K, MP>> {
94 let tile_writer = tile.try_borrow_mut();
95
96 match tile_writer {
97 Ok(mut writeable) => {
98 writeable.state = MapNodeState::Undecided(distribution.to_owned());
99 let inserted = self.undecided_tiles.insert(writeable.position, tile.to_owned());
100 match inserted {
101 Some(_) => Some(tile),
102 None => panic!("Failed to insert a tile into the undecided tiles map!")
103 }
104 },
105 Err(_) => panic!("Failed to obtain a write lock on tile to un-assign!")
106 }
107 }
108
109 pub fn unassign_tiles<'n, I: IntoIterator<Item=&'n ThreadsafeNodeRef<AG, K, MP>>>(&'n mut self, tiles: I, distribution: MultinomialDistribution<K>) -> Option<()> {
110 let tile_iter = tiles.into_iter();
111 tile_iter.for_each(|tile| {
112 self.unassign_tile(tile, &distribution);
113 });
114 Some(())
115 }
116}
117
118impl<K: DistributionKey, MP: MapPosition<2>, RMP: Borrow<MP> + From<MP>, AG: AdjacencyGenerator<2, Input=RMP>> Map2D<AG, K, MP> {
119 pub fn adjacent_from_pos(&self, pos: RMP) -> SmallVec<[ThreadsafeNodeRef<AG, K, MP>; 8]> {
122 let adjacents: AG::Output = MapPosition::adjacents::<RMP, AG>(pos);
123
124 let result = adjacents
125 .into_iter()
126 .filter_map(
127 |cand| {
128 let rcand = cand.borrow();
129 self.position_index
130 .get(rcand)
131 .map(|x| x.to_owned())
132 }
133 );
134
135 result.collect()
136 }
137
138 pub fn adjacent<NR: Borrow<Map2DNode<AG, K, MP>>>(&self, node: NR) -> SmallVec<[ThreadsafeNodeRef<AG, K, MP>; 8]> {
139 let pos = node.borrow().position;
140 let borrowed_pos: RMP = pos.into();
141
142 self.adjacent_from_pos(borrowed_pos)
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use crate::adjacency::CardinalAdjacencyGenerator;
149 use super::*;
150 use crate::position2d::Position2D;
151
152 #[test]
153 fn position_vector_addition_works_positives() {
154 let pos_a = Position2D { x: 5, y: 3 };
155 let pos_b = Position2D { x: 2, y: 6 };
156 let result_pos = pos_a + pos_b;
157 assert_eq!(result_pos.x, 7);
158 assert_eq!(result_pos.y, 9);
159 }
160
161 #[test]
162 fn position_vector_addition_works_one_negative() {
163 let pos_a = Position2D { x: -5, y: -3 };
164 let pos_b = Position2D { x: 2, y: 6 };
165 let result_pos = pos_a + pos_b;
166 assert_eq!(result_pos.x, -3);
167 assert_eq!(result_pos.y, 3);
168 }
169
170 #[test]
171 fn adjacents_cardinal_sane() {
172 let pos = Position2D { x: 2, y: 6 };
173 let results = Position2D::adjacents::<Position2D<i32>, CardinalAdjacencyGenerator<Position2D<i32>>>(pos);
174 assert_eq!(results[0], Position2D { x: 1i32, y: 6i32 });
175 assert_eq!(results[1], Position2D { x: 3i32, y: 6i32 });
176 assert_eq!(results[2], Position2D { x: 2i32, y: 5i32 });
177 assert_eq!(results[3], Position2D { x: 2i32, y: 7i32 });
178 }
179
180 #[test]
181 fn serde_pos() {
182 let pos = Position2D { x: 2, y: 6 };
183 let results = serde_json::to_string(&pos).unwrap();
184 assert!(results.len() > 0)
185 }
186}