1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! A trait for `World`.
use crate::{
cells::{Coord, State, ALIVE, DEAD},
config::Config,
error::Error,
rules::Rule,
search::Status,
world::World,
};
use std::fmt::Write;
#[cfg(feature = "serialize")]
use crate::save::WorldSer;
/// A trait for `World`.
///
/// So that we can switch between different rule types using trait objects.
pub trait Search {
/// The search function.
///
/// Returns `Found` if a result is found,
/// `None` if such pattern does not exist,
/// `Searching` if the number of steps exceeds `max_step`
/// and no results are found.
fn search(&mut self, max_step: Option<u64>) -> Status;
/// Gets the state of a cell. Returns `Err(())` if there is no such cell.
fn get_cell_state(&self, coord: Coord) -> Result<Option<State>, Error>;
/// World configuration.
fn config(&self) -> &Config;
/// Whether the rule is a Generations rule.
fn is_gen_rule(&self) -> bool;
/// Whether the rule contains `B0`.
///
/// In other words, whether a cell would become `Alive` in the next
/// generation, if all its neighbors in this generation are dead.
fn is_b0_rule(&self) -> bool;
/// Number of known living cells in some generation.
///
/// For Generations rules, dying cells are not counted.
fn cell_count_gen(&self, t: isize) -> usize;
/// Minumum number of known living cells in all generation.
///
/// For Generations rules, dying cells are not counted.
fn cell_count(&self) -> usize;
/// Number of conflicts during the search.
fn conflicts(&self) -> u64;
/// Set the max cell counts.
///
/// Currently this is the only parameter that you can change
/// during the search.
fn set_max_cell_count(&mut self, max_cell_count: Option<usize>);
#[cfg(feature = "serialize")]
/// Saves the world as a `WorldSer`,
/// which can be easily serialized.
fn ser(&self) -> WorldSer;
/// Displays the whole world in some generation,
/// in a mix of [Plaintext](https://conwaylife.com/wiki/Plaintext) and
/// [RLE](https://conwaylife.com/wiki/Rle) format.
///
/// * **Dead** cells are represented by `.`;
/// * **Living** cells are represented by `o` for rules with 2 states,
/// `A` for rules with more states;
/// * **Dying** cells are represented by uppercase letters starting from `B`;
/// * **Unknown** cells are represented by `?`;
/// * Each line is ended with `$`;
/// * The whole pattern is ended with `!`.
fn rle_gen(&self, t: isize) -> String {
let mut str = String::new();
writeln!(
str,
"x = {}, y = {}, rule = {}",
self.config().width,
self.config().height,
self.config().rule_string
)
.unwrap();
for y in 0..self.config().height {
for x in 0..self.config().width {
let state = self.get_cell_state((x, y, t)).unwrap();
match state {
Some(DEAD) => str.push('.'),
Some(ALIVE) => {
if self.is_gen_rule() {
str.push('A')
} else {
str.push('o')
}
}
Some(State(i)) => str.push((b'A' + i as u8 - 1) as char),
_ => str.push('?'),
};
}
if y == self.config().height - 1 {
str.push('!')
} else {
str.push('$')
};
str.push('\n');
}
str
}
/// Displays the whole world in some generation in
/// [Plaintext](https://conwaylife.com/wiki/Plaintext) format.
///
/// * **Dead** cells are represented by `.`;
/// * **Living** and **Dying** cells are represented by `o`;
/// * **Unknown** cells are represented by `?`.
fn plaintext_gen(&self, t: isize) -> String {
let mut str = String::new();
for y in 0..self.config().height {
for x in 0..self.config().width {
let state = self.get_cell_state((x, y, t)).unwrap();
match state {
Some(DEAD) => str.push('.'),
Some(_) => str.push('o'),
None => str.push('?'),
};
}
str.push('\n');
}
str
}
}
/// The `Search` trait is implemented for every `World`.
impl<'a, R: Rule> Search for World<'a, R> {
fn search(&mut self, max_step: Option<u64>) -> Status {
self.search(max_step)
}
fn get_cell_state(&self, coord: Coord) -> Result<Option<State>, Error> {
self.get_cell_state(coord)
}
fn config(&self) -> &Config {
&self.config
}
fn is_gen_rule(&self) -> bool {
R::IS_GEN
}
fn is_b0_rule(&self) -> bool {
self.rule.has_b0()
}
fn cell_count_gen(&self, t: isize) -> usize {
self.cell_count[t as usize]
}
fn cell_count(&self) -> usize {
self.cell_count()
}
fn conflicts(&self) -> u64 {
self.conflicts
}
fn set_max_cell_count(&mut self, max_cell_count: Option<usize>) {
self.set_max_cell_count(max_cell_count)
}
#[cfg(feature = "serialize")]
fn ser(&self) -> WorldSer {
self.ser()
}
}