76 std::cout <<
"═══════════════════════════════════════════════════════════════\n";
77 std::cout <<
" " << title <<
'\n';
78 std::cout <<
"═══════════════════════════════════════════════════════════════\n";
84 std::int64_t x_min, std::int64_t y_min,
88 const std::int64_t
w =
x_max - x_min;
89 const std::int64_t
h =
y_max - y_min;
90 std::vector<std::string>
rows(
static_cast<std::size_t
>(
h),
91 std::string(
static_cast<std::size_t
>(
w),
'.'));
92 engine.for_each_alive([&](std::int64_t x, std::int64_t
y)
95 rows[
static_cast<std::size_t
>(
y - y_min)]
96 [
static_cast<std::size_t
>(x - x_min)] =
'O';
99 for (std::int64_t i = 0; i <
w; ++i) std::cout <<
"─";
100 std::cout <<
"┐ " <<
caption <<
'\n';
101 for (
const auto &
r :
rows)
102 std::cout <<
" │" <<
r <<
"│\n";
104 for (std::int64_t i = 0; i <
w; ++i) std::cout <<
"─";
133 std::int64_t
ox = 0, std::int64_t
oy = 0)
135 static constexpr int xy[][2] = {
136 { 1, 5 }, { 1, 6 }, { 2, 5 }, { 2, 6 },
137 { 11, 5 }, { 11, 6 }, { 11, 7 }, { 12, 4 }, { 12, 8 },
138 { 13, 3 }, { 13, 9 }, { 14, 3 }, { 14, 9 },
139 { 15, 6 }, { 16, 4 }, { 16, 8 },
140 { 17, 5 }, { 17, 6 }, { 17, 7 }, { 18, 6 },
141 { 21, 3 }, { 21, 4 }, { 21, 5 },
142 { 22, 3 }, { 22, 4 }, { 22, 5 },
143 { 23, 2 }, { 23, 6 },
144 { 25, 1 }, { 25, 2 }, { 25, 6 }, { 25, 7 },
145 { 35, 3 }, { 35, 4 }, { 36, 3 }, { 36, 4 },
147 for (
const auto &p :
xy)
148 e.set_alive(
ox + p[0],
oy + p[1]);
157 print_section(
"Demo 1 — Glider: 5 cells, period 4, moves (+1,+1) per period");
164 for (
int frame = 0; frame < 5; ++frame)
167 std::cout <<
" step " << std::setw(4) << e.
generation()
169 <<
" bbox=(" <<
bb.x_min <<
',' <<
bb.y_min
170 <<
")…(" <<
bb.x_max <<
',' <<
bb.y_max <<
")\n";
182 print_section(
"Demo 2 — R-pentomino: 5 chaotic cells stabilising at step 1103");
186 std::cout <<
" Initial seed (5 cells):\n";
193 10u, 100u, 500u, 1000u, 1103u, 2000u, 5000u
197 const auto current =
static_cast<std::uint64_t
>(e.
generation());
198 if (target > current)
199 e.
run(target - current);
201 std::cout <<
" step " << std::setw(5) << e.
generation()
203 <<
" bbox=" << std::setw(4) <<
bb.width()
204 <<
" x " << std::setw(4) <<
bb.height() <<
'\n';
206 std::cout <<
" → the methuselah settles into still-lifes, blinkers and"
207 " 6 escaping gliders.\n";
216 print_section(
"Demo 3 — Gosper gun: exponential advances up to step 2²⁰");
220 std::cout <<
" Seed (36 cells, classic Gosper gun configuration):\n";
223 using clock = std::chrono::steady_clock;
224 std::cout <<
"\n Calling advance(k) for k = 4, 8, 12, 16, 20:\n";
225 std::cout <<
" k | 2^k generations | pop | cache nodes | wall time\n";
226 std::cout <<
" ----+-----------------+-----------+----------------+--------------\n";
227 for (
unsigned k : { 4u, 8u, 12u, 16u, 20u })
229 const auto t0 = clock::now();
231 const auto dt = std::chrono::duration<double, std::milli>(
232 clock::now() -
t0).count();
233 const auto stats = e.
stats();
234 std::cout <<
" " << std::setw(2) <<
k
235 <<
" | " << std::setw(15) <<
advanced
237 <<
" | " << std::setw(14) << stats.canonical_nodes
238 <<
" | " << std::fixed << std::setprecision(2)
239 << std::setw(8) << dt <<
" ms\n";
243 std::cout <<
"\n Final state: " << e.
population() <<
" alive cells across a "
244 <<
bb.width() <<
" × " <<
bb.height() <<
" bounding box.\n";
245 std::cout <<
" Generation: " << e.
generation() <<
'\n';
247 const auto stats = e.
stats();
248 std::cout <<
" Cache: " << stats.
canonical_nodes <<
" canonical nodes, "
249 << stats.result_hits <<
" result hits, "
250 << stats.result_misses <<
" result misses, "
251 << stats.result_cache_clears <<
" evictions.\n";
252 std::cout <<
" Hit ratio: " << std::fixed << std::setprecision(2)
253 << (100.0 * stats.result_hits
254 / std::max<std::size_t>(1, stats.result_hits + stats.result_misses))
255 <<
" % (high hit ratio = lots of repeated subtree work avoided)\n";
269 const std::string
serialised = src.save_rle_string(
"glider, evolved by HighLife");
270 std::cout <<
" RLE serialisation of the seed:\n";
272 std::cout << ((c ==
'\n') ?
std::string(
"\n ") :
std::string(1, c));
277 std::cout <<
"\n After parsing, dst.rule = " <<
format_rule(
dst.rule())
278 <<
" population = " <<
dst.population() <<
'\n';
286 std::cout <<
"Aleph::CA::Hashlife_Engine — guided tour\n";
287 std::cout <<
"Outer-totalistic binary cellular automata at exponential scale.\n";
294 std::cout <<
"\nDone.\n";
void print_section(const string &title)
Hashlife engine for outer-totalistic binary cellular automata.
void load_rle_string(const std::string &s)
Convenience overload that reads the pattern from a string.
BBox bbox() const
Tight bounding box of the alive cells (empty if population() == 0).
std::uint64_t run(std::uint64_t generations)
Advance by exactly generations steps.
Stats stats() const noexcept
Diagnostic counters and current root level.
void set_alive(const std::int64_t x, const std::int64_t y, const bool alive=true)
Set or clear the cell at world coordinates (x, y).
std::uint64_t advance(const unsigned k)
Advance the universe by 2^k generations.
std::int64_t generation() const noexcept
Number of generations elapsed since construction (or the last clear).
std::uint64_t population() const noexcept
Number of alive cells.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
std::string format_rule(const Outer_Totalistic_Binary_Rule &r)
Format a rule as a Conway-style Bxxx/Sxxx string.
constexpr Outer_Totalistic_Binary_Rule HighLife
Nathan Thompson's HighLife: B36/S23 (replicators).
and
Check uniqueness with explicit hash + equality functors.
std::size_t canonical_nodes
number of distinct canonical nodes
Hashlife engine for outer-totalistic binary cellular automata.