1#![no_std]
2#![forbid(unsafe_code)]
3#![doc = include_str!("../README.md")]
4
5#[macro_use] extern crate alloc;
6
7use core::fmt;
8use alloc::vec::Vec;
9
10use z3::{Context, Solver, SatResult};
11use z3::ast::{Ast, Bool, Int};
12
13#[derive(Clone, PartialEq, Eq)]
15pub struct Conway {
16 rows: usize,
17 cols: usize,
18 data: Vec<bool>,
19}
20impl Conway {
21 pub fn new(mut rows: usize, mut cols: usize) -> Self {
23 if rows == 0 || cols == 0 {
24 (rows, cols) = (0, 0);
25 }
26
27 Self { rows, cols, data: vec![false; rows * cols] }
28 }
29 pub fn get(&self, row: usize, col: usize) -> Result<bool, ()> {
31 if row < self.rows && col < self.cols {
32 Ok(self.data[row * self.cols + col])
33 } else {
34 Err(())
35 }
36 }
37 pub fn set(&mut self, row: usize, col: usize, value: bool) -> Result<(), ()> {
39 if row < self.rows && col < self.cols {
40 self.data[row * self.cols + col] = value;
41 Ok(())
42 } else {
43 Err(())
44 }
45 }
46 pub fn inflate(&self, padding: usize) -> Self {
48 let mut res = Self::new(self.rows + 2 * padding, self.cols + 2 * padding);
49 for row in 0..self.rows {
50 for col in 0..self.cols {
51 res.set(row + padding, col + padding, self.get(row, col).unwrap()).unwrap();
52 }
53 }
54 res
55 }
56 pub fn forward(&self, steps: usize) -> Self {
58 let mut res = self.clone();
59 for _ in 0..steps {
60 let mut counts = vec![0; res.rows * res.cols];
61 for row in 0..res.rows {
62 for col in 0..res.cols {
63 if res.data[row * res.cols + col] {
64 for c_row in row.saturating_sub(1)..(row + 2).min(res.rows) {
65 for c_col in col.saturating_sub(1)..(col + 2).min(res.cols) {
66 counts[c_row * res.cols + c_col] += 1;
67 }
68 }
69 }
70 }
71 }
72 res = Conway { rows: res.rows, cols: res.cols, data: res.data.iter().zip(counts).map(|(live, count)| (*live && count == 4) || count == 3).collect() };
73 }
74 res
75 }
76 pub fn backward(&self, steps: usize) -> Option<Self> {
81 let context = Context::new(&Default::default());
82
83 let zero = Int::from_u64(&context, 0);
84 let one = Int::from_u64(&context, 1);
85 let three = Int::from_u64(&context, 3);
86 let four = Int::from_u64(&context, 4);
87
88 let vars = {
89 let mut vars = Vec::with_capacity(self.rows * self.cols);
90 for row in 0..self.rows {
91 for col in 0..self.cols {
92 vars.push(Bool::new_const(&context, format!("d{row},{col}")));
93 }
94 }
95 vars
96 };
97
98 let mut res = vars.clone();
99 for _ in 0..steps {
100 let mut counts = vec![zero.clone(); self.rows * self.cols];
101 for row in 0..self.rows {
102 for col in 0..self.cols {
103 for c_row in row.saturating_sub(1)..(row + 2).min(self.rows) {
104 for c_col in col.saturating_sub(1)..(col + 2).min(self.cols) {
105 counts[c_row * self.cols + c_col] += res[row * self.cols + col].ite(&one, &zero);
106 }
107 }
108 }
109 }
110 res = res.iter().zip(counts).map(|(live, count)| (live & count._eq(&four) | count._eq(&three))).collect();
111 }
112
113 let s = Solver::new(&context);
114 for (res, actual) in res.iter().zip(&self.data) {
115 if *actual {
116 s.assert(res);
117 } else {
118 let res = res.not();
119 s.assert(&res);
120 }
121 }
122
123 match s.check() {
124 SatResult::Sat => {
125 let model = s.get_model().unwrap();
126 Some(Self { rows: self.rows, cols: self.cols, data: vars.iter().map(|v| model.eval(v, true).unwrap().as_bool().unwrap()).collect() })
127 }
128 SatResult::Unsat => None,
129 SatResult::Unknown => unreachable!(),
130 }
131 }
132}
133impl fmt::Debug for Conway {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 if self.rows == 0 || self.cols == 0 {
136 return f.write_str("[]");
137 }
138
139 for row in 0..self.rows {
140 for col in 0..self.cols {
141 f.write_str(if self.data[row * self.cols + col] { "■" } else { "□" })?;
142 }
143 f.write_str("\n")?;
144 }
145 Ok(())
146 }
147}