1#![no_std]
46#![warn(missing_docs)]
47#![warn(clippy::missing_docs_in_private_items)]
48
49const VERTICAL_MAX: usize = u8::MAX as usize;
52const HORIZONTAL_MAX: usize = u8::MAX as usize;
55
56#[derive(Copy, Clone, Debug, PartialEq)]
62#[cfg(not(feature = "dead-alive-only"))]
63pub enum CellState {
64 Dummy,
65}
66
67#[derive(Copy, Clone, Debug, PartialEq)]
74#[cfg(feature = "dead-alive-only")]
75pub enum CellState {
76 Dead,
78 Alive,
80}
81
82impl CellState {
83 #[cfg(feature = "dead-alive-into-bool")]
84 pub fn into_bool(self) -> bool {
89 if self == CellState::Dead {
90 return false;
91 }
92 true
93 }
94}
95
96#[cfg(feature = "dead-alive-u8-utils")]
97pub fn cs8_into_u8(cs: [&CellState; 8]) -> u8 {
100 let mut rdata: u8 = 0b00000000;
101 for s in cs.iter() {
102 rdata = rdata.rotate_left(1);
103 if s == &&CellState::Alive {
104 let bit: u8 = 0b00000001;
106 rdata = rdata | bit;
107 }
108 }
109 return rdata;
110}
111
112#[cfg(feature = "dead-alive-u8-utils")]
113pub fn u8_into_cs8(bits: u8) -> [&'static CellState; 8] {
116 let mut mask: u8 = 0b00000001;
117 let mut rdata = [
118 &CellState::Dead,
119 &CellState::Dead,
120 &CellState::Dead,
121 &CellState::Dead,
122 &CellState::Dead,
123 &CellState::Dead,
124 &CellState::Dead,
125 &CellState::Dead,
126 ];
127 for i in 0..8 {
128 mask = mask.rotate_right(1);
129 let bit = mask & bits;
130 if bit == 0 {
131 rdata[i] = &CellState::Dead;
132 } else {
133 rdata[i] = &CellState::Alive;
134 }
135 }
136 return rdata;
137}
138
139#[derive(Copy, Clone, Debug)]
149pub struct Grid {
150 horizontal_size: u8,
154 vertical_size: u8,
158 cells: [[CellState; HORIZONTAL_MAX]; VERTICAL_MAX],
160 horizontal_cell_iterator_index: usize,
162 vertical_cell_iterator_index: usize,
164 horizontal_byte_iterator_index: usize,
166 vertical_byte_iterator_index: usize,
168}
169
170impl Grid {
171 pub fn new(h_size: u8, v_size: u8) -> Grid {
185 if h_size == 0 {
186 panic!("horizontal coordinate too small")
187 }
188 if v_size == 0 {
189 panic!("vertical coordinate too small")
190 }
191 if h_size as usize > HORIZONTAL_MAX {
192 panic!("horizontal coordinate too large")
193 }
194 if v_size as usize > VERTICAL_MAX {
195 panic!("vertical coordinate too large")
196 }
197
198 Grid {
199 horizontal_size: h_size,
200 vertical_size: v_size,
201 horizontal_cell_iterator_index: 0,
202 vertical_cell_iterator_index: 0,
203 horizontal_byte_iterator_index: 0,
204 vertical_byte_iterator_index: 0,
205 #[cfg(not(feature = "dead-alive-only"))]
206 cells: [[CellState::Dummy; HORIZONTAL_MAX]; VERTICAL_MAX],
207 #[cfg(feature = "dead-alive-only")]
208 cells: [[CellState::Dead; HORIZONTAL_MAX]; VERTICAL_MAX],
209 }
210 }
211
212 pub fn get_horizontal_size(&self) -> u8 {
214 self.horizontal_size
215 }
216
217 pub fn get_vertical_size(&self) -> u8 {
219 self.vertical_size
220 }
221
222 pub fn get_cellstate(&self, h: u8, v: u8) -> &CellState {
228 if h >= self.horizontal_size {
229 panic!("horizontal coordinate too large")
230 }
231 if v >= self.vertical_size {
232 panic!("vertical coordinate too large")
233 }
234 &self.cells[h as usize][v as usize]
235 }
236
237 pub fn get_cellstate_hv(&self, hv: (u8, u8)) -> &CellState {
242 self.get_cellstate(hv.0, hv.1)
243 }
244
245 pub fn set_cellstate(&mut self, h: u8, v: u8, state: CellState) {
251 if h >= self.horizontal_size {
252 panic!("horizontal coordinate too large")
253 }
254 if v >= self.vertical_size {
255 panic!("vertical coordinate too large")
256 }
257 self.cells[h as usize][v as usize] = state;
258 }
259
260 pub fn set_cellstate_hv(&mut self, hv: (u8, u8), state: CellState) {
265 self.set_cellstate(hv.0, hv.1, state)
266 }
267
268 pub fn get_north_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
275 if h >= self.horizontal_size {
276 panic!("horizontal coordinate too large")
277 }
278 if v >= self.vertical_size {
279 panic!("vertical coordinate too large")
280 }
281 if v == 0 {
282 return (h, self.vertical_size - 1);
283 }
284 (h, v - 1)
285 }
286
287 pub fn get_north_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
293 self.get_north_coordinate(hv.0, hv.1)
294 }
295
296 pub fn get_east_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
303 if h >= self.horizontal_size {
304 panic!("horizontal coordinate too large")
305 }
306 if v >= self.vertical_size {
307 panic!("vertical coordinate too large")
308 }
309 if h == self.horizontal_size - 1 {
310 return (0, v);
311 }
312 (h + 1, v)
313 }
314
315 pub fn get_east_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
321 self.get_east_coordinate(hv.0, hv.1)
322 }
323
324 pub fn get_south_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
331 if h >= self.horizontal_size {
332 panic!("horizontal coordinate too large")
333 }
334 if v >= self.vertical_size {
335 panic!("vertical coordinate too large")
336 }
337 if v == self.vertical_size - 1 {
338 return (h, 0);
339 }
340 (h, v + 1)
341 }
342
343 pub fn get_south_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
349 self.get_south_coordinate(hv.0, hv.1)
350 }
351
352 pub fn get_west_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
359 if h >= self.horizontal_size {
360 panic!("horizontal coordinate too large")
361 }
362 if v >= self.vertical_size {
363 panic!("vertical coordinate too large")
364 }
365 if h == 0 {
366 return (self.horizontal_size - 1, v);
367 }
368 (h - 1, v)
369 }
370
371 pub fn get_west_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
377 self.get_west_coordinate(hv.0, hv.1)
378 }
379
380 pub fn get_northeast_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
387 self.get_north_coordinate_hv(self.get_east_coordinate(h, v))
388 }
389
390 pub fn get_northeast_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
396 self.get_north_coordinate_hv(self.get_east_coordinate(hv.0, hv.1))
397 }
398
399 pub fn get_southeast_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
406 self.get_south_coordinate_hv(self.get_east_coordinate(h, v))
407 }
408
409 pub fn get_southeast_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
415 self.get_south_coordinate_hv(self.get_east_coordinate(hv.0, hv.1))
416 }
417
418 pub fn get_southwest_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
425 self.get_south_coordinate_hv(self.get_west_coordinate(h, v))
426 }
427
428 pub fn get_southwest_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
434 self.get_south_coordinate_hv(self.get_west_coordinate(hv.0, hv.1))
435 }
436
437 pub fn get_northwest_coordinate(&self, h: u8, v: u8) -> (u8, u8) {
444 self.get_north_coordinate_hv(self.get_west_coordinate(h, v))
445 }
446
447 pub fn get_northwest_coordinate_hv(&self, hv: (u8, u8)) -> (u8, u8) {
453 self.get_north_coordinate_hv(self.get_west_coordinate(hv.0, hv.1))
454 }
455
456 #[cfg(feature = "dead-alive-only")]
460 pub fn next_byte(&mut self) -> Option<u8> {
461 let mut rbyte = 0x00u8; for offset in 0..8 as u8 {
465 if self.horizontal_byte_iterator_index >= self.horizontal_size as usize {
466 self.vertical_byte_iterator_index += 1;
469 self.horizontal_byte_iterator_index = 0;
471 }
472 if self.vertical_byte_iterator_index >= self.vertical_size as usize {
473 return None;
474 }
475
476 match self.get_cellstate(
477 self.horizontal_byte_iterator_index as u8,
478 self.vertical_byte_iterator_index as u8,
479 ) {
480 CellState::Alive => {
481 rbyte = rbyte | (0x80u8 >> offset);
483 }
484 CellState::Dead => {}
485 }
486 self.horizontal_byte_iterator_index += 1;
487 }
488 Some(rbyte)
489 }
490}
491
492impl Iterator for Grid {
493 type Item = CellState;
494
495 fn next(&mut self) -> Option<CellState> {
499 if self.horizontal_cell_iterator_index >= self.horizontal_size as usize {
501 self.vertical_cell_iterator_index += 1;
503 self.horizontal_cell_iterator_index = 0;
505 }
506 if self.vertical_cell_iterator_index >= self.vertical_size as usize {
508 return None;
510 }
511
512 let rdata = Some(*self.get_cellstate(
514 self.horizontal_cell_iterator_index as u8,
515 self.vertical_cell_iterator_index as u8,
516 ));
517 self.horizontal_cell_iterator_index += 1;
519
520 rdata
521 }
522}
523
524#[derive(Copy, Clone)]
527pub struct Universe {
528 pub grid: Grid,
530 shadow: Grid,
532 automaton: fn(u8, u8, &Grid) -> CellState,
534}
535
536impl Universe {
537 pub fn new(h_size: u8, v_size: u8, rules: fn(u8, u8, &Grid) -> CellState) -> Universe {
544 Universe {
545 grid: Grid::new(h_size, v_size),
546 shadow: Grid::new(h_size, v_size),
547 automaton: rules,
548 }
549 }
550
551 pub fn update(&mut self) {
553 for h in 0..self.grid.horizontal_size {
556 for v in 0..self.grid.vertical_size {
557 let state = (self.automaton)(h, v, &self.grid);
558 self.shadow.set_cellstate(h, v, state);
559 }
560 }
561
562 for h in 0..self.grid.horizontal_size {
565 for v in 0..self.grid.vertical_size {
566 let state = self.shadow.get_cellstate(h, v);
567 self.grid.set_cellstate(h, v, *state); }
569 }
570 }
571}
572
573#[cfg(test)]
574mod tests {
575 use super::*;
576
577 #[test]
578 fn grid_new() {
580 let g = Grid::new(5, 23);
581 assert_eq!(g.horizontal_size, 5);
582 assert_eq!(g.vertical_size, 23);
583 }
584
585 #[test]
586 #[should_panic]
587 fn grid_new_too_small() {
588 let _ = Grid::new(0, 1);
589 let _ = Grid::new(1, 0);
590 }
591
592 #[test]
593 fn grid_get_cellstate() {
595 let g = Grid::new(3, 17);
596 let mut c = g.get_cellstate(1, 8);
597 #[cfg(not(feature = "dead-alive-only"))]
598 assert_eq!(c, &CellState::Dummy);
599 #[cfg(feature = "dead-alive-only")]
600 assert_eq!(c, &CellState::Dead);
601
602 c = g.get_cellstate_hv((1, 2));
604 #[cfg(not(feature = "dead-alive-only"))]
605 assert_eq!(c, &CellState::Dummy);
606 #[cfg(feature = "dead-alive-only")]
607 assert_eq!(c, &CellState::Dead);
608 }
609
610 #[test]
611 #[should_panic]
612 fn grid_get_cell_v_too_large() {
613 let g = Grid::new(3, 17);
614 let _c = g.get_cellstate(1, 17);
615 }
616
617 #[test]
618 #[should_panic]
619 fn grid_get_cell_h_too_large() {
620 let g = Grid::new(3, 1);
621 let _c = g.get_cellstate(3, 0);
622 }
623
624 #[test]
625 fn grid_set_cellstate() {
627 let mut g = Grid::new(3, 17);
628 #[cfg(feature = "dead-alive-only")]
629 g.set_cellstate(1, 8, CellState::Alive);
630 let mut c = g.get_cellstate(1, 8);
631 #[cfg(feature = "dead-alive-only")]
632 assert_eq!(c, &CellState::Alive);
633
634 #[cfg(feature = "dead-alive-only")]
636 g.set_cellstate_hv((2, 5), CellState::Alive);
637 c = g.get_cellstate(2, 5);
638 #[cfg(feature = "dead-alive-only")]
639 assert_eq!(c, &CellState::Alive);
640 }
641
642 #[test]
643 #[should_panic]
644 fn grid_set_cell_v_too_large() {
645 let mut g = Grid::new(3, 17);
646 #[cfg(not(feature = "dead-alive-only"))]
647 g.set_cellstate(1, 17, CellState::Dummy);
648 #[cfg(feature = "dead-alive-only")]
649 g.set_cellstate(1, 17, CellState::Alive);
650 }
651
652 #[test]
653 #[should_panic]
654 fn grid_set_cell_h_too_large() {
655 let mut g = Grid::new(3, 1);
656 #[cfg(not(feature = "dead-alive-only"))]
657 g.set_cellstate(3, 0, CellState::Dummy);
658 #[cfg(feature = "dead-alive-only")]
659 g.set_cellstate(3, 0, CellState::Alive);
660 }
661
662 #[test]
663 fn grid_get_north_coordinate() {
664 let g = Grid::new(3, 4);
665 let mut result = g.get_north_coordinate(1, 2);
666 assert_eq!(result.0, 1);
667 assert_eq!(result.1, 1);
668
669 result = g.get_north_coordinate(2, 0);
670 assert_eq!(result.0, 2);
671 assert_eq!(result.1, 3);
672 }
673
674 #[test]
675 #[should_panic]
676 fn grid_get_north_coordinate_v_too_large() {
677 let g = Grid::new(1, 4);
678 let _ = g.get_north_coordinate(0, 4);
679 }
680
681 #[test]
682 #[should_panic]
683 fn grid_get_north_coordinate_h_too_large() {
684 let g = Grid::new(1, 4);
685 let _ = g.get_north_coordinate(1, 2);
686 }
687
688 #[test]
689 fn grid_get_south_coordinate() {
690 let g = Grid::new(3, 4);
691 let mut result = g.get_south_coordinate(1, 2);
692 assert_eq!(result.0, 1);
693 assert_eq!(result.1, 3);
694
695 result = g.get_south_coordinate(2, 0);
696 assert_eq!(result.0, 2);
697 assert_eq!(result.1, 1);
698 }
699
700 #[test]
701 #[should_panic]
702 fn grid_get_south_coordinate_v_too_large() {
703 let g = Grid::new(1, 4);
704 let _ = g.get_south_coordinate(0, 4);
705 }
706
707 #[test]
708 #[should_panic]
709 fn grid_get_south_coordinate_h_too_large() {
710 let g = Grid::new(1, 4);
711 let _ = g.get_south_coordinate(1, 2);
712 }
713
714 #[test]
715 fn grid_get_west_coordinate() {
716 let g = Grid::new(3, 4);
717 let mut result = g.get_west_coordinate(1, 2);
718 assert_eq!(result.0, 0);
719 assert_eq!(result.1, 2);
720
721 result = g.get_west_coordinate(0, 2);
722 assert_eq!(result.0, 2);
723 assert_eq!(result.1, 2);
724 }
725
726 #[test]
727 #[should_panic]
728 fn grid_get_west_coordinate_v_too_large() {
729 let g = Grid::new(1, 4);
730 let _ = g.get_west_coordinate(0, 4);
731 }
732
733 #[test]
734 #[should_panic]
735 fn grid_get_west_coordinate_h_too_large() {
736 let g = Grid::new(1, 4);
737 let _ = g.get_west_coordinate(1, 2);
738 }
739
740 #[test]
741 fn grid_get_northeast_coordinate() {
742 let g = Grid::new(3, 4);
743 let mut result = g.get_northeast_coordinate(1, 2);
744 assert_eq!(result.0, 2);
745 assert_eq!(result.1, 1);
746
747 result = g.get_northeast_coordinate(2, 0);
748 assert_eq!(result.0, 0);
749 assert_eq!(result.1, 3);
750 }
751
752 #[test]
753 #[should_panic]
754 fn grid_get_northeast_coordinate_v_too_large() {
755 let g = Grid::new(1, 4);
756 let _ = g.get_northeast_coordinate(0, 4);
757 }
758
759 #[test]
760 #[should_panic]
761 fn grid_get_northeast_coordinate_h_too_large() {
762 let g = Grid::new(1, 4);
763 let _ = g.get_northeast_coordinate(1, 2);
764 }
765
766 #[test]
767 fn grid_get_southeast_coordinate() {
768 let g = Grid::new(3, 4);
769 let mut result = g.get_southeast_coordinate(1, 2);
770 assert_eq!(result.0, 2);
771 assert_eq!(result.1, 3);
772
773 result = g.get_southeast_coordinate(2, 0);
774 assert_eq!(result.0, 0);
775 assert_eq!(result.1, 1);
776 }
777
778 #[test]
779 #[should_panic]
780 fn grid_get_southeast_coordinate_v_too_large() {
781 let g = Grid::new(1, 4);
782 let _ = g.get_southeast_coordinate(0, 4);
783 }
784
785 #[test]
786 #[should_panic]
787 fn grid_get_southeast_coordinate_h_too_large() {
788 let g = Grid::new(1, 4);
789 let _ = g.get_southeast_coordinate(1, 2);
790 }
791
792 #[test]
793 fn grid_get_southwest_coordinate() {
794 let g = Grid::new(3, 4);
795 let mut result = g.get_southwest_coordinate(1, 2);
796 assert_eq!(result.0, 0);
797 assert_eq!(result.1, 3);
798
799 result = g.get_southwest_coordinate(0, 0);
800 assert_eq!(result.0, 2);
801 assert_eq!(result.1, 1);
802 }
803
804 #[test]
805 #[should_panic]
806 fn grid_get_southwest_coordinate_v_too_large() {
807 let g = Grid::new(1, 4);
808 let _ = g.get_southwest_coordinate(0, 4);
809 }
810
811 #[test]
812 #[should_panic]
813 fn grid_get_southwest_coordinate_h_too_large() {
814 let g = Grid::new(1, 4);
815 let _ = g.get_southwest_coordinate(1, 2);
816 }
817
818 #[test]
819 fn grid_get_northwest_coordinate() {
820 let g = Grid::new(3, 4);
821 let mut result = g.get_northwest_coordinate(1, 2);
822 assert_eq!(result.0, 0);
823 assert_eq!(result.1, 1);
824
825 result = g.get_northwest_coordinate(0, 0);
826 assert_eq!(result.0, 2);
827 assert_eq!(result.1, 3);
828 }
829
830 #[test]
831 #[should_panic]
832 fn grid_get_northwest_coordinate_v_too_large() {
833 let g = Grid::new(1, 4);
834 let _ = g.get_northwest_coordinate(0, 4);
835 }
836
837 #[test]
838 #[should_panic]
839 fn grid_get_northwest_coordinate_h_too_large() {
840 let g = Grid::new(1, 4);
841 let _ = g.get_northwest_coordinate(1, 2);
842 }
843
844 #[test]
845 fn grid_next_byte() {
846 let mut g = Grid::new(8, 2);
849 g.set_cellstate(0, 0, CellState::Dead);
850 g.set_cellstate(1, 0, CellState::Alive);
851 g.set_cellstate(2, 0, CellState::Dead);
852 g.set_cellstate(3, 0, CellState::Dead);
853 g.set_cellstate(4, 0, CellState::Dead);
854 g.set_cellstate(5, 0, CellState::Alive);
855 g.set_cellstate(6, 0, CellState::Alive);
856 g.set_cellstate(7, 0, CellState::Alive);
857 g.set_cellstate(0, 1, CellState::Alive);
858 g.set_cellstate(1, 1, CellState::Alive);
859 g.set_cellstate(2, 1, CellState::Dead);
860 g.set_cellstate(3, 1, CellState::Dead);
861 g.set_cellstate(4, 1, CellState::Alive);
862 g.set_cellstate(5, 1, CellState::Dead);
863 g.set_cellstate(6, 1, CellState::Alive);
864 g.set_cellstate(7, 1, CellState::Dead);
865
866 assert_eq!(Some(0b01000111), g.next_byte());
867 assert_eq!(Some(0b11001010), g.next_byte());
868 assert_eq!(None, g.next_byte());
869 assert_eq!(None, g.next_byte());
870 }
871 #[test]
872 fn grid_next() {
873 let mut g = Grid::new(3, 2);
877 g.set_cellstate(0, 0, CellState::Dead);
878 g.set_cellstate(1, 0, CellState::Dead);
879 g.set_cellstate(2, 0, CellState::Alive);
880 g.set_cellstate(0, 1, CellState::Dead);
881 g.set_cellstate(1, 1, CellState::Alive);
882 g.set_cellstate(2, 1, CellState::Dead);
883
884 assert_eq!(Some(CellState::Dead), g.next());
885 assert_eq!(Some(CellState::Dead), g.next());
886 assert_eq!(Some(CellState::Alive), g.next());
887 assert_eq!(Some(CellState::Dead), g.next());
888 assert_eq!(Some(CellState::Alive), g.next());
889 assert_eq!(Some(CellState::Dead), g.next());
890 assert_eq!(None, g.next());
891 assert_eq!(None, g.next());
892 }
893
894 #[test]
895 fn universe_update_on_grid() {
896 fn identity(h: u8, v: u8, g: &Grid) -> CellState {
897 *g.get_cellstate(h, v)
898 }
899 let mut u1 = Universe::new(4, 6, identity);
900 u1.update();
901 for h in 0..4u8 {
902 for v in 0..6u8 {
903 let cs = u1.grid.get_cellstate(h, v);
904 #[cfg(not(feature = "dead-alive-only"))]
905 assert_eq!(cs, &CellState::Dummy);
906 #[cfg(feature = "dead-alive-only")]
907 assert_eq!(cs, &CellState::Dead);
908 }
909 }
910
911 fn inversion(h: u8, v: u8, g: &Grid) -> CellState {
912 match g.get_cellstate(h, v) {
913 &CellState::Alive => CellState::Dead,
914 &CellState::Dead => CellState::Alive,
915 }
916 }
917
918 let mut u2 = Universe::new(4, 6, inversion);
919 u2.update();
920 for h in 0..4u8 {
921 for v in 0..6u8 {
922 let cs = u2.grid.get_cellstate(h, v);
923 assert_eq!(cs, &CellState::Alive);
924 }
925 }
926 }
927
928 #[test]
929 #[cfg(feature = "dead-alive-only")]
930 fn universe_automaton() {
931 fn inversion(h: u8, v: u8, g: &Grid) -> CellState {
932 match g.get_cellstate(h, v) {
933 &CellState::Alive => CellState::Dead,
934 &CellState::Dead => CellState::Alive,
935 }
936 }
937
938 let u = Universe::new(1, 1, inversion);
939 assert_eq!(u.grid.get_cellstate(0, 0), &CellState::Dead);
940
941 let state = (u.automaton)(0, 0, &u.grid);
942 assert_eq!(state, CellState::Alive);
943 }
944
945 #[test]
946 #[cfg(feature = "dead-alive-only")]
947 fn universe_update_one_cell_inversion() {
948 fn inversion(h: u8, v: u8, g: &Grid) -> CellState {
949 match g.get_cellstate(h, v) {
950 &CellState::Alive => CellState::Dead,
951 &CellState::Dead => CellState::Alive,
952 }
953 }
954
955 let mut u = Universe::new(1, 1, inversion);
956 assert_eq!(u.grid.get_cellstate(0, 0), &CellState::Dead);
957
958 u.grid.set_cellstate(0, 0, CellState::Alive);
960 assert_eq!(u.grid.get_cellstate(0, 0), &CellState::Alive);
961
962 u.update(); assert_eq!(u.grid.get_cellstate(0, 0), &CellState::Dead); }
968
969 #[test]
973 #[cfg(feature = "dead-alive-only")]
974 fn universe_update_rule30() {
975 fn rule30(h: u8, v: u8, g: &Grid) -> CellState {
976 let left = g.get_west_coordinate(h, v);
977 let right = g.get_east_coordinate(h, v);
978 let state = (
979 g.get_cellstate_hv(left),
980 g.get_cellstate(h, v),
981 g.get_cellstate_hv(right),
982 );
983 return match state {
984 (CellState::Alive, CellState::Alive, CellState::Alive) => CellState::Dead,
985 (CellState::Alive, CellState::Alive, CellState::Dead) => CellState::Dead,
986 (CellState::Alive, CellState::Dead, CellState::Alive) => CellState::Dead,
987 (CellState::Alive, CellState::Dead, CellState::Dead) => CellState::Alive,
988 (CellState::Dead, CellState::Alive, CellState::Alive) => CellState::Alive,
989 (CellState::Dead, CellState::Alive, CellState::Dead) => CellState::Alive,
990 (CellState::Dead, CellState::Dead, CellState::Alive) => CellState::Alive,
991 (CellState::Dead, CellState::Dead, CellState::Dead) => CellState::Dead,
992 };
993 }
994
995 let mut u1 = Universe::new(3, 1, rule30);
997 u1.update();
998 for h in 0..2u8 {
999 let cs = u1.grid.get_cellstate(h, 0);
1000 assert_eq!(cs, &CellState::Dead)
1001 }
1002
1003 let mut u2 = Universe::new(3, 1, rule30);
1005 u2.grid.set_cellstate(1, 0, CellState::Alive);
1006 assert_eq!(u2.grid.get_cellstate(0, 0), &CellState::Dead);
1008 assert_eq!(u2.grid.get_cellstate(1, 0), &CellState::Alive);
1009 assert_eq!(u2.grid.get_cellstate(2, 0), &CellState::Dead);
1010
1011 assert_eq!((1, 0), u2.grid.get_east_coordinate(0, 0));
1013 assert_eq!((2, 0), u2.grid.get_east_coordinate(1, 0));
1014 assert_eq!((0, 0), u2.grid.get_east_coordinate(2, 0));
1015 assert_eq!((2, 0), u2.grid.get_west_coordinate(0, 0));
1016 assert_eq!((0, 0), u2.grid.get_west_coordinate(1, 0));
1017 assert_eq!((1, 0), u2.grid.get_west_coordinate(2, 0));
1018
1019 assert_eq!(CellState::Alive, rule30(0, 0, &u2.grid));
1021 assert_eq!(CellState::Alive, rule30(1, 0, &u2.grid));
1022 assert_eq!(CellState::Alive, rule30(2, 0, &u2.grid));
1023
1024 u2.update();
1026
1027 assert_eq!(u2.shadow.get_cellstate(0, 0), &CellState::Alive);
1029 assert_eq!(u2.shadow.get_cellstate(1, 0), &CellState::Alive);
1030 assert_eq!(u2.shadow.get_cellstate(2, 0), &CellState::Alive);
1031
1032 assert_eq!(u2.grid.get_cellstate(0, 0), &CellState::Alive);
1034 assert_eq!(u2.grid.get_cellstate(1, 0), &CellState::Alive);
1035 assert_eq!(u2.grid.get_cellstate(2, 0), &CellState::Alive);
1036
1037 u2.update();
1039 assert_eq!(u2.grid.get_cellstate(0, 0), &CellState::Dead);
1040 assert_eq!(u2.grid.get_cellstate(1, 0), &CellState::Dead);
1041 assert_eq!(u2.grid.get_cellstate(2, 0), &CellState::Dead);
1042 }
1043
1044 #[test]
1045 #[cfg(feature = "dead-alive-into-bool")]
1046 fn cellstate_into_bool() {
1047 let mut cs = CellState::Dead;
1048 assert_eq!(cs.into_bool(), false);
1049 cs = CellState::Alive;
1050 assert_eq!(cs.into_bool(), true);
1051 }
1052
1053 #[test]
1054 #[cfg(feature = "dead-alive-u8-utils")]
1055 fn util_cs8_into_u8() {
1056 let mut group = [&CellState::Dead; 8];
1057 let mut result = cs8_into_u8(group);
1058 assert_eq!(result, 0b00000000);
1059
1060 group[7] = &CellState::Alive;
1061 result = cs8_into_u8(group);
1062 assert_eq!(result, 0b00000001);
1063
1064 group[0] = &CellState::Alive;
1065 result = cs8_into_u8(group);
1066 assert_eq!(result, 0b10000001);
1067
1068 group[0] = &CellState::Alive;
1069 group[3] = &CellState::Alive;
1070 group[7] = &CellState::Dead;
1071 result = cs8_into_u8(group);
1072 assert_eq!(result, 0b10010000);
1073 }
1074
1075 #[test]
1076 #[cfg(feature = "dead-alive-u8-utils")]
1077 fn util_u8_into_cs8() {
1078 let mut expectation = [&CellState::Dead; 8];
1080 let mut result = u8_into_cs8(0);
1081 assert_eq!(result, expectation);
1082
1083 expectation[7] = &CellState::Alive;
1084 result = u8_into_cs8(1);
1085 assert_eq!(result, expectation);
1086
1087 expectation[0] = &CellState::Alive;
1088 result = u8_into_cs8(129);
1089 assert_eq!(result, expectation);
1090 }
1091}