1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3
4use Cell::*;
5
6pub mod games;
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10pub enum Cell {
11 Unknown,
13 Player,
15 Follower,
19 Val(bool),
23}
24
25#[derive(Clone)]
27pub struct Map {
28 pub cells: [[Cell; 4]; 4],
30 pub f: fn(&mut u16),
32 pub player_pos: [usize; 2],
34}
35
36impl Map {
37 pub fn new(f: fn(&mut u16)) -> Map {
41 Map {
42 cells: [
43 [Player, Unknown, Unknown, Unknown],
44 [Unknown; 4],
45 [Unknown; 4],
46 [Unknown; 4],
47 ],
48 f,
49 player_pos: [0, 0],
50 }
51 }
52
53 pub fn has_won(&self) -> bool {
55 if let Player = self.cells[3][3] {true} else {false}
56 }
57
58 pub fn has_lost(&self) -> bool {
60 for i in 0..4 {
61 for j in 0..4 {
62 if let Player = self.cells[i][j] {return false}
63 }
64 }
65 true
66 }
67
68 pub fn information(&self) -> u8 {
70 let mut sum = 0;
71 for i in 0..4 {
72 for j in 0..4 {
73 if let Val(_) = self.cells[i][j] {sum += 1}
74 }
75 }
76 sum
77 }
78
79 pub fn followers(&self) -> u8 {
81 let mut sum = 0;
82 for i in 0..4 {
83 for j in 0..4 {
84 if let Follower = self.cells[i][j] {sum += 1}
85 }
86 }
87 sum
88 }
89
90 pub fn mov(&mut self, pos: [usize; 2]) -> bool {
93 if pos == [0, 0] {return false}
94 let information = self.information();
95
96 let old_pos = self.player_pos;
97 self.cells[self.player_pos[1]][self.player_pos[0]] = Follower;
98 self.cells[pos[1]][pos[0]] = Player;
99 self.player_pos = pos;
100
101 let mut valid = true;
102 let mut filter1: u16 = u16::MAX;
103 let mut filter2: u16 = 0;
104 'state: for s in 0..=u16::MAX {
105 for i in 0..4 {
106 for j in 0..4 {
107 let b = i * 4 + j;
108 let v = (s >> b) & 1 == 1;
109 match self.cells[i][j] {
110 Player | Follower | Unknown => {}
111 Val(a) => if v != a {continue 'state}
112 }
113 }
114 }
115
116 let b = old_pos[1] * 4 + old_pos[0];
117 let old_player_state = (s >> b) & 1 == 1;
118 let mut t = s;
119 (self.f)(&mut t);
120 let b2 = pos[1] * 4 + pos[0];
121 let new_player_state = (t >> b2) & 1 == 1;
122 if new_player_state != old_player_state {
123 valid = false;
124 break;
125 }
126 filter1 &= t;
127 filter2 |= t;
128 }
129 if !valid {
130 self.cells[self.player_pos[1]][self.player_pos[0]] = Follower;
131 }
132
133 let old_cells = self.cells.clone();
135 for i in 0..4 {
136 for j in 0..4 {
137 let b = i * 4 + j;
138 let set_to_1 = (filter1 >> b) & 1 == 1;
139 let set_to_0 = (filter2 >> b) & 1 == 0;
140 match (set_to_1, set_to_0) {
141 (true, true) | (false, false) => match self.cells[i][j] {
142 Player | Follower | Unknown => {}
143 Val(_) => self.cells[i][j] = Unknown,
144 },
145 (true, false) => self.cells[i][j] = Val(true),
146 (false, true) => self.cells[i][j] = Val(false),
147 }
148 }
149 }
150 if self.information() != information {return false}
151
152 'other_state: for s2 in 0..=u16::MAX {
155 let mut match_all = true;
156 for i in 0..4 {
157 for j in 0..4 {
158 let b = i * 4 + j;
159 let v = (s2 >> b) & 1 == 1;
160 match old_cells[i][j] {
161 Player | Follower | Unknown => {}
162 Val(a) => if v != a {match_all = false}
163 }
164 }
165 }
166 if match_all {continue 'other_state}
167
168 let mut t2 = s2;
169 (self.f)(&mut t2);
170 let mut match_all = true;
171 for i in 0..4 {
172 for j in 0..4 {
173 let b = i * 4 + j;
174 let v = (t2 >> b) & 1 == 1;
175 match self.cells[i][j] {
176 Player | Follower | Unknown => {}
177 Val(a) => if v != a {match_all = false}
178 }
179 }
180 }
181 if match_all {
182 valid = false;
183 break 'other_state;
184 }
185 }
186
187 valid
188 }
189}
190
191pub struct Game {
193 pub name: String,
195 pub f: fn(&mut u16),
197 pub config: fn(&mut Map),
199}
200
201pub fn move_bit(from: [usize; 2], to: [usize; 2], s: &mut u16) {
203 let b = from[1] * 4 + from[0];
204 let b2 = to[1] * 4 + to[0];
205 if (*s >> b) & 1 == 1 {*s |= 1 << b2} else {*s &= !(1 << b2)}
206}
207
208pub fn snake_bits(ps: &[[usize; 2]], s: &mut u16) {
210 for i in (1..ps.len()).rev() {
211 let j = i - 1;
212 move_bit(ps[j], ps[i], s);
213 }
214}
215
216pub fn swap_bits(from: [usize; 2], to: [usize; 2], s: &mut u16) {
218 let a = get_bit(from, *s);
219 set_bit(from, get_bit(to, *s), s);
220 set_bit(to, a, s);
221}
222
223pub fn toggle_bit(at: [usize; 2], s: &mut u16) {
225 set_bit(at, !get_bit(at, *s), s);
226}
227
228pub fn set_bit(a: [usize; 2], val: bool, s: &mut u16) {
230 let b = a[1] * 4 + a[0];
231 if val {*s |= 1 << b} else {*s &= !(1 << b)}
232}
233
234pub fn get_bit(a: [usize; 2], s: u16) -> bool {
236 let b = a[1] * 4 + a[0];
237 (s >> b) & 1 == 1
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 pub fn direct_win(s: &mut u16) {
246 move_bit([0, 0], [3, 3], s);
247 }
248
249 pub fn set_1_0_to_1(s: &mut u16) {
251 set_bit([1, 0], true, s);
252 }
253
254 pub fn diagonal(s: &mut u16) {
256 move_bit([2, 2], [3, 3], s);
257 move_bit([1, 1], [2, 2], s);
258 move_bit([0, 0], [1, 1], s);
259 }
260
261 pub fn anywhere(s: &mut u16) {
263 for i in 0..4 {
264 for j in 0..4 {
265 let pos = [i, j];
266 if pos == [0, 0] {continue}
267 move_bit([0, 0], pos, s);
268 }
269 }
270 }
271
272 pub fn fake_choice(s: &mut u16) {
275 move_bit([3, 0], [3, 3], s);
276 move_bit([0, 0], [3, 0], s);
277 move_bit([0, 0], [0, 3], s);
278 }
279
280 pub fn fake_choice2(s: &mut u16) {
285 if get_bit([3, 0], *s) == get_bit([0, 3], *s) {
286 move_bit([3, 0], [3, 3], s);
287 assert_eq!(get_bit([0, 3], *s), get_bit([3, 0], *s));
288 }
289 move_bit([0, 0], [3, 0], s);
290 move_bit([0, 0], [0, 3], s);
291 }
292
293 pub fn set_goal_to_zero(s: &mut u16) {
295 set_bit([3, 3], false, s);
296 }
297
298 #[test]
299 fn test_direct_win() {
300 let mut map = Map::new(direct_win);
301 assert!(!map.has_won());
302 assert!(!map.has_lost());
303
304 assert!(map.mov([3, 3]));
305 assert!(map.has_won());
306 }
307
308 #[test]
309 fn test_set_1_0_to_1() {
310 let mut map = Map::new(set_1_0_to_1);
311 assert_eq!(map.cells[0][1], Unknown);
312
313 assert!(!map.mov([1, 1]));
314 assert_eq!(map.cells[0][1], Val(true));
315 }
316
317 #[test]
318 fn test_diagonal() {
319 let mut map = Map::new(diagonal);
320 assert!(map.mov([1, 1]));
321 assert!(map.mov([2, 2]));
322 assert!(map.mov([3, 3]));
323 assert!(map.has_won());
324 }
325
326 #[test]
327 fn test_anywhere() {
328 let mut map = Map::new(anywhere);
329 assert!(map.mov([2, 3]));
330 assert!(!map.mov([3, 3]));
332 assert!(!map.has_won());
333 }
334
335 #[test]
336 fn test_fake_choice() {
337 let mut map = Map::new(fake_choice);
338 assert!(map.mov([3, 0]));
339 assert!(map.mov([3, 3]));
340
341 let mut map = Map::new(fake_choice);
342 assert!(map.mov([0, 3]));
343 assert!(!map.mov([3, 3]));
344 }
345
346 #[test]
347 fn test_fake_choice2() {
348 let mut map = Map::new(fake_choice2);
349 assert!(map.mov([3, 0]));
350 assert!(!map.mov([3, 3]));
351
352 let mut map = Map::new(fake_choice2);
353 assert!(map.mov([0, 3]));
354 assert!(!map.mov([3, 3]));
355 }
356
357 #[test]
358 fn test_set_goal_to_zero() {
359 let mut map = Map::new(set_goal_to_zero);
360 assert!(!map.mov([3, 3]));
361 assert!(map.has_lost());
362 }
363}
364