Re: Script request thread
Posted: August 19th, 2021, 10:28 am
gencols, if that's what you're asking for.Cyclotrons wrote: ↑August 25th, 2021, 12:12 pmWould anyone mind writing a spaceship collision stdin script for INT rules?
Indeed, Paul Tooke's modification allows INT rules using Hensel notation. You don't need to follow the steps in the first post. Just download the attached .zip file.
Code: Select all
.*
**
.*
Code: Select all
*!*.*!**!
..*!*.*!.**!
Code: Select all
./gencols -rule B3/S2-i34q -pat t-W.life g-SW-SE.list -nph 4 -tc 10 14 -gen 300 -leq 8 -filt ag | ./makematrix > gt.life
Code: Select all
x = 459, y = 60, rule = B3/S2-i34q
5bo52bo42bo51bo52bo44bo54bobo41bo50bo49bo$5bobo48b2o42bo51bo52bo44bo
55b2o43b2o49bo49bo$5b2o50b2o41b3o49b3o50b3o42b3o54bo42b2o48b3o47b3o$
360bo$359b2o$51bo308bo$bo48b2o149bo99bo$2o49bo49bo49bo48b2o98b2o104bo$
bo98b2o48b2o49bo49bo49bo103b2o51bo$101bo49bo98b2o154bo50b2o$251bo206bo
40$obo47bobo$b2o48b2o$bo49bo$10bo$9b2o$10bo2$59bo$58b2o$59bo!
Code: Select all
The life collision search program "gencols" takes all of its input from
command-line arguments and from files specified in this arguments.
For examples of its use, see the file "Examples", which is also an
executable C-shell script that will produce files suitable for viewing
with Xlife.
Arguments for basic two-object collisions:
-----------------------------------------
The term "product" denotes the pattern that exists after the collision.
-pat <file1> <file2> :
file1 contains a pattern or a list of patterns to try as pattern 1
file2 contains a pattern or a list of patterns to try as pattern 2
The format of a single pattern is either a simple character map in
which '.' is dead and '*' is alive, or else a list of cell coordinates.
A list of patterns contains one pattern per line, stored as character
maps in which '!' is equivalent to a carriage return.
-nph #phases :
Try phase differences of 0,...,#phases-1.
A phase difference of k means that pattern 2 has been generated
k steps, while pattern 1 has been left in its initial form.
-tc #gen1 #gen2:
First collision occurs in range generation #gen1 to generation #gen2.
Note: the patterns are considered to be in generation 1 initially.
(A "collision" is an event such that there exists a single cell with
neighbors both in pattern 1 and in pattern 2. Thus, there are instances
in which patterns "collide" but do not affect each other. These can
be selected for output, and are actually useful for finding objects that
pass close to each other.)
-gen #gen :
Simulate collision to find product at generation #gen.
Pattern-deletion options:
------------------------
-del1 :
Attempt to delete pattern 1 from product. Either it will be
removed from the product or failure will be flagged.
-del2 :
Attempt to delete pattern 2 from product. Either it will be
removed from the product or failure will be flagged.
Special-purpose options:
-----------------------
The options below require some analysis of the patterns that will be collided.
-test1 <file>:
Attempt to delete pattern in file from product. Either it will be
removed from the product or failure will be flagged. See example:
"# lwss spark converts b-heptomino into p20 puffer engine"
-test2 <file>:
Attempt to delete pattern in file from product. Also match the phase of
this pattern with pattern 2. Either it will be removed from the
product or failure will be flagged.
Note: -test1 and -test2 will only succeed if test pattern is located at
the same translation position given in specified file.
-nosynch :
Normally when a pattern is to be deleted with -del1, -del2, -test1,
or -test2, it is generated alone to match the final generation of
the product to be tested. The -nosynch option eliminates this
synchronization step, which can destroy an unstablized oscillator
such as a queenbee shuttle. As a result, the number given for the
-gen option must be 1+p, where p is the period of the resulting
stabilized oscillator. (Used in examples that stabilize one end of a
shuttle.)
-genafter #steps :
Generate product for #steps steps after attempting deletions.
The result will be the product tested in the output filters.
May sometimes help to eliminate sparks and allow idenitification
of gliders, spaceships, etc.
Output filters:
--------------
-leq #cells
Only output products with population <= #cells
-geq #cells
Only output products with population >= #cells
-filt <filterstring>
Select products according to filter string, as follows:
A particular selection criterion is activated by including the
corresponding character from the table below:
p: PERIODIC (low-period oscillator or spaceship)
a: APERIODIC (no periodicity or too high to detect)
1: PERIOD1 (still-life)
2: PERIOD2 (period-2 oscillator)
3: PERIOD3 (period-3 oscillator)
4: PERIOD4 (period-4 oscillator or spaceship)
g: GLIDER (glider or several in same direction)
s: SPACESHIP (spaceship or several in same direction)
n: NOINTERACTION (patterns do not affect each other)
f: FAILURE (deletion failed assumes -del# or -test#)
For example:
-filt p (output periodic products)
-filt a (output aperiodic products)
-filt 12 (output still-life and period-2 products)
-filt gs (output gliders and spaceships)
-filt n (output collisions that come close and pass by)
-filt ap (output collisions in which the patterns
affect each other, and deletions succeed)
No, I was looking for any of the 3 small ships, and I was not looking for the p160 oscillator. The "-leq 8" filter was meant to catch the non-glider c/4 diagonal ship, as its maximum population is 8. the "-filt ag" filter was meant to eliminate low-period (less than or equal to 4) constellations. I don't see an easy way to avoid finding the p160 without also potentially missing some collisions that produce a small spaceship.
Code: Select all
--Script by dani, Aug 31 2021
--This script determines the canonical apgcode of a pattern. To use, create a blank layer with the object you want to get the apgcode of and run the script.
--Make sure the object you are running is in a fully evolved form and not a predecessor.
--You can copy the output by hitting Ctrl-C on the message box.
--There is currently a bug where if you undo after running the script, the selection used by the script reappears. You can fix this by deselecting after running the script.
local g = golly()
function pattern_to_apgcode() --Generates an apgcode of a pattern in its current orientation
local box = g.getrect()
local letters = "0123456789abcdefghijklmnopqrstuvwxyz"
local apgcode = ""
local count = 0
for y = box[2], box[2] + box[4] - 1, 5 do
for x = box[1], box[1] + box[3] - 1 do
total = 1
for cell = 0, 4 do
total = total + 2^cell * g.getcell(x, y + cell)
end
if total ~= 1 then
if count > 0 then
for space = count, 1, -39 do
if space == 1 then
apgcode = apgcode .. "0"
elseif space == 2 then
apgcode = apgcode .. "w"
elseif space == 3 then
apgcode = apgcode .. "x"
elseif space > 38 then
apgcode = apgcode .. "yz"
else
apgcode = apgcode .. "y" .. string.sub(letters, space - 3, space - 3)
end
end
count = 0
end
apgcode = apgcode .. string.sub(letters, total, total)
else
count = count + 1
end
end
apgcode = apgcode .. "z"
count = 0
end
return string.sub(apgcode, 1, -2) --Remove final z
end
function canonicalize_apgcode() --Generates a "canonical" apgcode using pattern_to_apgcode; having the shortest length and alphabetically earliest string. Also adds header
local header
local old = g.getcells(g.getrect())
local hashes = {}
local period = 0
--Determine period
while true do
local hash = g.hash(g.getrect())
if hashes[hash] then
break
end
hashes[hash] = true
period = period + 1
g.run(1)
end
g.putcells(old, 0, 0, 1, 0, 0, 1, "xor") --XOR pattern to see if it moved
--Determine header
if period == 1 then
header = "xs" .. #old // 2
elseif tonumber(g.getpop()) == 0 then
header = "xp" .. period
else
header = "xq" .. period
end
g.reset()
--Determine canonical apgcode. This might actually be able to be combined with the determine period loop but I don't see an obvious way to do that
local apgcodes = {}
local minimum_length = string.len(pattern_to_apgcode())
for step = 0, period - 1 do
g.select(g.getrect())
for flip = 0, 1 do
for rot = 0, 3 do
local apgcode = pattern_to_apgcode()
local length = string.len(apgcode)
if length == minimum_length then
table.insert(apgcodes, apgcode)
elseif length < minimum_length then
apgcodes = {apgcode}
minimum_length = length
end
g.rotate(0)
end
g.flip(0)
end
g.run(1)
end
table.sort(apgcodes)
g.reset()
g.select({})
return header .. "_" .. apgcodes[1]
end
if g.empty() then
g.exit("No pattern provided.")
end
g.getstring("Canonical apgcode:", canonicalize_apgcode())
I decided to do it myself instead.Cyclotrons wrote: ↑August 25th, 2021, 12:12 pmWould anyone mind writing a spaceship collision stdin script for INT rules? It would take an RLE, a rule, the number of spaceships to collide, and maybe a symmetry as inputs, preferably upon compilation, and would generate a random (preferably valid) n-spaceship soup when run. It should at least be able to determine whether a ship's slope is orthogonal or diagonal (oblique slopes would be nice as well), but having the slope as input is acceptable as well.
Code: Select all
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <new>
#include <string.h>
#include <string>
#include <vector>
#include <time.h>
#include <random>
using namespace std;
string intlookup[51][11] = { {"0","f","f", "00000000", "00000000", "00000000", "00000000", "00000000", "00000000", "00000000", "00000000"},{"1c","f","f", "10000000", "00000100", "00000001", "00100000", "00000001", "10000000", "00100000", "00000100"},{"1e","f","f", "00010000", "00000010", "00001000", "01000000", "00000010", "01000000", "00001000", "00010000"},{"2c","f","f", "10000100", "00000101", "00100001", "10100000", "00000101", "10100000", "00100001", "10000100"},{"2e","f","f", "01010000", "00010010", "00001010", "01001000", "00001010", "01010000", "01001000", "00010010"},{"2k","f","f", "10000010", "00001100", "01000001", "00110000", "00010001", "10001000", "00100010", "01000100"},{"2a","f","f", "10010000", "00000110", "00001001", "01100000", "00000011", "11000000", "00101000", "00010100"},{"2i","f","f","01000010","00011000","01000010","00011000","01000010","00011000","01000010","00011000"},{"2n","f","f", "10000001", "00100100", "10000001", "00100100", "10000001", "10000001", "00100100", "00100100"},{"3c","f","f", "10100100", "10000101", "00100101", "10100001", "00100101", "10100100", "10100001", "10000101"},{"3e","f","f", "01010010", "00011010", "01001010", "01011000", "00011010", "01011000", "01001010", "01010010"},{"3k","f","f", "10001010", "01001100", "01010001", "00110010", "01010001", "10001010", "00110010", "01001100"},{"3a","f","f", "11010000", "00010110", "00001011", "01101000", "00001011", "11010000", "01101000", "00010110"},{"3i","f","f", "11100000", "10010100", "00000111", "00101001", "00101001", "10010100", "11100000", "00000111"},{"3n","f","f", "11000100", "00010101", "00100011", "10101000", "00001101", "10110000", "01100001", "10000110"},{"3y","f","f", "10001100", "01000101", "00110001", "10100010", "01000101", "10100010", "00110001", "10001100"},{"3q","f","f", "10010001", "00100110", "10001001", "01100100", "10000011", "11000001", "00101100", "00110100"},{"3j","f","f", "11001000", "01010100", "00010011", "00101010", "01001001", "10010010", "01110000", "00001110"},{"3r","f","f", "11000010", "00011100", "01000011", "00111000", "00011001", "10011000", "01100010", "01000110"},{"4c","f","f", "10100101", "10100101", "10100101", "10100101", "10100101", "10100101", "10100101", "10100101"},{"4e","f","f", "01011010", "01011010", "01011010", "01011010", "01011010", "01011010", "01011010", "01011010"},{"4k","f","f", "10110010", "10001110", "01001101", "01110001", "00110011", "11001100", "10101010", "01010101"},{"4a","f","f", "11110000", "10010110", "00001111", "01101001", "00101011", "11010100", "11101000", "00010111"},{"4i","f","f", "11000110", "00011101", "01100011", "10111000", "00011101", "10111000", "01100011", "11000110"},{"4n","f","f", "11100100", "10010101", "00100111", "10101001", "00101101", "10110100", "11100001", "10000111"},{"4y","f","f", "10101100", "11000101", "00110101", "10100011", "01100101", "10100110", "10110001", "10001101"},{"4q","f","f", "11010001", "00110110", "10001011", "01101100", "10001011", "11010001", "01101100", "00110110"},{"4j","f","f", "11001010", "01011100", "01010011", "00111010", "01011001", "10011010", "01110010", "01001110"},{"4r","f","f", "11010010", "00011110", "01001011", "01111000", "00011011", "11011000", "01101010", "01010110"},{"4t","f","f", "11100010", "10011100", "01000111", "00111001", "00111001", "10011100", "11100010", "01000111"},{"4w","f","f", "11001001", "01110100", "10010011", "00101110", "11001001", "10010011", "01110100", "00101110"},{"4z","f","f", "10011001", "01100110", "10011001", "01100110", "11000011", "11000011", "00111100", "00111100"},{"5c","f","f", "01111010", "11011010", "01011110", "01011011", "01111010", "01011110", "11011010", "01011011"},{"5e","f","f", "10101101", "11100101", "10110101", "10100111", "11100101", "10100111", "10110101", "10101101"},{"5k","f","f", "01110101", "10110011", "10101110", "11001101", "10101110", "01110101", "11001101", "10110011"},{"5a","f","f", "00101111", "11101001", "11110100", "10010111", "11110100", "00101111", "10010111", "11101001"},{"5i","f","f", "00011111", "01101011", "11111000", "11010110", "11010110", "01101011", "00011111", "11111000"},{"5n","f","f", "00111011", "11101010", "11011100", "01010111", "11110010", "01001111", "10011110", "01111001"},{"5y","f","f", "01110011", "10111010", "11001110", "01011101", "10111010", "01011101", "11001110", "01110011"},{"5q","f","f", "01101110", "11011001", "01110110", "10011011", "01111100", "00111110", "11010011", "11001011"},{"5j","f","f", "00110111", "10101011", "11101100", "11010101", "10110110", "01101101", "10001111", "11110001"},{"5r","f","f", "00111101", "11100011", "10111100", "11000111", "11100110", "01100111", "10011101", "10111001"},{"6c","f","f", "01111011", "11111010", "11011110", "01011111", "11111010", "01011111", "11011110", "01111011"},{"6e","f","f", "10101111", "11101101", "11110101", "10110111", "11110101", "10101111", "10110111", "11101101"},{"6k","f","f", "01111101", "11110011", "10111110", "11001111", "11101110", "01110111", "11011101", "10111011"},{"6a","f","f", "01101111", "11111001", "11110110", "10011111", "11111100", "00111111", "11010111", "11101011"},{"6i","f","f", "11100111", "10111101", "11100111", "10111101", "10111101", "10111101", "11100111", "11100111"},{"6n","f","f", "01111110", "11011011", "01111110", "11011011", "01111110", "01111110", "11011011", "11011011"},{"7c","f","f", "01111111", "11111011", "11111110", "11011111", "11111110", "01111111", "11011111", "11111011"},{"7e","f","f", "11101111", "11111101", "11110111", "10111111", "11111101", "10111111", "11110111", "11101111"},{"8","f","f", "11111111", "11111111", "11111111", "11111111", "11111111", "11111111", "11111111", "11111111"} };
mt19937 rng;
//sets the rule by parsing the provided rulestring and updating intlookup
void set_rule(string rulestring)
{
int bors = 1; //birth is 1, survival is 2
string currentNum = "";
string currentChar = "";
bool setToFalse = false;
string nums = "012345678";
string chars = "cekainyqjrtwz";
for (int i = 0; i < rulestring.length(); i++)
{
if (rulestring[i] == '8')
{
intlookup[50][bors] = "t";
}
else if (nums.find(rulestring[i]) >= 0 && nums.find(rulestring[i]) < 9)
{
currentNum = rulestring.substr(i, 1);
setToFalse = false;
if (rulestring[i + 1] == '-')
{
setToFalse = true;
for (int j = 0; j < 51; j++)
{
if (intlookup[j][0][0] == currentNum[0])
{
intlookup[j][bors] = "t";
}
}
}
else if ((nums.find(rulestring[i + 1]) > 0 && nums.find(rulestring[i + 1]) < 9) || rulestring[i+1] == '/' || rulestring[i+1] == 's' || rulestring[i + 1] == 'S' || rulestring[i + 1] == '\0')
{
for (int j = 0; j < 51; j++)
{
if (intlookup[j][0][0] == currentNum[0])
{
intlookup[j][bors] = "t";
}
}
}
}
else if (chars.find(rulestring[i]) >= 0 && chars.find(rulestring[i]) < 13)
{
currentChar = rulestring.substr(i, 1);
for (int j = 0; j < 51; j++)
{
if (strcmp(intlookup[j][0].c_str(), (currentNum + currentChar).c_str()) == 0)
{
if (setToFalse)
{
intlookup[j][bors] = "f";
}
else
{
intlookup[j][bors] = "t";
}
}
}
}
else if (rulestring[i] == 'S' || rulestring[i] == 's')
{
bors = 2;
}
}
}
//converts a provided rle to a cell list (note: cell list format is {x0,y0,x1,y1...})
void rle_to_clist(vector<int>& target, string rle)
{
int xpos = 0;
int ypos = 0;
int begin = 0;
int end = 0;
string currentstr = "";
int len = 0;
while (end != -1)
{
end = rle.find_first_of("bo$", begin) + 1;
if (end == 0)
{
end = -1;
}
if (end != -1)
{
currentstr = rle.substr(begin, end - begin);
len = currentstr.length();
begin = end;
}
if (len > 1 && end != -1)
{
if (strcmp(currentstr.substr(len - 1, len).c_str(), "o") == 0)
{
for (int i = 0; i < atoi(currentstr.substr(0, len - 1).c_str()); i++)
{
target.push_back(xpos + i);
target.push_back(ypos);
}
}
if (strcmp(currentstr.substr(len - 1, len).c_str(), "$") == 0)
{
ypos = ypos + atoi(currentstr.substr(0, len - 1).c_str());
xpos = 0;
}
else
{
xpos = xpos + atoi(currentstr.substr(0, len - 1).c_str());
}
}
else if (end != -1)
{
if (strcmp(currentstr.c_str(), "o") == 0)
{
target.push_back(xpos);
target.push_back(ypos);
}
if (strcmp(currentstr.c_str(), "$") == 0)
{
ypos++;
xpos = 0;
}
else
{
xpos++;
}
}
}
}
//checks if the cell at the provided coordinates is in a cell list
string get_state(int xpos, int ypos, vector<int>& clist)
{
for (int i = 0; i < clist.size(); i = i + 2)
{
if (clist[i] == xpos && clist[i + 1] == ypos)
{
return "1";
}
}
return "0";
}
//takes a cell list as an argument and returns another cell list advanced by one generation in the rule
vector<int> evolve_clist(vector<int> current)
{
vector<int> newclist;
int minx = current[0];
int miny = current[1];
int maxx = current[0];
int maxy = current[1];
string currentNeighborhood = "";
for (int i = 0; i < current.size(); i = i + 2)
{
if (current[i] < minx)
{
minx = current[i];
}
else if (current[i] > maxx)
{
maxx = current[i];
}
if (current[i + 1] < miny)
{
miny = current[i + 1];
}
else if (current[i + 1] > maxy)
{
maxy = current[i + 1];
}
}
for (int y = miny - 1; y <= maxy + 1; y++)
{
for (int x = minx - 1; x <= maxx + 1; x++)
{
currentNeighborhood = get_state(x - 1, y - 1, current) + get_state(x, y - 1, current) + get_state(x + 1, y - 1, current) + get_state(x - 1, y, current) + get_state(x + 1, y, current) + get_state(x - 1, y + 1, current) + get_state(x, y + 1, current) + get_state(x + 1, y + 1, current);
for (int i = 0; i < 51; i++)
{
if (strcmp(get_state(x, y, current).c_str(), "0") == 0 && strcmp(intlookup[i][1].c_str(), "t") == 0)
{
for (int j = 3; j < 11; j++)
{
if (strcmp(currentNeighborhood.c_str(), intlookup[i][j].c_str()) == 0)
{
newclist.push_back(x);
newclist.push_back(y);
break;
}
}
}
else if (strcmp(get_state(x, y, current).c_str(), "1") == 0 && strcmp(intlookup[i][2].c_str(), "t") == 0)
{
for (int j = 3; j < 11; j++)
{
if (strcmp(currentNeighborhood.c_str(), intlookup[i][j].c_str()) == 0)
{
newclist.push_back(x);
newclist.push_back(y);
break;
}
}
}
}
}
}
return newclist;
}
//checks if two cell lists are equivalent
bool equivalent(vector<int> current, vector<int> base, int &dx, int &dy)
{
if (current.size() != base.size())
{
return false;
}
vector<int> translated;
int diffx = current[0] - base[0];
int diffy = current[1] - base[1];
for (int i = 0; i < current.size(); i = i + 2)
{
translated.push_back(current[i] - diffx);
translated.push_back(current[i + 1] - diffy);
}
for (int i = 0; i < translated.size(); i++)
{
if (translated[i] != base[i])
{
return false;
}
}
dx = diffx;
dy = diffy;
return true;
}
//alters the provided cell list so that it's center is at (0,0)
void normalize(vector<int> &target)
{
int minx = target[0];
int miny = target[1];
int maxx = target[0];
int maxy = target[1];
for (int i = 0; i < target.size(); i = i + 2)
{
if (target[i] < minx)
{
minx = target[i];
}
else if (target[i] > maxx)
{
maxx = target[i];
}
if (target[i + 1] < miny)
{
miny = target[i + 1];
}
else if (target[i + 1] > maxy)
{
maxy = target[i + 1];
}
}
int centerx = (minx + maxx) / 2;
int centery = (miny + maxy) / 2;
for (int i = 0; i < target.size(); i = i + 2)
{
target[i] = target[i] - centerx;
target[i + 1] = target[i + 1] - centery;
}
}
//rotates a target cell list 90 degrees clockwise around (0,0)
void crot(vector<vector<int>> &target, int numRots)
{
int currentx = 0;
int currenty = 0;
for (int r = 0; r < numRots % 4; r++)
{
for (int j = 0; j < target.size(); j++)
{
for (int i = 0; i < target[j].size(); i = i + 2)
{
currentx = target[j][i];
currenty = target[j][i + 1];
target[j][i] = 0 - currenty;
target[j][i + 1] = currentx;
}
}
}
}
//reflects a target cell list either over the y-axis or over the x-axis
void refl(vector<vector<int>> &target, bool horizontal, bool vertical)
{
int h = 1;
int v = 1;
if (horizontal)
{
h = -1;
}
if (vertical)
{
v = -1;
}
for (int j = 0; j < target.size(); j++)
{
for (int i = 0; i < target[j].size(); i = i + 2)
{
target[j][i] = target[j][i] * h;
target[j][i + 1] = target[j][i + 1] * v;
}
}
}
//gets a range between 2 numbers (inclusive)
int rand_range(int minNum, int maxNum)
{
if (minNum == maxNum)
{
return minNum;
}
return rng() % (maxNum - minNum) + minNum;
}
//generates the parameters needed to place a glider
void generate_glider(int* target, int minDistance, int maxDistance, int displacementScale, int maxOffset, int gens, int dx, int dy)
{
//format: {x,y,xoffset,yoffset,gen}
int displacement;
int temp;
target[0] = rand_range(minDistance, maxDistance);
if (dx == 0 || dy == 0)
{
target[1] = rand_range(0 - (target[0] / displacementScale), target[0] / displacementScale);
}
else if (dx == dy)
{
target[1] = target[0];
displacement = rand_range(0 - (target[0] / displacementScale), target[0] / displacementScale);
target[0] = target[0] + displacement;
target[1] = target[1] - displacement;
}
else
{
target[1] = target[0] * 2;
displacement = rand_range(0 - (target[0] / displacementScale), target[0] / displacementScale);
target[0] = target[0] + displacement;
target[1] = target[1] - displacement * 2;
if (target[1] > maxDistance || target[1] < 0 - maxDistance)
{
target[0] = target[0] / 2;
target[1] = target[1] / 2;
}
}
if (target[0] > maxDistance || target[0] < 0 - maxDistance)
{
target[0] = maxDistance;
}
if (target[1] > maxDistance || target[1] < 0 - maxDistance)
{
target[1] = maxDistance;
}
if (rng() % 2 == 0)
{
target[0] = 0 - target[0];
}
if (rng() % 2 == 0)
{
target[1] = 0 - target[1];
}
for (int i = 0; i < rng() % 4; i++)
{
temp = target[0];
target[0] = 0 - target[1];
target[1] = temp;
}
target[2] = rand_range(0 - maxOffset, maxOffset);
target[3] = rand_range(0 - maxOffset, maxOffset);
target[4] = rng() % gens;
}
void glider_coords(int* glider, int* coords)
{
//format: {x0,y0,x1,y1...}
int currentpos = 0;
coords[0] = glider[0];
coords[1] = glider[1];
coords[2] = 0; coords[3] = 0; coords[4] = 0; coords[5] = 0; coords[6] = 0; coords[7] = 0;
currentpos = 2;
if (glider[2] > 0)
{
coords[currentpos] = glider[0] + 1;
coords[currentpos + 1] = glider[1];
currentpos = currentpos + 2;
}
else if (glider[2] < 0)
{
coords[currentpos] = glider[0] - 1;
coords[currentpos + 1] = glider[1];
currentpos = currentpos + 2;
}
if (glider[3] > 0)
{
coords[currentpos] = glider[0];
coords[currentpos + 1] = glider[1] + 1;
currentpos = currentpos + 2;
}
else if (glider[3] < 0)
{
coords[currentpos] = glider[0];
coords[currentpos + 1] = glider[1] - 1;
currentpos = currentpos + 2;
}
if (glider[2] > 0 && glider[3] > 0)
{
coords[currentpos] = glider[0] + 1;
coords[currentpos + 1] = glider[1] + 1;
}
else if (glider[2] > 0 && glider[3] < 0)
{
coords[currentpos] = glider[0] + 1;
coords[currentpos + 1] = glider[1] - 1;
}
else if (glider[2] < 0 && glider[3] < 0)
{
coords[currentpos] = glider[0] - 1;
coords[currentpos + 1] = glider[1] - 1;
}
else if (glider[2] < 0 && glider[3] > 0)
{
coords[currentpos] = glider[0] - 1;
coords[currentpos + 1] = glider[1] + 1;
}
}
int main(int argc, char* argv[])
{
rng.seed(time(NULL));
string gliderRLE = "null";
string rulestring = "null";
int numSoups = -1;
int minDistanceFromCenter = 1;
int maxDistanceFromCenter = 5;
int displacementScale = 2;
int numGliders = -1;
int maxGen = 1000;
bool displayHelp = false;
//parsing provided arguments
for (int i = 1; i < argc - 1; i++)
{
if (strcmp(argv[i], "-g") == 0)
{
gliderRLE = argv[i + 1];
}
else if (strcmp(argv[i], "-r") == 0)
{
rulestring = argv[i + 1];
}
else if (strcmp(argv[i], "-n") == 0)
{
numGliders = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-t") == 0)
{
numSoups = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-dmin") == 0)
{
minDistanceFromCenter = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-dmax") == 0)
{
maxDistanceFromCenter = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-dscale") == 0)
{
displacementScale = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-gmax") == 0)
{
maxGen = atoi(argv[i + 1]);
}
else if (strcmp(argv[i], "-h") == 0)
{
cout << "This program generates soups composed of a provided spaceship and outputs an RLE of said soup." << endl;
cout << "Required arguments:" << endl;
cout << "\t-g: The RLE of the spaceship on every generation. The RLE must be headerless." << endl;
cout << "\t-r: The rule the spaceship is from. Make sure the input RLE is actually a glider in the input rule!" << endl;
cout << "\t-n: The number of spaceships to be in each soup." << endl;
cout << "\t-t: How many soups to output. If you're piping the output into apgsearch, you'll want to set this to 0, which will generate soups indefinitely." << endl;
cout << "Other arguments:" << endl;
cout << "\t-dmin: The minimum distance (measured in spaceships) from the center a ship can be. The default is 2, and it is recommended that it be left unchanged." << endl;
cout << "\t-dmax: The minimum distance (measured in spaceships) from the center a ship can be. The default is 5. Set this higher if you are testing a lot of spaceships." << endl;
cout << "\t-dscale: Used to calculate a spaceships displacement from the line all ships going in the same direction are placed on. Set this higher if you want ships to be less displaced. The default is 2." << endl;
cout << "\t-gmax: The number of generations the given pattern will be run to check periodicity before this program gives up and terminates. Only change this if your ship has a very high period! The default is 1000." << endl;
cout << "\t-h: Prints this message, then exits." << endl;
return 0;
}
}
//checking that all required arguments are passed
if (strcmp(gliderRLE.c_str(), "null") == 0)
{
cout << "You must enter an RLE! Bring up the help message using the argument '-h 1' for more information." << endl;
return 0;
return 0;
}
if (strcmp(rulestring.c_str(), "null") == 0)
{
cout << "You must enter a rule! Bring up the help message using the argument '-h 1' for more information." << endl;
return 0;
}
if (numGliders == -1)
{
cout << "You must enter the number of gliders to include in a soup! Bring up the help message using the argument '-h 1' for more information." << endl;
return 0;
}
if (numSoups == -1)
{
cout << "You must enter a number of soups to generate! Bring up the help message using the argument '-h 1' for more information." << endl;
return 0;
}
//some more input filtering
if (numGliders < -1)
{
cout << "You entered a negative value!" << endl;
return 0;
}
if (numSoups < -1)
{
cout << "You entered a negative value!" << endl;
return 0;
}
if (minDistanceFromCenter < 0)
{
cout << "You entered a negative value!" << endl;
return 0;
}
if (maxDistanceFromCenter < 0)
{
cout << "You entered a negative value!" << endl;
return 0;
}
if (displacementScale < 0)
{
cout << "You entered a negative value!" << endl;
return 0;
}
if (maxGen < 0)
{
cout << "You entered a negative value!" << endl;
return 0;
}
set_rule(rulestring);
//stuff to fully characterize the glider
vector<int> initClist;
vector<vector<int>> initGlider;
rle_to_clist(initClist, gliderRLE);
initGlider.push_back(initClist);
int dx;
int dy;
int tempcount = 0;
while (!equivalent(evolve_clist(initGlider.back()), initClist, dx, dy))
{
initGlider.push_back(evolve_clist(initGlider.back()));
tempcount++;
if (tempcount > maxGen)
{
cout << "Failed to detect periodicity in " << maxGen << " generations. This is (probably) not a spaceship." << endl;
return 0;
}
}
for (int i = 0; i < initGlider.size(); i++)
{
normalize(initGlider[i]);
}
if (dx == 0 && dy == 0)
{
cout << "This is not a spaceship!" << endl;
return 0;
}
//gets all rotations + reflections of glider
vector<vector<int>> nNW; //-1,-2 x>y,x<0,y<0,ax<ay
vector<vector<int>> nne; //1,-2 x>y,x>0,y<0,ax<ay
vector<vector<int>> NEe; //2,-1 x>y,x>0,y<0,ax>ay
vector<vector<int>> see; //2,1 x>y,x>0,y>0,ax>ay
vector<vector<int>> sSE; //1,2 x<y,x>0,y>0,ax<ay
vector<vector<int>> ssw; //-1,2 x<y,x<0,y>0,ax<ay
vector<vector<int>> SWw; //-2,1 x<y,x<0,y>0,ax>ay
vector<vector<int>> nww; //-2,-1 x<y,x<0,y<0,ax>ay
if (dx >= 0 && dy >= 0)
{
if (dx >= dy)
{
see = initGlider;
nNW = see;
crot(nNW, 1);
refl(nNW, false, true);
}
else if (dx < dy)
{
sSE = initGlider;
nNW = sSE;
crot(nNW, 2);
}
}
else if (dx >= 0 && dy < 0)
{
if (dx >= 0 - dy)
{
NEe = initGlider;
nNW = NEe;
crot(nNW, 3);
}
else if (dx < 0 - dy)
{
nne = initGlider;
nNW = nne;
refl(nNW, true, false);
}
}
else if (dx < 0 && dy < 0)
{
if (0 - dx >= 0 - dy)
{
nww = initGlider;
nNW = nww;
crot(nNW, 1);
refl(nNW, true, false);
}
else if (0 - dx < 0 - dy)
{
nNW = initGlider;
}
}
else if (dx < 0 && dy >= 0)
{
if (0 - dx >= dy)
{
SWw = initGlider;
nNW = SWw;
crot(nNW, 1);
}
else if (0 - dx < dy)
{
ssw = initGlider;
nNW = ssw;
refl(nNW, false, true);
}
}
NEe = nNW;
crot(NEe, 1);
sSE = nNW;
crot(sSE, 2);
SWw = nNW;
crot(SWw, 3);
nne = nNW;
refl(nne, true, false);
see = nne;
crot(see, 1);
ssw = nne;
crot(ssw, 2);
nww = nne;
crot(nww, 3);
//getting the glider's max span
int minx;
int miny;
int maxx;
int maxy;
int bigx = 0;
int bigy = 0;
for (int j = 0; j < initGlider.size(); j++)
{
minx = initGlider[j][0];
miny = initGlider[j][1];
maxx = initGlider[j][0];
maxy = initGlider[j][1];
for (int i = 0; i < initGlider[j].size(); i = i + 2)
{
if (initGlider[j][i] < minx)
{
minx = initGlider[j][i];
}
else if (initGlider[j][i] > maxx)
{
maxx = initGlider[j][i];
}
if (initGlider[j][i + 1] < miny)
{
miny = initGlider[j][i + 1];
}
else if (initGlider[j][i + 1] > maxy)
{
maxy = initGlider[j][i + 1];
}
}
if (maxx - minx > bigx)
{
bigx = maxx - minx;
}
if (maxy - miny > bigy)
{
bigy = maxy - miny;
}
}
int gliderSize = 0;
if (bigx > bigy)
{
gliderSize = bigx + 1;
}
else
{
gliderSize = bigy + 1;
}
//getting absolute values of dx and dy
if (dx < 0)
{
dx = 0 - dx;
}
if (dy < 0)
{
dy = 0 - dy;
}
//some final initialization before the main loop
bool** mainSoup = new bool* [(gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2)];
for (int i = 0; i < (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2); i++)
{
mainSoup[i] = new bool[(gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2)];
}
int* takenCoords = new int[numGliders * 4 * 2];
int* gliderList = new int[numGliders * 5];
int tempGlider[5];
int tempCoords[8];
int offset = gliderSize / 2;
int gliderGens = initGlider.size();
int gliderCount;
bool isTaken;
vector<vector<int>>* gptr = &nNW;
string rle;
string temprle;
int currentNum;
char currentChar;
int minxsoup;
bool hasHit;
int zeroPoint = ((gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2)) / 2;
int soupCount = 0;
while (soupCount < numSoups || numSoups == 0)
{
//resetting some values...
for (int y = 0; y < (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2); y++)
{
for (int x = 0; x < (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2); x++)
{
mainSoup[y][x] = false;
}
}
for (int i = 0; i < numGliders * 4 * 2; i++)
{
takenCoords[i] = 0;
}
for (int i = 0; i < numGliders * 5; i++)
{
gliderList[i] = 0;
}
//generates glider positions, does basic validation
gliderCount = 0;
while (gliderCount < numGliders)
{
isTaken = false;
generate_glider(tempGlider, minDistanceFromCenter, maxDistanceFromCenter, displacementScale, offset, gliderGens, dx, dy);
glider_coords(tempGlider, tempCoords);
for (int i = 0; i < numGliders * 4 * 2; i = i + 2)
{
if (tempCoords[0] == takenCoords[i] && tempCoords[1] == takenCoords[i + 1])
{
isTaken = true;
break;
}
}
if (isTaken)
{
continue;
}
for (int i = 0; i < 8; i++)
{
takenCoords[gliderCount * 2 * 4 + i] = tempCoords[i];
}
for (int i = 0; i < 5; i++)
{
gliderList[gliderCount * 5 + i] = tempGlider[i];
}
gliderCount++;
}
//places gliders on a grid
for (int i = 0; i < numGliders * 5; i = i + 5)
{
if (gliderList[i] >= 0 && gliderList[i + 1] >= 0)
{
if (gliderList[i] >= gliderList[i + 1])
{
gptr = &nww;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
else if (gliderList[i] < gliderList[i + 1])
{
gptr = &nNW;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
}
else if (gliderList[i] >= 0 && gliderList[i + 1] < 0)
{
if (gliderList[i] >= 0 - gliderList[i + 1])
{
gptr = &SWw;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
else if (gliderList[i] < 0 - gliderList[i + 1])
{
gptr = &ssw;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
}
else if (gliderList[i] < 0 && gliderList[i + 1] < 0)
{
if (0 - gliderList[i] >= 0 - gliderList[i + 1])
{
gptr = &see;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
else if (0 - gliderList[i] < 0 - gliderList[i + 1])
{
gptr = &sSE;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
}
else if (gliderList[i] < 0 && gliderList[i + 1] >= 0)
{
if (0 - gliderList[i] >= gliderList[i + 1])
{
gptr = &NEe;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
else if (0 - gliderList[i] < gliderList[i + 1])
{
gptr = &nne;
//cout << gliderList[i] << " " << gliderList[i + 1] << endl;
}
}
for (int j = 0; j < gptr[0][gliderList[i + 4]].size(); j = j + 2)
{
//ypos = cell y on gen gliderList[i+4] in position [j+1] + gliderbox * glider y pos + y offset
mainSoup[(gptr[0][gliderList[i + 4]][j + 1] + (gliderSize + 2) * gliderList[i + 1] + gliderList[i + 3]) + zeroPoint][(gptr[0][gliderList[i + 4]][j] + (gliderSize + 2) * gliderList[i] + gliderList[i + 2]) + zeroPoint] = true;
}
}
temprle = "";
rle = "";
minxsoup = (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2);
for (int y = 0; y < (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2); y++)
{
for (int x = 0; x < (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2); x++)
{
if (mainSoup[y][x] && x < minxsoup)
{
minxsoup = x;
}
}
}
for (int y = (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2) - 1; y >= 0; y--)
{
hasHit = false;
temprle = "$" + temprle;
for (int x = (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2) - 1; x >= minxsoup; x--)
{
if (mainSoup[y][x])
{
hasHit = true;
temprle = "o" + temprle;
}
else if (hasHit)
{
temprle = "b" + temprle;
}
}
}
currentChar = 'h';
currentNum = 1;
for (int i = 0; i <= temprle.length(); i++)
{
if (temprle[i] == currentChar)
{
currentNum++;
}
else
{
if (currentNum != 1)
{
rle = rle + to_string(currentNum);
}
if (currentChar != 'h')
{
rle = rle + currentChar;
}
currentChar = temprle[i];
currentNum = 1;
}
}
cout << "x = 0, y = 0, rule = B3/S23\n" << rle << "!" << endl;
soupCount++;
}
//cleanup
for (int i = 0; i < (gliderSize + 2) * 2 * maxDistanceFromCenter + 2 * (gliderSize + 2); i++)
{
delete[] mainSoup[i];
}
delete[] mainSoup;
delete[] takenCoords;
delete[] gliderList;
}
A rookie question: how is the compiling done for that modification? On the regular Windows Command Prompt with both gcc and g++, the following command as I would expect threw a lot of errors about undefined reference to various names.Sokwe wrote: ↑August 27th, 2021, 9:37 pmIndeed, Paul Tooke's modification allows INT rules using Hensel notation. You don't need to follow the steps in the first post. Just download the attached .zip file.
After compiling...
Code: Select all
gcc -o gencols gencols.c -O3 -Ofast -flto -march=native
I was using Ubuntu for compilation. Try compiling it without the flags and see if it works (note that it will run a lot slower without them).GUYTU6J wrote: ↑September 3rd, 2021, 5:24 amA rookie question: how is the compiling done for that modification? On the regular Windows Command Prompt with both gcc and g++, the following command as I would expect threw a lot of errors about undefined reference to various names.Sokwe wrote: ↑August 27th, 2021, 9:37 pmIndeed, Paul Tooke's modification allows INT rules using Hensel notation. You don't need to follow the steps in the first post. Just download the attached .zip file.
After compiling...Code: Select all
gcc -o gencols gencols.c -O3 -Ofast -flto -march=native
I have installed Ubuntu 16.04 LTS as my WSL, but I'm not familiar with it and I cannot either 1) find the default location of files downloaded by git clone (such as apgmera) or 2) access other locations apart from default (such as the gencols file on disk D:; it won't even find D: if I input it directly). So I used Command Prompt instead of that Ubuntu for compiling.Cyclotrons wrote: ↑September 3rd, 2021, 12:09 pmI was using Ubuntu for compilation. Try compiling it without the flags and see if it works (note that it will run a lot slower without them).GUYTU6J wrote: ↑September 3rd, 2021, 5:24 amA rookie question: how is the compiling done for that [gencols] modification? On the regular Windows Command Prompt with both gcc and g++, the following command as I would expect threw a lot of errors about undefined reference to various names.Code: Select all
gcc -o gencols gencols.c -O3 -Ofast -flto -march=native
Are you using Mingw-w64? I suspect so, since this seems to be the standard Windows port of GCC. In that case, you can compile by simply running mingw32-make.
Yes! There's an even more user-friendly version of this called findpreds, which downloads the soups, looks for the ones that take at least 50 generations to produce the object, advances the soups to generation T-50, and prunes the soup (by deleting any clusters that aren't involved in producing the desired object).Extrementhusiast wrote: ↑September 7th, 2021, 5:00 pmThis seems like the sort of thing that should already exist, but is there a script that takes an object and pastes in all Catagolue soups that create that object? It sure would beat having to copy/paste tens or hundreds of soups every time I want to perform a detailed investigation into how a particular object forms.
Code: Select all
#C soup 0 gives birth at time 177
#C soup 1 gives birth at time 1834
#CLL state-numbering golly
x = 49, y = 165, rule = B3/S23
15b2o$14bob2o$14bobo$18b2o$12b2obo4b2obo$11bo3bo4bo3bo$13b2o5b3obo
$13b3o3bo2b2o$6bo8b3o2bo$5bobo7b2o2bo$5bob2o3b2obobo$6bob3obo2b2o$
8bo3b2o3bo$2bo5bo$2ob2o4bob2o$2o6bo2bo$2obo6bobobo$3b2o9bo$3b3o4$
18b3o3$21b2o$21b2o112$45b2o$44bo2bo$44bobo$30b2o5b3o5bo$29bo2bo$
29bobo3bo$30bo4bo9b3o$35bo9b3o$44bo3bo$42bobo2bo$11bo29bo2bo$10bob
o20b2o5b3o2bo$10bobo20b2o11b2o$11bo12b2o21bo$22b2o2bo$22b2o6b2o$
25bo6bo$31b3o6b2o$31b3o5bo2bo$33b2o5b2o$31b2o$27b4o$22bo3b2o3bo$
21b2o6b2o$20bo5bo3bo$21b2o3b4o$22bo5bo!
Code: Select all
x = 36, y = 9, rule = B3/S23
26bo$26bobo$9bo17bobo$9b2o16bo2bo3b2o$4b2o4b2o15bobo4b2o$2o2b2o4b3o13b
obo$2o2b2o4b2o7bobo4bo$9b2o9b2o$9bo10bo!
Code: Select all
x = 26, y = 33, rule = B3/S23
17b3o$17b3o$17b3o$14b3o$14b3o$14b3o2$3o$3o$3o$3b3o$3b3o$3b3o5b3o$11bo$
11b3o4$12b3o$14bo$12b3o5b3o$20b3o$20b3o$23b3o$23b3o$23b3o2$9b3o$9b3o$
9b3o$6b3o$6b3o$6b3o!
Code: Select all
x = 32, y = 17, rule = B3/S23
22bo$20b3o$19bo8b2o$19b2o$27bo3bo$16b3o7bo4bo$15bo3bo5bobobo$14bo5bo3b
obobo$14bo5bobo4bo$5bo8bo5bobo3bo$15bo3bo$3b3obo8b3o5b2o$2bob2o$2b2obo
$ob3o5b2o$10b2o$2bo!
Code: Select all
x = 73, y = 54, rule = B3/S23
62b3o$62bo2bo$6b3o18b3o32bo2bo$5bo3bo16bo3bo33b2o$4bo5bo2b3o4b3o2bo5bo
$13bobo4bobo$3bo7bob3o4b3obo7bo$3bo7bo12bo7bo20b3o$52bo2bo$4bo5bo14bo
5bo20bo$5bo3bo16bo3bo21b3o15b3o$6b3o18b3o42bo$69bo2bo$69b3o4$59b2o$59b
o2bo$59bo2bo$60b3o5$10bo$10b3o$13bo$12b2o5$14b2o$14bob2o$2o12b4o$bo13b
2ob2o$bobo13b3o$2b2o13b2obo$8b3o7b3o$8bob2o13b2o27bo6b2o$9b3o13bobo26b
o6b2obo$9b2ob2o13bo25bobo9bo$11b4o12b2o25bo7bo$11b2obo39bo8bob2o$13b2o
39bo10b2o$54bo$53bobo$54bo$54bo$15b2o$15bo$16b3o$18bo!
first you will need to find a base reaction yourself. Then you might want to use bellman. but actually it's hard to find a new stable glider converter because people have tried so much.AlbertArmStain wrote: ↑February 3rd, 2022, 4:19 pmCan someone make a syringe finder?
I would really like to see a g-to-pi or g-to-r.
1) git clone clones the repo to the current directory you're in. E.g. if you're in ~ (the home directory) and you do git clone https://gitlab.com/apgoucher/apgmera.git it clones apgsearch to ~/apgmera.GUYTU6J wrote: ↑September 3rd, 2021, 12:36 pmI have installed Ubuntu 16.04 LTS as my WSL, but I'm not familiar with it and I cannot either 1) find the default location of files downloaded by git clone (such as apgmera) or 2) access other locations apart from default (such as the gencols file on disk D:; it won't even find D: if I input it directly). So I used Command Prompt instead of that Ubuntu for compiling.
Note that my original question was for the gencols — which has a mysterious Makefile that I don't know how to run — and not your new program, but I may ask a relevant question to you by the way: when generating spaceship collisions, will the script attempt to reduce the number of wasted spaceships? For instance, a Life glider heading SE is more likely to fly away from the collision region if it is put in the SE corner of the bounding box — cases like these should be taken into consideration in my opinion.
Thank you for the useful script!Cyclotrons wrote: ↑September 1st, 2021, 3:15 pmI decided to do it myself instead.[...]Cyclotrons wrote: ↑August 25th, 2021, 12:12 pmWould anyone mind writing a spaceship collision stdin script for INT rules? It would take an RLE, a rule, the number of spaceships to collide, and maybe a symmetry as inputs, preferably upon compilation, and would generate a random (preferably valid) n-spaceship soup when run. It should at least be able to determine whether a ship's slope is orthogonal or diagonal (oblique slopes would be nice as well), but having the slope as input is acceptable as well.
Code: Select all
x = 0, y = 0, rule = B3/S238
10$37bobo$40bo$40bo$37bo2bo$38b3o12$37b2o$36b3o$36b2obo$37b3o$38bo2$81bobo2bobo$80bo8bo$80bo8bo$80bo2bo2bo2bo$80b3o4b3o3$51b2o60bo2bo$4b2o11b4o30b3o58bo$3b4o9bo3bo29bob2o58bo3bo$3b2ob2o12bo29b3o47b4o8b4o$5b2o9bo2bo31bo48bo3bo$100bo$101bo2bo4$29b4o$28bo3bo$32bo$28bo2bo4$11b2o$9b2ob2o$9b4o$10b2o9$31bo2bo$22b4o9bo$21bo3bo5bo3bo$25bo6b4o$21bo2bo3$123b2o$122b2ob2o$123b4o$124b2o2$115b2o$14bo2bo96b4o$18bo94b2ob2o$14bo3bo95b2o$15b4o4$102b2o$10b2o89b2ob2o$8b2ob2o89b4o$8b4o91b2o$9b2o2$30b2o76b2o$28b2ob2o74b2ob2o$28b4o76b4o$29b2o78b2o2bo2bo$112bo$112bo3bo$112b4o9$2b2o$2ob2o$4o$b2o6$9bo2bo$13bo$9bo3bo$10b4o3$11b2o$10b4o$10b2ob2o$12b2o2$33bo$32b3o$32bob2o44b3o$33b3o44bo2bo$33b2o45bo$80bo$81bobo$10bo54bo$9b3o52b3o$8b2obo51b2obo$8b3o44bo7b3o56bo$9b2o43b3o7b2o55b3o$53b2obo63b2obo$53b3o64b3o$54b2o65b2o11$!
Code: Select all
./shipcolls -g 'b2o$3o$2obo$b3o$2bo!' -n 30 -dmin 5 -dmax 10 -dscale 1 -r b3s238 -t 0
you can make a rule where state1 can turn into any states depending on its neighbour cells, but that is pretty annoying and that is the only way i know.atavoidirc wrote: ↑July 13th, 2022, 7:03 pmmultistate-apgsearch, i;e apgsearch but the starting soup contains all possible states
Alternatively, you can use an stdin script to generate soups with all states in them — see the LifeWiki tutorial.yujh wrote: ↑July 15th, 2022, 2:54 pmyou can make a rule where state1 can turn into any states depending on its neighbour cells, but that is pretty annoying and that is the only way i know.atavoidirc wrote: ↑July 13th, 2022, 7:03 pmmultistate-apgsearch, i;e apgsearch but the starting soup contains all possible states