Thread for your script-related questions

For scripts to aid with computation or simulation in cellular automata.
User avatar
Resu
Posts: 801
Joined: May 23rd, 2025, 10:47 am
Location: UTC+14:00
Contact:

Re: Thread for your script-related questions

Post by Resu »

Is there a python version of gencols?

Code: Select all

x = 31, y = 13, rule = C
8.2X2.3X.3X.X.X$8.X.X.X3.X3.X.X$8.X.X.3X.3X.X.X$8.2X2.X5.X.X.X$8.X.X.
3X.3X.3X$M2.M$4.M$M3.M$.4M$27.2M$27.M.M$29.M$29.2M! [[ AUTOSTART GPS 10 ]]
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

Resu wrote: August 24th, 2025, 8:51 am Is there a python version of gencols?
Probably not, and anyway, it is usually better to pipe the output of shipcolls into an apgsearch stdin symmetry than to use gencols, since apgsearch fully censuses collisions and shipcolls works with INT rules.

I have been looking for Python projects to practice using lifelib though, so I could try and write a Python version of shipcolls or gencols.
User:PK22
Learning miscellaneous programming languages.
User avatar
Resu
Posts: 801
Joined: May 23rd, 2025, 10:47 am
Location: UTC+14:00
Contact:

Re: Thread for your script-related questions

Post by Resu »

Is lifeAPI and lifelib similar?

Code: Select all

x = 31, y = 13, rule = C
8.2X2.3X.3X.X.X$8.X.X.X3.X3.X.X$8.X.X.3X.3X.X.X$8.2X2.X5.X.X.X$8.X.X.
3X.3X.3X$M2.M$4.M$M3.M$.4M$27.2M$27.M.M$29.M$29.2M! [[ AUTOSTART GPS 10 ]]
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

What prevents parallelisation from being used with stdin searching for apgsearch? I tried manually removing the warning in the source code, and it was faster, but then it did not upload any sample soups to Catagolue.
User:PK22
Learning miscellaneous programming languages.
User avatar
Resu
Posts: 801
Joined: May 23rd, 2025, 10:47 am
Location: UTC+14:00
Contact:

Re: Thread for your script-related questions

Post by Resu »

It is possible to make a script that makes guns from a glider syntheses?

Code: Select all

x = 31, y = 13, rule = C
8.2X2.3X.3X.X.X$8.X.X.X3.X3.X.X$8.X.X.3X.3X.X.X$8.2X2.X5.X.X.X$8.X.X.
3X.3X.3X$M2.M$4.M$M3.M$.4M$27.2M$27.M.M$29.M$29.2M! [[ AUTOSTART GPS 10 ]]
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

Resu wrote: August 30th, 2025, 12:55 pm It is possible to make a script that makes guns from a glider syntheses?
Probably, but to make efficient guns, you would need a complex script.
The simplest script I can think of would:
  • Split the synthesis into 4 salvos (or fewer) and handle each separately.
  • Over each glider, starting with the back ones, paste a custom-built gun mechanism. Clock insertion is unusually effective, and it is sufficient to construct any salvo, so the mechanism should have high-period guns linked to Herschel edge shooters in order to synthesise a clock from the two perpendicular directions to the glider and then destroy it.
  • Advance the salvo by a large number of generations and repeat.
  • Repeat for all salvos, then assemble the gun.
The resulting gun would probably end up looking sort of like this one from Travelling Ts, which uses clock insertion four times, but with clock insertion used in all cases and different base gun mechanisms.
User:PK22
Learning miscellaneous programming languages.
User avatar
dvgrn
Moderator
Posts: 12023
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Thread for your script-related questions

Post by dvgrn »

PK22 wrote: August 30th, 2025, 1:10 pm
Resu wrote: August 30th, 2025, 12:55 pm It is possible to make a script that makes guns from a glider syntheses?
Probably, but to make efficient guns, you would need a complex script.
Yup, this question comes up every now and then, and efficiency is definitely the key.

It would actually be fairly quick and easy to write a script that would take a glider synthesis as input and produce a gun that uses the clock inserter reaction everywhere. With a little more fiddling, the script could even figure out what the lowest workable period is for the whole mechanism, and build a complete gun at that minimum period.

The problem is that the guns generated by the script would be tremendously ugly, and so ridiculously huge that nobody would want to look at them. They'd be maybe one or two orders of magnitude larger in each dimension than what we could build by hand (if we wanted to take the time).

You almost never actually need a clock inserter to complete a "synthesis of a synthesis". Usually syntheses of complicated objects like big spaceships happen in several stages, and it's usually possible to adjust the stages to make the salvoes of synthesis gliders easier to construct -- sometimes at the cost of a slightly slower synthesis.

One thing I _am_ somewhat tempted to write is a script that builds a glider-to-X converter, for any glider-constructible object X, just by feeding in a glider synthesis. That would certainly solve the problem of building a gun for X. It would also produce painfully ugly circuitry, no doubt, but it would be kind of fun to have it available.
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

Is there a way to use slmake to create recipes that only use gliders of a single parity and/or colour?
User:PK22
Learning miscellaneous programming languages.
User avatar
TigerCub414
Posts: 167
Joined: March 25th, 2024, 9:51 pm

Re: Thread for your script-related questions

Post by TigerCub414 »

PK22 wrote: September 6th, 2025, 4:44 am Is there a way to use slmake to create recipes that only use gliders of a single parity and/or colour?
slmake doesn't have a feature to specify the parity or color of gliders, but pslmake does have a way to specify the color: there is an argument that can be passed to pslmake like [-c {any,black,white}].

Code: Select all

x = 32, y = 32, rule = B3aijkr5j/S2aek3-acy4iz6c
8b3o$7bo2bo$7bo2bo$7b3o4$28b3o$28bo2bo$28bo2bo$29b3o11$3o$o2bo$o2bo$b
3o4$22b3o$21bo2bo$21bo2bo$21b3o!
User avatar
LaundryPizza03
Posts: 2623
Joined: December 15th, 2017, 12:05 am
Location: Unidentified location "https://en.wikipedia.org/wiki/Texas"

Re: Thread for your script-related questions

Post by LaundryPizza03 »

Is there a way to get Golly to recognize a default Python library? I specifically want to reference a Conda virtual environment every time I start up.

Code: Select all

x = 4, y = 3, rule = B3-q4z5y/S234k5j
2b2o$b2o$2o!
LaundryPizza03 at Wikipedia
Sokwe
Moderator
Posts: 3375
Joined: July 9th, 2009, 2:44 pm

Re: Thread for your script-related questions

Post by Sokwe »

LaundryPizza03 wrote: September 6th, 2025, 8:02 pm Is there a way to get Golly to recognize a default Python library? I specifically want to reference a Conda virtual environment every time I start up.
You should be able to set the full path to the Python library in the GollyPrefs file. On Linux this should be at "~/.golly/GollyPrefs". On Windows, it's at

Code: Select all

C:\Users\<username>\AppData\Roaming\Golly\GollyPrefs
Make sure you close all instances of Golly before editing the GollyPrefs file. The relevant line should start with "python3_lib=". I think setting this to the full path to the desired Python library will accomplish your goal.
-Matthias Merzenich
User avatar
b-engine
Posts: 3762
Joined: October 26th, 2023, 4:11 am
Location: Somewhere on where Earth At
Contact:

Re: Thread for your script-related questions

Post by b-engine »

How to configure apgluxe so that it stops after uploading a haul?
User avatar
dvgrn
Moderator
Posts: 12023
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Thread for your script-related questions

Post by dvgrn »

b-engine wrote: September 10th, 2025, 12:19 am How to configure apgluxe so that it stops after uploading a haul?
The README says there's a -i option to limit the number of hauls before exiting. I haven't tested it so can't say for sure that it works.
User avatar
TigerCub414
Posts: 167
Joined: March 25th, 2024, 9:51 pm

Re: Thread for your script-related questions

Post by TigerCub414 »

dvgrn wrote: September 10th, 2025, 5:16 am
b-engine wrote: September 10th, 2025, 12:19 am How to configure apgluxe so that it stops after uploading a haul?
The README says there's a -i option to limit the number of hauls before exiting. I haven't tested it so can't say for sure that it works.
It does indeed work.

Code: Select all

x = 32, y = 32, rule = B3aijkr5j/S2aek3-acy4iz6c
8b3o$7bo2bo$7bo2bo$7b3o4$28b3o$28bo2bo$28bo2bo$29b3o11$3o$o2bo$o2bo$b
3o4$22b3o$21bo2bo$21bo2bo$21b3o!
User avatar
b-engine
Posts: 3762
Joined: October 26th, 2023, 4:11 am
Location: Somewhere on where Earth At
Contact:

Re: Thread for your script-related questions

Post by b-engine »

dvgrn wrote: September 10th, 2025, 5:16 am The README says there's a -i option to limit the number of hauls before exiting. I haven't tested it so can't say for sure that it works.
It do indeed work; those workflows there complete by themselves.
User avatar
R2INT
Posts: 811
Joined: July 2nd, 2024, 7:42 pm

Re: Thread for your script-related questions

Post by R2INT »

I have performed a few performance tests on rlifesrc with and without backjumping to compare:

Code: Select all

Benchmark results
The number in the parenthesis is the estimated difficulty factor.
c/8 with symmetry D2|
(24) 5x32: 17ms vs. 15.3 with backjumping
(32) 7x32: 1.0371s vs. 568.5ms with backjumping
(40) 9x32: 59.2186s vs. 27.41s with backjumping

c/7 with symmetry D2|
(35) 9x32: 4.5045s vs. 2.7035s with backjumping

3c/8 with symmetry D2|
(40) 9x32: 365.2ms vs. 319.1ms with backjumping
(48) 11x32: 4.5017s vs. 3.5168s with backjumping

c/4 with symmetry D2|
(24) 11x32: 68ms vs. 128.7ms with backjumping

c/5 with symmetry D2|
(30) 11x32: 387ms vs. 470.8ms with backjumping
(35) 13x32: 6.336s vs. 6.9899s with backjumping

c/5d with symmetry D2\
(??) 32x32 w10: 1.0055s vs. 1.5706s with backjumping

c/8d with symmetry D2\

(??) 32x32 w7: 6.0433s vs. 6.0846s with backjumping
Seems like backjumping is faster for high-period orthogonal spaceships (though there are still some optimizations that could be made).
Range-2 INT
R2INT's Rule Collection

Travelling Ts has surpassed LeapLife in post count, but not yet in technology.
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

Is it possible to use QuFince (or a hacked version) to semi-automatically (i.e, without manually having to create input files for every potential component) search for new components/syntheses?
Also, how do I make QuFince upload to Catagolue?
User:PK22
Learning miscellaneous programming languages.
User avatar
hotcrystal0
Posts: 4564
Joined: July 3rd, 2020, 5:32 pm
Location: wherever you think I am

Re: Thread for your script-related questions

Post by hotcrystal0 »

Does Bellman/Barrister work with INT rules? (more specifically, can it work with B3/S23-a5?)
139 days until New York's age verification law goes into effect.

Code: Select all

x = 192, y = 53, rule = B3/S23
33$42b4o$41b6o$40b2ob4o$41b2o3$41b2o$39bo6bo$38bo8bo$38bo8bo$38b9o3$42b
4o$41b6o$40b2ob4o$41b2o!
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

What program was/is used to find the single-channel recipe toolkit, and how hard would it be to write a program that can find a similar toolkit in INT rules using similar design principles?
User:PK22
Learning miscellaneous programming languages.
User avatar
I6_I6
Posts: 999
Joined: July 26th, 2025, 8:44 pm
Location: Here, there, somewhere, anywhere, everywhere.
Contact:

Re: Thread for your script-related questions

Post by I6_I6 »

How do you feed partials to rlifesrc? I've tried putting things in the "known cells" section in settings, but every time I try to do a search it gives me "No more result" in a few milliseconds. I did fix the RLE to include dead cells, but it doesn't work.
Also, what's backjumping?

EDIT:
Here's the exact RLE I gave rlifesrc:

Code: Select all

x = 27, y = 24, rule = B3/S23-a5
...........................$
...........................$
........oo.o...o.oo........$
........oo...o...oo........$
.......oo..ooooo..oo.......$
...........ooooo...........$
........oo.......oo........$
...........................$
.....oo.............oo.....$
.......ooo.......ooo.......$
.......oooooo.oooooo.......$
.........o.o...o.o.........$
.....o.o...oo.oo...o.o.....$
......oo...oo.oo...oo......$
.....o...o.o.o.o.o...o.....$
..........o.ooo.o..........$
.....oo...o.....o...oo.....$
.....oo.....o.o.....oo.....$
....o....o..ooo..o....o....$
....o..oo.o.....o.oo..o....$
............o.o............$
........o..o...o..o........$
.....oo...oo...oo...oo.....$
....o.o.............o.o....$
...oo?????????????????oo...!
Last edited by I6_I6 on October 9th, 2025, 1:48 am, edited 1 time in total.

Code: Select all

#C [[ THEME Golly ]]
x = 27, y = 15, rule = LifeHistory
8.A$A6.A.A$3A4.BA2B.B2D$3.A4.2B.2B2DB$2.2A2.3B.6B2.3B$2.20B$4.19B$4.2B
C10BD4B$4.2B2C10BD4B$4.B2C11B2D3B$4.13B2D4B$5.12BD3B.B2A$6.13B3.BA.A$
6.3B.B3.B10.A$25.2A!
RuleEdit: A .rule file editing tool
User avatar
dvgrn
Moderator
Posts: 12023
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Thread for your script-related questions

Post by dvgrn »

PK22 wrote: October 8th, 2025, 12:37 pm What program was/is used to find the single-channel recipe toolkit, and how hard would it be to write a program that can find a similar toolkit in INT rules using similar design principles?
See this post in Basic Questions for the last time this question was answered, with some vaguely related discussion here and here.

Long story short, Simon Ekström's code has a lot of hard-coded limitations. Luckily it really wouldn't be all that difficult to write a new single-channel search program that supports single-channel searches in INT rules, and avoids some of the other arbitrary limitations.

A quick-and-dirty rewrite might run slower than simeks' C code, but the nice thing about single-channel searches is that they just have to run once for any given rule -- so search speed isn't a really big issue. It might even work to dump intermediate targets to disk, and cover let's say a terabyte-sized search space over a longer time period.
dvgrn wrote: April 28th, 2025, 7:11 am An OCA-supporting single-channel search program would be a big step forward. But it might be just as easy to write something like that from scratch using lifelib (which wasn't available when simeks was doing single-channel searches -- it showed up in 2018). Seems like it would be tricky to rework Gol-search to support OCA, and/or to remove its other limitations.
User avatar
I6_I6
Posts: 999
Joined: July 26th, 2025, 8:44 pm
Location: Here, there, somewhere, anywhere, everywhere.
Contact:

Re: Thread for your script-related questions

Post by I6_I6 »

Is it harder to search for a knightship than it is to search for an asymmetric non-oblique ship of the same period?

Code: Select all

#C [[ THEME Golly ]]
x = 27, y = 15, rule = LifeHistory
8.A$A6.A.A$3A4.BA2B.B2D$3.A4.2B.2B2DB$2.2A2.3B.6B2.3B$2.20B$4.19B$4.2B
C10BD4B$4.2B2C10BD4B$4.B2C11B2D3B$4.13B2D4B$5.12BD3B.B2A$6.13B3.BA.A$
6.3B.B3.B10.A$25.2A!
RuleEdit: A .rule file editing tool
User avatar
b-engine
Posts: 3762
Joined: October 26th, 2023, 4:11 am
Location: Somewhere on where Earth At
Contact:

Re: Thread for your script-related questions

Post by b-engine »

I6_I6 wrote: October 20th, 2025, 9:11 am Is it harder to search for a knightship than it is to search for an asymmetric non-oblique ship of the same period?
Maybe; for example there's only one known p6 knightship (Sir Robin), but WinLifeSrc can spin up a 2c/6 spaceship in matter of hours.
User avatar
PK22
Posts: 612
Joined: January 25th, 2025, 11:38 am
Location: United Kingdom
Contact:

Re: Thread for your script-related questions

Post by PK22 »

I tried to implement pseudo-object symmetries in apgsearch v5 by modifying classifier.h in lifelib, but it detects quasi objects as well:

Code: Select all

#pragma once
#include "pattern2.h"
#include "incubator.h"
#include <unordered_map>
#include <map>
#include <set>

#include "dsds.h"

/*
* This contains code from apgmera, minus the dependence on Golly, for
* separating and classifying objects.
*/

namespace apg {

    template<int M>
    class base_classifier {

        public:

        bool b0;
        uint64_t gmax;
        uint8_t transtable[512];
        std::string rule;
        std::string zoi;
        lifetree_abstract<uint32_t>* lab;
        lifetree<uint32_t, M + 1> lh;
        std::unordered_map<uint64_t, std::string> bitcache;
        std::unordered_map<std::string, std::vector<std::string> > decompositions;

        bool diagbirth() {
            /*
            * Does birth occur in either of the following situations?
            *  o..    ..o
            *  ... or ...
            *  ..o    o..
            */

            return (transtable[257] || transtable[68] || b0);
        }

        std::vector<std::vector<apg::pattern>> get_patterns(dsds &uf, std::unordered_map<uint64_t, uint64_t> &umap, std::vector<apg::pattern> &phases, std::vector<int> *short_connections) {

            uint64_t islcount = 0;

            std::unordered_map<uint64_t, uint64_t> cmap;
            std::vector<uint64_t> invcmap;

            for (auto it = umap.begin(); it != umap.end(); ++it) {
                uint64_t cid = uf.find(it->second);
                if (cmap.count(cid) == 0) {
                    cmap[cid] = (islcount++);
                    invcmap.push_back(cid);
                }
            }

            // Create empty array of patterns:
            std::vector<std::vector<apg::pattern>> subpats(islcount);
            for (uint64_t c = 0; c < islcount; c++) {
                for (uint64_t t = 0; t < phases.size(); t++) {
                    subpats[c].emplace_back(lab, "", rule);
                }
            }

            // Populate patterns:
            for (auto it = umap.begin(); it != umap.end(); ++it) {
                uint64_t cid = uf.find(it->second);
                uint64_t c = cmap[cid];
                uint64_t t = it->first >> 48;
                subpats[c][t] += phases[t].subrect((it->first & 0xffffff), ((it->first >> 24) & 0xffffff), 1, 1);
            }

            if (short_connections == nullptr) { return subpats; }

            for (uint64_t t = 0; t < phases.size() - 1; t++) {
                for (uint64_t i = 0; i < islcount; i++) {
                    auto successor = subpats[i][t][1];
                    if (successor == subpats[i][t+1]) {
                        continue; // island is stable in this generation
                    }
                    auto extrabirths = successor - subpats[i][t+1];
                    std::vector<int64_t> celllist(extrabirths.totalPopulation() * 2);
                    extrabirths.get_coords(&(celllist[0]));

                    for (uint64_t ii = 0; ii < celllist.size(); ii += 2) {
                        uint64_t coord = (t << 48) + (celllist[ii+1] << 24) + celllist[ii];
                        
                        std::set<uint64_t> friends;

                        for (auto&& x : (*short_connections)) {
                            uint64_t other = coord + x;
                            if (umap.count(other)) {
                                uint64_t j = cmap[uf.find(umap[other])];
                                if (j != i) { friends.insert(j); }
                            }
                        }

                        if (friends.size() == 1) {
                            uint64_t j = *(friends.begin());
                            uf.merge(invcmap[i], invcmap[j]);
                            return subpats; // improvement made
                        } else if (friends.size() == 0) {
                            std::cerr << "Unreachable code!!!" << std::endl;
                        }
                    }
                }
            }

            return subpats;
        }

        /**
         * Complete object separation.
         */
        std::vector<std::string> full_3dsep(std::string parent) {

            // cache:
            {
                auto it = decompositions.find(parent);
                if (it != decompositions.end()) {
                    return it->second;
                }
            }

            std::vector<std::string> elements;

            #define RETURN_SINGLETON() elements.push_back(parent); decompositions[parent] = elements; return elements
            if (parent[0] != 'x') { RETURN_SINGLETON(); }

            apg::pattern pat(lab, parent, rule);
            uint64_t period = pat.ascertain_period();

            if ((pat.empty()) || (period == 0) || (period > 30000)) { RETURN_SINGLETON(); }

            int64_t dy = pat.dy;
            int64_t dx = pat.dx;

            pat = pat.shift(262144, 262144);

            int64_t bbox[4] = {0};
            pat.getrect(bbox);

            if ((bbox[2] > 100000) || (bbox[3] > 100000)) { RETURN_SINGLETON(); }

            std::unordered_map<uint64_t, uint64_t> umap;
            uint64_t id = 0;

            std::vector<apg::pattern> phases;

            for (uint64_t t = 0; t <= period; t++) {
                phases.emplace_back(lab, "", rule);
                phases[t] += pat;

                std::vector<int64_t> celllist(pat.totalPopulation() * 2);
                pat.get_coords(&(celllist[0]));
                for (uint64_t i = 0; i < celllist.size(); i += 2) {
                    uint64_t coord = (t << 48) + (celllist[i+1] << 24) + celllist[i];
                    umap[coord] = id; id += 1;
                }

                if (t != period) { pat = pat[1]; }
            }

            std::vector<uint64_t> connections;
            std::vector<int> short_connections;

            connections.push_back((period << 48) + (dy << 24) + dx);

            int range = zoi.size() >> 1;

            for (int i = -range; i <= range; i++) {
                for (int j = -range; j <= range; j++) {
                    int k = (i << 24) + j;
                    if (k > 0) { connections.push_back(k); }
                    connections.push_back((1ull << 48) + k);
                    if (k != 0) { short_connections.push_back(k); }
                }
            }

            // disjoint-set data structure:
            dsds uf(id);
            dsds uf2(id);

            std::map<uint64_t, std::vector<uint64_t>> suppressed;

            for (auto it = umap.begin(); it != umap.end(); ++it) {
                for (auto&& x : connections) {
                    uint64_t other = it->first + x;
                    if (umap.count(other)) {
                        uf.merge(it->second, umap[other]);
                        uf2.merge(it->second, umap[other]);
                    }
                }
                for (auto&& x : short_connections) {
                    uint64_t other = it->first + x;
                    if (!(umap.count(other))) {
                        suppressed[other].push_back(it->second);
                    }
                }
            }

            for (auto it = suppressed.begin(); it != suppressed.end(); ++it) {
                uint64_t l = it->second.size();
                if (l >= 3) {
                    for (uint64_t i = 1; i < l; i++) {
                        uf2.merge(it->second[i-1], it->second[i]);
                    }
                }
            }

            if (uf2.count() > 1) {
                // fast separation:

                auto subpats = get_patterns(uf2, umap, phases, nullptr);

                for (auto&& y : subpats) {
                    std::string apgcode = y[0].apgcode();
                    auto new_elems = full_3dsep(apgcode);
                    for (auto&& x : new_elems) { elements.push_back(x); }
                }

                decompositions[parent] = elements;
                return elements;
            }

            std::vector<std::vector<apg::pattern>> subpats;

            // uint64_t isize = uf.count();

            while (subpats.size() != uf.count()) {
                subpats = get_patterns(uf, umap, phases, &short_connections);
            }

            uint64_t islcount = subpats.size();

            /*
            if (islcount != isize) {
                std::cout << parent << " improved from " << isize << " islands to " << islcount << std::endl;
            }
            */

            // Only one island; terminate.
            if (islcount == 1) { RETURN_SINGLETON(); }

            bool all_standalone = true;
            for (uint64_t i = 0; i < islcount; i++) {
                for (uint64_t t = 0; t < period; t++) {
                    if (subpats[i][t][1] != subpats[i][t+1]) {
                        all_standalone = false;
                    }
                }
            }

            if (all_standalone) {

                for (uint64_t i = 0; i < islcount; i++) {
                    std::string apgcode = subpats[i][0].apgcode();
                    auto new_elems = full_3dsep(apgcode);
                    for (auto&& x : new_elems) { elements.push_back(x); }
                }

                decompositions[parent] = elements;
                return elements;
            }

            std::set<uint64_t> invalid_cache;

            bool low_period_osc = (period <= 3) && (dx == 0) && (dy == 0);

            for (uint64_t n = 2; n <= islcount; n++) {

                if (low_period_osc) {
                    if ((n > 4) && (zoi == "95")) {
                        // unnecessary by Four Colour Theorem
                        break;
                    } else if ((n > 7) && (zoi == "99")) {
                        break;
                    }
                }

                uint64_t cost = 1;
                for (uint64_t i = 0; i < islcount; i++) {
                    cost *= n;
                    if (cost > 1048576) { break; }
                }

                if ((cost > 1048576) || (islcount > 16)) {
                    // too expensive; give up
                    std::cerr << "Gave up attempting to separate " << parent << " (" << islcount << " islands) into " << n << " subobjects." << std::endl;
                    break;
                }

                // std::cerr << "Separating " << parent << " (" << islcount << " islands) into " << n << " subobjects." << std::endl;

                std::vector<uint8_t> currstack(islcount);
                std::vector<uint8_t> maxstack(islcount);

                currstack[0] = 0;
                currstack[1] = 0;
                maxstack[0] = 0;

                uint64_t focus = 1;
                while (focus) {

                    uint8_t limit = maxstack[focus - 1] + 1;
                    limit = (limit >= n) ? (n - 1) : limit;
                    if (currstack[focus] > limit) {
                        focus -= 1;
                        currstack[focus] += 1;
                    } else {

                        maxstack[focus] = maxstack[focus - 1];
                        if (maxstack[focus] < currstack[focus]) { maxstack[focus] = currstack[focus]; }
                        if (focus < (islcount - 1)) {
                            focus += 1;
                            currstack[focus] = 0;
                        } else {
                            if (maxstack[focus] == n - 1) {

                                // We have a n-colouring which uses all n colours:
                                std::vector<uint64_t> bitmasks(n);

                                for (uint64_t i = 0; i < islcount; i++) {
                                    bitmasks[currstack[i]] |= (1ull << i);
                                }

                                bool valid = true;

                                for (uint64_t i = 0; i < n; i++) {
                                    if (invalid_cache.count(bitmasks[i])) { valid = false; }
                                }

                                if (valid) {

                                    std::vector<std::vector<apg::pattern>> unions(n);
                                    for (uint64_t i = 0; i < n; i++) {
                                        for (uint64_t t = 0; t <= period; t++) {
                                            unions[i].push_back(pattern(lab, "", rule));
                                        }
                                    }
                                    for (uint64_t i = 0; i < islcount; i++) {
                                        for (uint64_t t = 0; t <= period; t++) {
                                            unions[currstack[i]][t] |= subpats[i][t];
                                        }
                                    }

                                    bool faithful = true;

                                    for (uint64_t i = 0; i < n; i++) {
                                        for (uint64_t t = 0; t < period; t++) {
                                            if (unions[i][t][1] != unions[i][t+1]) {
                                                faithful = false;
                                                invalid_cache.insert(bitmasks[i]);
                                            }
                                        }
                                    }

                                    if (faithful) {
                                        // We have a decomposition into non-interacting pieces!

                                        for (uint64_t i = 0; i < n; i++) {
                                            std::string apgcode = unions[i][0].apgcode();
                                            auto new_elems = full_3dsep(apgcode);
                                            for (auto&& x : new_elems) { elements.push_back(x); }
                                        }

                                        decompositions[parent] = elements;
                                        return elements;
                                    }
                                }
                            }
                            currstack[focus] += 1;
                        }
                    }
                }
            }

            RETURN_SINGLETON();

        }


        std::vector<std::string> pseudoBangBang(pattern pat, std::vector<bitworld> *clvec) {
            /*
            * Borrowed from apgmera, and upgraded.
            */

            uint64_t period = pat.ascertain_period();
            bool isOscillator = ((pat.dx == 0) && (pat.dy == 0));
            pattern hist(&lh, "", rule + "History");
            hist += pat;
            hist = hist[period + 2];
            bitworld lrem = hist.flatlayer(0);
            bitworld env = hist.flatlayer(1);

            // If we have a moving object, do not reiterate:
            bool reiterate = isOscillator && (zoi.length() <= 2);

            std::map<std::pair<int64_t, int64_t>, uint64_t> geography;
            uint64_t label = 0;
            while (lrem.population() != 0) {
                bitworld cluster = grow_cluster(lrem.get1cell(), env, reiterate ? "9" : zoi);
                lrem -= cluster;
                label += 1;
                std::vector<std::pair<int64_t, int64_t> > celllist = cluster.getcells();
                for (uint64_t i = 0; i < celllist.size(); i++) {
                    geography[celllist[i]] = label;
                }
            }

            while (reiterate) {
                reiterate = false;
                for (uint64_t i = 0; i < period; i++) {
                    hist = hist[1];
                    bitworld lcurr = hist.flatlayer(0);
                    bitworld dcurr = bleed(lcurr, "9");
                    dcurr -= env;
                    std::vector<std::pair<int64_t, int64_t> > liberties = dcurr.getcells();
                    for (uint64_t j = 0; j < liberties.size(); j++) {
                        int64_t ix = liberties[j].first;
                        int64_t iy = liberties[j].second;
                        std::map<uint64_t, uint64_t> tally;
                        for (int64_t ux = 0; ux <= 2; ux++) {
                            for (int64_t uy = 0; uy <= 2; uy++) {
                                int value = geography[std::pair<int64_t, int64_t>(ux + ix - 1, uy + iy - 1)];
                                if (lcurr.getcell(ux + ix - 1, uy + iy - 1)) {
                                    tally[value] = tally[value] + (1 << (uy * 3 + ux));
                                }
                            }
                        }

                        uint64_t dominantColour = 0;
                        std::map<uint64_t, uint64_t>::iterator it2;
                        for (it2 = tally.begin(); it2 != tally.end(); it2++) {
                            int colour = it2->first;
                            uint64_t count = it2->second;
                            if (transtable[count]) { dominantColour = colour; }
                            // if (__builtin_popcountll(count) == 3) { dominantColour = colour; }
                        }
                        // Resolve dependencies:
                        if (dominantColour != 0) {
                            std::map<std::pair<int64_t, int64_t>, uint64_t>::iterator it3;
                            for (it3 = geography.begin(); it3 != geography.end(); it3++) {
                                std::pair<int64_t, int64_t> coords = it3->first;
                                uint64_t colour = it3->second;

                                if (tally[colour] > 0) {
                                    geography[coords] = dominantColour;
                                    if (colour != dominantColour) {
                                        // A change has occurred; keep iterating until we achieve stability:
                                        reiterate = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            bitworld lcurr = (isOscillator ? pat.flatlayer(0) : hist.flatlayer(0));
            std::vector<bitworld> cbs(label+1);
            std::map<std::pair<int64_t, int64_t>, uint64_t>::iterator it3;
            for (it3 = geography.begin(); it3 != geography.end(); it3++) {
                std::pair<int64_t, int64_t> coords = it3->first;
                uint64_t colour = it3->second;
                cbs[colour].setcell(coords.first, coords.second, 1);
            }
            std::vector<std::string> components;
            for (uint64_t l = 1; l <= label; l++) {
                cbs[l] &= lcurr;
                if (cbs[l].population() > 0) {
                    if (clvec != 0) { clvec->push_back(cbs[l]); }
                    apg::pattern ppart(lab, lab->demorton(cbs[l], 1), rule);
                    components.push_back(ppart.apgcode());
                }
            }

            for (auto it = components.begin(); it != components.end(); ++it) {
                if ((*it) == "PATHOLOGICAL") {
                    // invalid separation
                    std::vector<std::string> newcomps;
                    newcomps.push_back(pat.apgcode());
                    return newcomps;
                }
            }

            return components;
        }

        std::vector<bitworld> getclusters(bitworld &live, bitworld &env, bool rigorous) {

            bitworld lrem = live;
            std::vector<bitworld> clusters;

            while (lrem.population() != 0) {
                // Obtain cluster:
                bitworld cluster = grow_cluster(lrem.get1cell(), env, zoi);
                cluster &= lrem;
                lrem -= cluster;
                if (rigorous) {
                    pattern ppart(lab, lab->demorton(cluster, 1), rule);
                    pseudoBangBang(ppart, &clusters);
                } else {
                    clusters.push_back(cluster);
                }
            }

            return clusters;
        }

        // Forward declaration for co-recursive function:
        // std::map<std::string, int64_t> census(pattern pat, int numgens, std::string (*adv)(pattern), bool recurse);

        std::pair<bool, std::vector<std::string> > identify(uint64_t bb, std::vector<bitworld> &cplanes, bool recurse) {

            std::string repr;
            std::vector<std::string> elements;

            if ((bb != 0) && (bitcache.find(bb) != bitcache.end())) {
                repr = bitcache[bb];
                elements = decompositions[repr];
                return std::pair<bool, std::vector<std::string> >(true, elements);
            }

            if (cplanes.size() == 0) {
                cplanes.resize(1);
                cplanes[0].world.emplace(std::pair<int32_t, int32_t>(0, 0), bb);
            }

            apg::pattern cl2(lab, cplanes, rule);
            cl2.pdetect(gmax); // Restrict period.

            if (cl2.dt == 0) {
                return std::pair<bool, std::vector<std::string> >(false, elements);
            }

            uint64_t period = cl2.ascertain_period();
            repr = cl2.apgcode();

            if ((repr[0] == 'x') && (period <= 10000)) {
                elements = full_3dsep(repr);
            } else if (recurse) {
                std::map<std::string, int64_t> rc = census(cl2, period << 3, 0, false);
                for (auto it2 = rc.begin(); it2 != rc.end(); ++it2) {
                    if (it2->second > 0) {
                        for (int64_t i = 0; i < it2->second; i++) {
                            elements.push_back(it2->first);
                        }
                    }
                }
            } else {
                elements.push_back(repr);
            }

            if ((repr[0] == 'x') && (bb != 0)) {
                bitcache.emplace(bb, repr);
            }
            
            return std::pair<bool, std::vector<std::string> >(true, elements);
        }

        template<int H>
        void deeppurge(std::map<std::string, int64_t> &cm, incubator<56, H> &icb, std::string (*adv)(pattern),
                        bool remove_annoyances, bool remove_gliders) {

            uint64_t excess[8] = {0ull};

            for (auto it = icb.tiles.begin(); it != icb.tiles.end(); ++it) {
                Incube<56, H>* sqt = &(it->second);
                for (int y = 0; y < H; y++) {
                    uint64_t r = sqt->d[y];
                    while (r != 0) {
                        uint64_t x = __builtin_ctzll(r);
                        int annoyance = (remove_annoyances ? icb.isAnnoyance(sqt, x, y) : 0);
                        if (annoyance > 0) {
                            excess[annoyance] += 1;
                        } else if ((!remove_gliders) || (icb.isGlider(sqt, x, y) == 0)) {
                            // TODO: Identify unknown object
                            auto intList = icb.get_component(sqt, x, y);
                            int population = intList.back();
                            int ll = intList.size() - 1;
                            if (population > 0) {
                                if ((remove_annoyances) && (population == 3)) {
                                    excess[3] += 1;
                                } else {
                                    std::vector<int> celllist(population*2);
                                    int i = 0;
                                    for (int j = 0; j < ll; j += 3) {
                                        if (intList[j + 2] == 1) {
                                            celllist[i++] = intList[j];
                                            celllist[i++] = intList[j+1];
                                        }
                                    }

                                    int left = celllist[0];
                                    int top = celllist[1];
                                    int right = celllist[0];
                                    int bottom = celllist[1];

                                    for (int i = 0; i < (population*2); i += 2) {
                                        if (left > celllist[i]) { left = celllist[i]; }
                                        if (right < celllist[i]) { right = celllist[i]; }
                                        if (top > celllist[i+1]) { top = celllist[i+1]; }
                                        if (bottom < celllist[i+1]) { bottom = celllist[i+1]; }
                                    }

                                    for (int i = 0; i < (population*2); i += 2) {
                                        celllist[i] -= left;
                                        celllist[i+1] -= top;
                                    }

                                    right -= left;
                                    bottom -= top;

                                    uint64_t bitstring = 0;
                                    std::vector<bitworld> cplanes;

                                    if (right <= 7 && bottom <= 7) {
                                        for (int i = 0; i < (population*2); i += 2) {
                                            bitstring |= (1ull << (celllist[i] + 8*celllist[i+1]));
                                        }
                                    } else {
                                        cplanes.resize(1);
                                        for (int i = 0; i < (population*2); i += 2) {
                                            cplanes[0].setcell(celllist[i], celllist[i+1], 1);
                                        }
                                    }

                                    std::pair<bool, std::vector<std::string> > res = identify(bitstring, cplanes, true);

                                    if (!(res.first)) {
                                        apg::pattern cl2(lab, cplanes, rule);
                                        std::string diagnosed = "PATHOLOGICAL";
                                        if (adv != 0) { diagnosed = (*adv)(cl2); }
                                        res.second.push_back(diagnosed);
                                    }

                                    // Enter elements into tally:
                                    for (uint64_t i = 0; i < res.second.size(); i++) {
                                        cm[res.second[i]] += 1;
                                    }
                                }
                            }
                        }
                        r ^= (1ull << x);
                        r &= sqt->d[y];
                    }
                }
            }

            if (excess[3] > 0) { cm["xp2_7"] += excess[3]; }
            if (excess[4] > 0) { cm["xs4_33"] += excess[4]; }
            if (excess[5] > 0) { cm["xq4_153"] += excess[5]; }
            if (excess[6] > 0) { cm["xs6_696"] += excess[6]; }
            if (excess[7] > 0) { cm["xs5_253"] += excess[7]; }

        }

        void census(std::map<std::string, int64_t> &tally, std::vector<bitworld> &planes, std::string (*adv)(pattern), bool recurse) {

            bitworld lrem = planes[0];
            for (uint64_t i = 1; i < M; i++) {
                lrem += planes[i];
            }
            bitworld env = lrem;
            env += planes[M];

            bool glider_plane = ((M == 1) && (planes.size() == 3));

            bitworld lrem2 = lrem;
            if (glider_plane) { lrem2 -= planes[2]; }

            while (lrem2.population() != 0) {

                // Obtain cluster:
                bitworld cluster = grow_cluster(lrem2.get1cell(), env, zoi);
                cluster &= lrem;
                lrem -= cluster;
                lrem2 -= cluster;

                uint64_t bb = 0;

                if (M == 1) {
                    if (cluster.world.size() > 1) { cluster = fix_topleft(cluster); }
                    if (cluster.world.size() == 1) {
                        // We use a bitcache for fast lookup of small objects:
                        auto it = cluster.world.begin(); bb = it->second;
                    }
                }

                std::vector<bitworld> cplanes;

                if (bb == 0) {
                    for (uint64_t i = 0; i < M; i++) {
                        cplanes.push_back(cluster);
                        if (M != 1) { cplanes.back() &= planes[i]; }
                    }
                }

                std::pair<bool, std::vector<std::string> > res = identify(bb, cplanes, recurse);

                if (!(res.first)) {
                    apg::pattern cl2(lab, cplanes, rule);
                    std::string diagnosed = "PATHOLOGICAL";
                    if (adv != 0) { diagnosed = (*adv)(cl2); }
                    res.second.push_back(diagnosed);
                }

                // Enter elements into tally:
                for (uint64_t i = 0; i < res.second.size(); i++) {
                    tally[res.second[i]] += 1;
                }
            }

            if (lrem.population() > 0) { tally["xq4_153"] += (lrem.population() / 5); }

        }

        std::map<std::string, int64_t> census(std::vector<bitworld> &planes, std::string (*adv)(pattern), bool recurse) {
            std::map<std::string, int64_t> tally;
            census(tally, planes, adv, recurse);
            return tally;
        }

        std::map<std::string, int64_t> census(std::vector<bitworld> &planes, std::string (*adv)(pattern)) {
            return census(planes, adv, true);
        }

        std::map<std::string, int64_t> census(bitworld &live, bitworld &env, std::string (*adv)(pattern)) {
            std::vector<bitworld> bwv;
            bwv.push_back(live); bwv.push_back(env);
            return census(bwv, adv);
        }

        std::map<std::string, int64_t> census(bitworld &live, bitworld &env) {
            return census(live, env, 0);
        }

        std::map<std::string, int64_t> census(pattern pat, int numgens, std::string (*adv)(pattern), bool recurse) {
            pattern hist(&lh, "", rule + "History");
            hist += pat;
            hist = hist[numgens];
            std::vector<bitworld> bwv;
            for (uint64_t i = 0; i <= M; i++) { bwv.push_back(hist.flatlayer(i)); }
            return census(bwv, adv, recurse);
        }

        std::map<std::string, int64_t> census(pattern pat, int numgens, std::string (*adv)(pattern)) {
            return census(pat, numgens, adv, true);
        }

        std::map<std::string, int64_t> census(pattern pat, int numgens) {
            return census(pat, numgens, 0);
        }

        base_classifier(lifetree_abstract<uint32_t>* lab, std::string rule) : lh(100)
        {
            this->lab = lab;
            this->rule = rule;
            gmax = 1048576;

            /*
            * We construct the transition table by bootstrapping: we run a
            * pattern containing all 512 3-by-3 tiles and examine the
            * centre cells of the tiles after one generation.
            */
            std::string transrle = "3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob"
            "5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob2ob2ob2ob2ob2o"
            "b2ob2o2$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob"
            "2o3b2obob5o$2bo2bo2bo2bo2bo2bo2bo2b2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob"
            "2ob2ob2ob2ob26o2$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob"
            "5o3bo3bob2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bo"
            "b2ob2ob2ob2ob2ob2ob2ob2o$o2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2b"
            "o2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo$3bo3bob2o3b2obob5o3b"
            "o3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2b"
            "o2bo2b2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$o2bo2bo2bo2bo"
            "2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo"
            "2bo2bo2bo2bo$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo"
            "3bob2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob"
            "2ob2ob2ob2ob2ob2ob2o$bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2b"
            "o2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo$3bo3bob2o3b2obob5o3bo3b"
            "ob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2bo2b"
            "o2b2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$bo2bo2bo2bo2bo2b"
            "o2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo"
            "2bo2bo2bo$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bo"
            "b2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob2ob"
            "2ob2ob2ob2ob2ob2o$2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob"
            "2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2o$3bo3bob2o3b2obob5o3bo3bob"
            "2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2bo2bo"
            "2b2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$2ob2ob2ob2ob2ob2o"
            "b2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob"
            "2ob2ob2o$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob"
            "2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob2ob2o"
            "b2ob2ob2ob2ob2o$2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo"
            "2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo$3bo3bob2o3b2obob5o3bo3bob2o"
            "3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2bo2bo2b"
            "2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$2bo2bo2bo2bo2bo2bo"
            "2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo2bo"
            "2bo2bo2bo$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bo"
            "b2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob2ob"
            "2ob2ob2ob2ob2ob2o$ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2o"
            "b2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2obo$3bo3bob2o3b2obob5o3bo3bob"
            "2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2bo2bo"
            "2b2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$ob2ob2ob2ob2ob2ob"
            "2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob"
            "2ob2ob2obo$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3b"
            "ob2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob2ob"
            "2ob2ob2ob2ob2ob2o$b2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob"
            "2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2o$3bo3bob2o3b2obob5o3bo3bob"
            "2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2bo2bo"
            "2b2ob2ob2ob2ob2ob2ob2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$b2ob2ob2ob2ob2ob"
            "2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob2ob"
            "2ob2ob2ob2o$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo"
            "3bob2o3b2obob5o$24bo2bo2bo2bo2bo2bo2bo2bo3bo2bo2bo2bo2bo2bo2bo2bob2ob"
            "2ob2ob2ob2ob2ob2ob2o$96o$3bo3bob2o3b2obob5o3bo3bob2o3b2obob5o3bo3bob2o"
            "3b2obob5o3bo3bob2o3b2obob5o$2bo2bo2bo2bo2bo2bo2bo2b2ob2ob2ob2ob2ob2ob"
            "2ob2obob2ob2ob2ob2ob2ob2ob2ob26o$96o!";


            b0 = false;
            std::string subrule = rule;

            // Strip Generations prefix:
            if (subrule[0] == 'g') {
                subrule = subrule.substr(1);
                while ((subrule[0] >= '0') && (subrule[1] <= '9')) {
                    subrule = subrule.substr(1);
                }
            }

            if (uli_get_family(rule2int(rule)) >= 6) {
                zoi = get_zoi(rule);
            } else if ((subrule[0] == 'b') && (subrule[1] == '0')) {
                zoi = "99"; b0 = true;
            } else if (subrule[0] == 'r') {
                zoi = std::string(2 * (subrule[1] - '0'), '9');
            } else if (subrule[0] == 'b') {
                pattern transpat(lab, transrle, rule);
                bitworld bw = transpat[1].flatlayer(0);
                for (int i = 0; i < 512; i++) {
                    int x = 3 * (i & 31) + 1;
                    int y = 3 * (i >> 5) + 1;
                    transtable[i] = bw.getcell(x, y);
                }
                zoi = (diagbirth()) ? "99" : "95";
            } else {
                zoi = get_zoi(rule);
            }
        }
    };

    typedef base_classifier<1> classifier;

}
What needs to be modified so that it separates quasi-objects, but accepts pseudo-objects?
User:PK22
Learning miscellaneous programming languages.
102564
Posts: 29
Joined: October 27th, 2025, 6:32 pm

Re: Thread for your script-related questions

Post by 102564 »

Is it possible to make apgsearch not include sample soups when uploading to Catagolue?
Post Reply