53# include <gtest/gtest.h>
61 using Cell = std::pair<std::int64_t, std::int64_t>;
72 { s.emplace(x,
y); });
78 for (
const auto & c : cells)
79 e.set_alive(c.first, c.second,
true);
90 for (
const auto & c :
cur)
91 for (
int dy = -1; dy <= 1; ++dy)
92 for (
int dx = -1; dx <= 1; ++dx)
93 candidates.emplace(c.first + dx, c.second + dy);
99 for (
int dy = -1; dy <= 1; ++dy)
100 for (
int dx = -1; dx <= 1; ++dx)
102 if (dx == 0
and dy == 0)
104 if (
cur.count({ c.first + dx, c.second + dy }))
107 const bool alive =
cur.count(c) != 0;
108 if (rule.
apply(alive, n))
118 for (std::uint64_t i = 0; i <
steps; ++i)
127 return Cell_Set{ { 0, -1 }, { 0, 0 }, { 0, 1 } };
132 return Cell_Set{ { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
143 { 0, 2 }, { 1, 2 }, { 2, 2 } };
149 for (
const auto & c :
cs)
150 out.emplace(c.first + dx, c.second + dy);
158 static const int xy[][2] = {
159 { 1, 5 }, { 1, 6 }, { 2, 5 }, { 2, 6 },
160 { 11, 5 }, { 11, 6 }, { 11, 7 }, { 12, 4 }, { 12, 8 },
161 { 13, 3 }, { 13, 9 }, { 14, 3 }, { 14, 9 },
162 { 15, 6 }, { 16, 4 }, { 16, 8 },
163 { 17, 5 }, { 17, 6 }, { 17, 7 }, { 18, 6 },
164 { 21, 3 }, { 21, 4 }, { 21, 5 },
165 { 22, 3 }, { 22, 4 }, { 22, 5 },
166 { 23, 2 }, { 23, 6 },
167 { 25, 1 }, { 25, 2 }, { 25, 6 }, { 25, 7 },
168 { 35, 3 }, { 35, 4 }, { 36, 3 }, { 36, 4 },
171 for (
const auto & p :
xy)
172 s.emplace(p[0], p[1]);
214 Cell_Set src{ { -100, -100 }, { 0, 0 }, { 7, 13 }, { -3, 5 } };
215 for (
const auto & c : src)
259 for (
unsigned k : { 0u, 1u, 2u, 3u, 4u, 5u })
263 <<
"block changed after advance(" <<
k <<
")";
280 <<
"advance returned an odd total of generations: "
298 static_cast<std::int64_t
>(
advanced) / 4,
299 static_cast<std::int64_t
>(
advanced) / 4));
310 for (
unsigned k = 0;
k <= 9; ++
k)
315 <<
"after advance(" <<
k <<
") = " <<
advanced <<
" steps";
357 [](const ::testing::TestParamInfo<Rule_Sample> & i)
358 {
return std::string(i.param.name); });
369 for (
unsigned k = 0;
k <= 8; ++
k)
383 const std::int64_t target = e.
generation() + 1023;
421 std::int64_t
mx =
cs.begin()->first;
422 std::int64_t
my =
cs.begin()->second;
423 for (
const auto & c :
cs)
425 if (c.first <
mx)
mx = c.first;
426 if (c.second <
my)
my = c.second;
429 for (
const auto & c :
cs)
430 out.emplace(c.first -
mx, c.second -
my);
454 EXPECT_NE(
rle.find(
"rule = B36/S23"), std::string::npos)
455 <<
"rule field missing from: " <<
rle;
463 "x = 3, y = 3, rule = B3/S23\n"
494 const auto stats = e.
stats();
582 for (
int i = 0; i < 10; ++i)
585 for (
int i = 0; i < 10; ++i)
598 for (
auto p : { Cell{1, 0}, Cell{2, 0}, Cell{0, 1}, Cell{1, 1}, Cell{1, 2} })
size_t size_t int32_t * out
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).
void set_rule(const Rule &r)
Replace the rule. Invalidates the result cache.
std::uint64_t run(std::uint64_t generations)
Advance by exactly generations steps.
void for_each_alive(F &&f) const
Iterate over all alive cells, calling f(x, y) for each.
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::string save_rle_string(const std::string &comment={}) const
Convenience overload returning the RLE serialisation as a string.
void clear()
Reset the universe to empty (preserves rule, capacity and node cache).
std::int64_t generation() const noexcept
Number of generations elapsed since construction (or the last clear).
bool alive_at(const std::int64_t x, const std::int64_t y) const
Read the cell at world coordinates (x, y).
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::optional< Outer_Totalistic_Binary_Rule > parse_rule(const std::string &s)
Parse a B.../S... (or Wolfram S/B) rule string.
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 Conway_Life
Conway's Game of Life: B3/S23.
constexpr Outer_Totalistic_Binary_Rule HighLife
Nathan Thompson's HighLife: B36/S23 (replicators).
constexpr Outer_Totalistic_Binary_Rule Day_And_Night
Bays' Day & Night: B3678/S34678 (self-complementary).
constexpr Outer_Totalistic_Binary_Rule Seeds
Seeds: B2/S (every live cell dies, two neighbours produce a birth).
Compiler_SSA_Block & block(Compiler_SSA_Function &function, const Compiler_SSA_Block_Id id)
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
bool is_empty() const noexcept
True iff there are no alive cells.
std::size_t result_cache_clears
times the result cache was invalidated
Outer-totalistic binary rule encoded as two 9-bit bitmasks.
constexpr bool apply(const bool current, const std::uint8_t n) const noexcept
True iff a cell with current state and n live neighbours is alive next.
Outer_Totalistic_Binary_Rule rule
Hashlife engine for outer-totalistic binary cellular automata.
INSTANTIATE_TEST_SUITE_P(CAHashlifeBruteForce, CAHashlifeBruteForceMatch, ::testing::Values(Rule_Sample{ "Conway_blinker_128", Conway_Life, blinker(), 128u }, Rule_Sample{ "Conway_block_128", Conway_Life, block(), 128u }, Rule_Sample{ "Conway_glider_256", Conway_Life, glider(), 256u }, Rule_Sample{ "HighLife_glider_128", HighLife, glider(), 128u }, Rule_Sample{ "Seeds_blinker_32", Seeds, blinker(), 32u }, Rule_Sample{ "Day_Night_block_64", Day_And_Night, block(), 64u }), [](const ::testing::TestParamInfo< Rule_Sample > &i) { return std::string(i.param.name);})
TEST_P(CAHashlifeBruteForceMatch, MatchesUnboundedReference)