morkovmap_rc/
map2d.rs

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    // NOTE: we're using a magic maxcap, because generics are a bane of my existence
120
121    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}