half_matrix/lib.rs
1//! Half matrix storage, Row major
2//! ```ignore
3//! ABCD
4//! A-
5//! B--
6//! C---
7//! D----
8//! ```
9//!
10//! In memory representation:
11//! ```ignore
12//! -|--|---|----
13//! ```
14//!
15//! Indexing starts at 0.
16//! ```ignore
17//! ABCD
18//! 0123
19//! ```
20//!
21//! Row Major means that the first parameter of the methods is the Y axis in the matrix, and the second is the X axis.
22//!
23//! As shown by the matrix, the row value is required to be bigger or equal to the column value.
24//!
25//! ### Example
26//! Parameters: (3, 0) = (D, A)
27//!
28//! ```ignore
29//! ABCD
30//! A-
31//! B--
32//! C---
33//! DX---
34//! ```
35//!
36
37use hibitset::BitSet;
38
39/// A matrix where only half of it is stored. See the lib documentation for more details.
40#[derive(Debug, Clone)]
41pub struct HalfMatrix {
42 size: u32,
43 index_size: u32,
44 collision_matrix: BitSet,
45}
46
47impl HalfMatrix {
48 /// Creates a new half matrix of the given size.
49 /// This value represents the maximum number of indices you can have for both sides.
50 /// ABCD size = 4.
51 pub fn new(size: u32) -> Self {
52 if size > 5792 {
53 panic!("Size of HalfMatrix too big! Maximum size is 5792 and requested size is {}.", size);
54 }
55 let index_size = (size * (size + 1)) / 2;
56 HalfMatrix {
57 size,
58 index_size,
59 collision_matrix: BitSet::with_capacity(index_size),
60 }
61 }
62
63 /// Returns the size of one side of the matrix.
64 pub fn size(&self) -> u32 {
65 self.size
66 }
67
68 /// Enables the boolean for the position (row, column).
69 pub fn enable(&mut self, row: u32, column: u32) {
70 self.collision_matrix.add(self.index_of(row, column));
71 }
72
73 /// Disables the boolean for the position (row, column).
74 pub fn disable(&mut self, row: u32, column: u32) {
75 self.collision_matrix.remove(self.index_of(row, column));
76 }
77
78 /// Returns the boolean for the position (row, column).
79 pub fn contains(&self, row: u32, column: u32) -> bool {
80 self.collision_matrix.contains(self.index_of(row, column))
81 }
82
83 /// Gives the internal memory index of the bitset for the given (row, column) values.
84 /// The internal indexing starts at 0. This means that index_of(0,0) = 0. That is the position of (A, A).
85 /// Row is required to be bigger or equal to column.
86 pub(crate) fn index_of(&self, row: u32, column: u32) -> u32 {
87 // If you entered the indices in the wrong orther, I'll fix them for you. ;)
88 let (a, b) = if row >= column {
89 (row, column)
90 } else {
91 (column, row)
92 };
93
94 let row_sum = (a * (a + 1)) / 2;
95 let idx = row_sum + b;
96
97 assert!(idx < self.index_size);
98
99 idx
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use crate::*;
106
107 #[test]
108 fn index_calculation() {
109 // 4x4
110 // C,C (2,2)
111 // Expected: 5
112 let m = HalfMatrix::new(4);
113 assert_eq!(m.index_of(2,2), 5);
114 }
115
116 #[should_panic]
117 #[test]
118 fn index_of_fail() {
119 // 4x4
120 // C,C (2,2)
121 // Expected: 5
122 let m = HalfMatrix::new(1);
123 m.index_of(0, 1);
124 }
125
126 #[test]
127 fn index_calculation2() {
128 // 4x4
129 // D,C (3,2)
130 // Expected: 9
131 let m = HalfMatrix::new(4);
132 assert_eq!(m.index_of(3,2), 8);
133 }
134
135 #[test]
136 fn max_size_okay() {
137 let size = 5792;
138 HalfMatrix::new(size);
139 }
140
141 #[test]
142 #[should_panic]
143 fn max_size_too_big() {
144 let size = 5793;
145 HalfMatrix::new(size);
146 }
147
148 #[test]
149 fn enable() {
150 // 3x3
151 //
152 // 012
153 //
154 // 2 oxo
155 // 1 xx
156 // 0 o
157
158 let mut m = HalfMatrix::new(3);
159 m.enable(2, 0);
160 m.enable(2, 2);
161 m.enable(0, 0);
162
163 assert!(m.contains(2,0));
164 assert!(m.contains(2,2));
165 assert!(m.contains(0,0));
166
167 assert!(!m.contains(1,0));
168 assert!(!m.contains(1,1));
169 assert!(!m.contains(2,1));
170 }
171
172 #[test]
173 fn out_of_range_swap() {
174 let m = HalfMatrix::new(3);
175 m.contains(0,1);
176 }
177}