What syntax should a GoL API support?
Posted: November 9th, 2016, 9:40 pm
I'm writing a C++ library for manipulating cellular automaton patterns. It currently has the following features:
I've decided that the pattern class should be immutable (so operations such as advance return a new object, rather than modifying the old one). There is no overhead associated with this, since the actual contents of the pattern reside externally in the quadtree. When patterns fall out of scope (i.e. are destructed), a handle is released inside the quadtree so that it knows that the corresponding memory can be freed during garbage-collection.
However, I think that the x.advance() syntax is rather terse. Through operator overloading, we could optionally dispense with 'advance' and just write:
for instance. And should the rulestring be remembered by the pattern itself, so you can instead write:
(Then, the rule would be automatically loaded from the macrocell file if there's a #R line, obviating the need for an explicit call to setrule.)
Come to think of it, would square brackets (to match glife) be more intuitive? Or overloading the addition operator instead?
I quite like this += syntax for advancing a pattern, in which case you could write:
...and so on. What about shifting a pattern? Is the following syntax idiomatic enough, or do we need a further shortcut?
Looking at the glife source code, one can simply write glider(-2495, 29085228) instead.
I feel that the Boolean operations (intersection, union, etc.) should be represented by the usual operators.
Finally, any feature requests? Obviously I still need to do the following:
- Loading both 2-state and multistate macrocell patterns.
- Running patterns in B/S rules, plus optional history envelope, marked cells, and annotation layers (think of LifeHistory without the grey cells).
- Translating, rotating, and reflecting patterns.
- Bounding box and population functions.
- Boolean operations (union, intersection, difference, xor).
- Selecting rectangular subsets of patterns.
- The universe is infinite (although certain editing operations only work for int64 coordinates);
- The algorithm behaves like HashLife globally (the universe is a hashed quadtree), and like GoLGrid locally (32-by-32 leaf nodes are simulated using vectorised assembly). It's marginally faster than any of Golly's algorithms.
Code: Select all
lifetree<uint32_t, 1> lt;
std::cerr << "Loading caterpillar...";
pattern x(<, "caterpillar.mc");
std::cerr << "done!" << std::endl;
std::cerr << "Population: " << x.popcount() << std::endl;
x = x.advance("b3s23", 256);
std::cerr << "Population: " << x.popcount() << std::endl;
x = x.advance("b3s23", 14);
std::cerr << "Population: " << x.popcount() << std::endl;
However, I think that the x.advance() syntax is rather terse. Through operator overloading, we could optionally dispense with 'advance' and just write:
Code: Select all
x = x("b3s23", 256);Code: Select all
x.setrule("b3s23");
x = x(256);Come to think of it, would square brackets (to match glife) be more intuitive? Or overloading the addition operator instead?
Code: Select all
x += 256;
Code: Select all
pattern odd_phase_blinker = even_phase_blinker + 1;
pattern lidka_final = lidka + 30000;Code: Select all
pattern distant_glider = glider.shift(-2495, 29085228);I feel that the Boolean operations (intersection, union, etc.) should be represented by the usual operators.
Finally, any feature requests? Obviously I still need to do the following:
- Support saving files and loading RLEs;
- Allow bitplanes to be extracted and modified (e.g. for drawing on a pattern);
- Rudimentary pattern segmentation and/or recognition;
- Potentially support wider classes of rules?