Script request thread

For scripts to aid with computation or simulation in cellular automata.
User avatar
muzik
Posts: 5612
Joined: January 28th, 2016, 2:47 pm
Location: Scotland

Re: Script request thread

Post by muzik » August 19th, 2021, 10:28 am

dvgrn wrote:
August 19th, 2021, 9:01 am
muzik wrote:
August 19th, 2021, 8:51 am
Are there any scripts that can turn a non-isotropic range-1 rule into its strobing complement?
My memory of strobing rules is pretty vague at this point. A rule's "strobing complement" in general is two alternating rules, right?
Probably should have clarified: this would only apply to rules already invariant under black-white reversal.

Cyclotrons
Posts: 129
Joined: January 26th, 2021, 12:19 am

Re: Script request thread

Post by Cyclotrons » August 25th, 2021, 12:12 pm

Would 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.
I wrote a stdin script that generates random soups of a provided number of a given spaceship. It works for all (non-B0) spaceships in the INT rulespace!
A Multistate INT notation + script.

User avatar
pzq_alex
Posts: 792
Joined: May 1st, 2021, 9:00 pm
Location: tell me if you know

Re: Script request thread

Post by pzq_alex » August 26th, 2021, 8:52 am

Cyclotrons wrote:
August 25th, 2021, 12:12 pm
Would anyone mind writing a spaceship collision stdin script for INT rules?
gencols, if that's what you're asking for.
\sum_{n=1}^\infty H_n/n^2 = \zeta(3)

How much of current CA technology can I redevelop "on a desert island"?

User avatar
dvgrn
Moderator
Posts: 10610
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Script request thread

Post by dvgrn » August 26th, 2021, 9:09 am

pzq_alex wrote:
August 26th, 2021, 8:52 am
gencols, if that's what you're asking for.
Isn't gencols hard-coded to B3/S23? Or has someone made an INT version of it when I wasn't paying attention?

User avatar
pzq_alex
Posts: 792
Joined: May 1st, 2021, 9:00 pm
Location: tell me if you know

Re: Script request thread

Post by pzq_alex » August 27th, 2021, 7:36 am

dvgrn wrote:
August 26th, 2021, 9:09 am
pzq_alex wrote:
August 26th, 2021, 8:52 am
gencols, if that's what you're asking for.
Isn't gencols hard-coded to B3/S23? Or has someone made an INT version of it when I wasn't paying attention?
I think Paul Tooke once posted about changing gencols' rule.
\sum_{n=1}^\infty H_n/n^2 = \zeta(3)

How much of current CA technology can I redevelop "on a desert island"?

Sokwe
Moderator
Posts: 2644
Joined: July 9th, 2009, 2:44 pm

Re: Script request thread

Post by Sokwe » August 27th, 2021, 9:37 pm

pzq_alex wrote:
August 27th, 2021, 7:36 am
dvgrn wrote:
August 26th, 2021, 9:09 am
Isn't gencols hard-coded to B3/S23? Or has someone made an INT version of it when I wasn't paying attention?
I think Paul Tooke once posted about changing gencols' rule.
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.

After compiling, I tested it with tlife (B3/S2-i34q). I tried collisions between a T-ship and a glider with a few filter options to look for collisions that resulted in one of the three small spaceships. Here's what I did:

First I added two files:

t-W.life:

Code: Select all

.*
**
.*
g-SW-SE.list:

Code: Select all

*!*.*!**!
..*!*.*!.**!
I then ran

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
which gave this output (it actually gave life 1.05 output with the header line missing, which I corrected and opened in Golly so I could copy out the RLE):

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!
There are still some life-specific assumptions in the filters, so I don't know how exactly they'll work in other rules. For example, "-filt g" will find both the glider and the 7-cell c/4 diagonal ship in tlife, but "-filt s" will not find the T-ship.

To get at least some sense of what the arguments do, consult the Arguments.Explanation file from the original release of gencols. I have copied this file here for convenience:

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) 


-Matthias Merzenich

User avatar
pzq_alex
Posts: 792
Joined: May 1st, 2021, 9:00 pm
Location: tell me if you know

Re: Script request thread

Post by pzq_alex » August 28th, 2021, 1:58 am

Sokwe wrote:
August 27th, 2021, 9:37 pm
I tried collisions between a T-ship and a glider with a few filter options to look for collisions that resulted in one of the three small spaceships. Here's what I did:
You mean one of (two small spaceships and a big p160 RRO) right?
\sum_{n=1}^\infty H_n/n^2 = \zeta(3)

How much of current CA technology can I redevelop "on a desert island"?

Sokwe
Moderator
Posts: 2644
Joined: July 9th, 2009, 2:44 pm

Re: Script request thread

Post by Sokwe » August 28th, 2021, 7:00 am

pzq_alex wrote:
August 28th, 2021, 1:58 am
Sokwe wrote:
August 27th, 2021, 9:37 pm
I tried collisions between a T-ship and a glider with a few filter options to look for collisions that resulted in one of the three small spaceships. Here's what I did:
You mean one of (two small spaceships and a big p160 RRO) right?
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.
-Matthias Merzenich

dani
Posts: 1222
Joined: October 27th, 2017, 3:43 pm

Re: Script request thread

Post by dani » August 31st, 2021, 3:04 pm

Here's a Lua script that determines the apgcode of a given pattern. No support for linear growth yet, and I don't plan on it because I'm planning a bigger script involving these functions soon. Let me know if there are any obvious improvements or glaringly obvious bugs, I tried it out on the 7 engine Cordership and it was admittedly quite slow for that, but for general purpose small patterns it shouldn't be too bad.

EDIT: Added further comments, switched to getstring to allow user to copy output easier.

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())

Cyclotrons
Posts: 129
Joined: January 26th, 2021, 12:19 am

Re: Script request thread

Post by Cyclotrons » September 1st, 2021, 3:15 pm

Cyclotrons wrote:
August 25th, 2021, 12:12 pm
Would 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.
I decided to do it myself instead.

Compile it with the line g++ -o shipcolls shipcolls.cpp -std=c++11 -O3 -Ofast -flto -march=native
Pipe it into apgluxe by running it like so:
./shipcolls -g '(insert RLE of your spaceship here)' -r (insert rule the spaceship is from here) -n (number of ships to collide here) -t 0 | ./apgluxe <normal provided arguments> --symmetry (symmetry name containing 'stdin' here) -t 0 - L 0

Notes:
  • For shipcolls, -t is the argument that sets how many soups to generate. Setting it to 0 runs it indefinitely.
  • For apgluxe, -t is the argument that sets whether or not testing mode is enabled. If it is, the haul won't be uploaded to catagolue. If logging (-L) is enabled, a log file for the haul will be created locally. For stdin searches, both are enabled by default. Note that older and/or hacked versions of apgsearch may fail to provide sample soup RLEs for a stdin haul, so it is recommended that you run a small test (by setting -t 1 and -L 1 or not including the arguments at all) to be sure that a sample soup is actually being provided before uploading to catagolue.
  • The | symbol indicates that console output from the program preceding it is being redirected to the program following it. Run standalone, shipcolls will print directly to the console.
  • Make sure that the RLE is enclosed by single quotes (' '). The RLE will not be interpreted correctly if you don't.
  • You may notice that the output RLE headers are incorrect. While the headers need to be there for apgsearch to interpret them correctly, it doesn't actually care about what they say, so a standard template header can be used.
The program:

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;
	
}
I wrote a stdin script that generates random soups of a provided number of a given spaceship. It works for all (non-B0) spaceships in the INT rulespace!
A Multistate INT notation + script.

GUYTU6J
Posts: 2200
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Script request thread

Post by GUYTU6J » September 3rd, 2021, 5:24 am

Sokwe wrote:
August 27th, 2021, 9:37 pm
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.

After compiling...
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.

Code: Select all

gcc -o gencols gencols.c -O3 -Ofast -flto -march=native

Cyclotrons
Posts: 129
Joined: January 26th, 2021, 12:19 am

Re: Script request thread

Post by Cyclotrons » September 3rd, 2021, 12:09 pm

GUYTU6J wrote:
September 3rd, 2021, 5:24 am
Sokwe wrote:
August 27th, 2021, 9:37 pm
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.

After compiling...
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.

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).
I wrote a stdin script that generates random soups of a provided number of a given spaceship. It works for all (non-B0) spaceships in the INT rulespace!
A Multistate INT notation + script.

GUYTU6J
Posts: 2200
Joined: August 5th, 2016, 10:27 am
Location: 拆哪!I repeat, CHINA! (a.k.a. 种花家)
Contact:

Re: Script request thread

Post by GUYTU6J » September 3rd, 2021, 12:36 pm

Cyclotrons wrote:
September 3rd, 2021, 12:09 pm
GUYTU6J wrote:
September 3rd, 2021, 5:24 am
A 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
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).
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.

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.

Sokwe
Moderator
Posts: 2644
Joined: July 9th, 2009, 2:44 pm

Re: Script request thread

Post by Sokwe » September 3rd, 2021, 5:16 pm

GUYTU6J wrote:
September 3rd, 2021, 5:24 am
how is the compiling done for that modification? On the regular Windows Command Prompt with both gcc and g++...
GUYTU6J wrote:
September 3rd, 2021, 12:36 pm
Note that my original question was for the gencols — which has a mysterious Makefile that I don't know how to run
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.
-Matthias Merzenich

User avatar
Extrementhusiast
Posts: 1966
Joined: June 16th, 2009, 11:24 pm
Location: USA

Re: Script request thread

Post by Extrementhusiast » September 7th, 2021, 5:00 pm

This 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.
I Like My Heisenburps! (and others)

User avatar
calcyman
Moderator
Posts: 2932
Joined: June 1st, 2009, 4:32 pm

Re: Script request thread

Post by calcyman » September 7th, 2021, 5:39 pm

Extrementhusiast wrote:
September 7th, 2021, 5:00 pm
This 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.
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).

Here's the link to a version that you can save as a (non-Golly) Python script and run in a terminal:

viewtopic.php?p=75522#p75522

For example, you can run:

python findpreds.py xs21_08e1dagz259d11 C1 100

to get the following output:

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!
What do you do with ill crystallographers? Take them to the mono-clinic!

hotdogPi
Posts: 1586
Joined: August 12th, 2020, 8:22 pm

Re: Script request thread

Post by hotdogPi » October 1st, 2021, 8:59 am

This requested script will take a hassler/shuttle/etc. and determine how likely it is to occur naturally.

Code: Select all

x = 36, y = 9, rule = B3/S23
26bo$26bobo$9bo17bobo$9b2o16bo2bo3b2o$4b2o4b2o15bobo4b2o$2o2b2o4b3o13b
obo$2o2b2o4b2o7bobo4bo$9b2o9b2o$9bo10bo!
Gosper glider gun:
Queen bee (the first object isn't pinned to a location or timing)
Queen bee, exact location and and orientation, timed correctly
Block in one of two positions
Block in one of two positions
Vicinity is clear

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!
p24 pi-heptomino hassler, assuming symmetry:
Figure eight at exact location and orientation (with symmetry, location must be exact for the first object, but not timing)
Figure eight at exact location and orientation, timed correctly
Pi-heptomino at exact location and orientation, timed correctly
Vicinity is clear

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!
p32 honey farm hassler:
Figure eight
Figure eight at exact location and orientation, timed correctly
Block at exact location
Fishhook at exact location and orientation
Honey farm or LOM at exact location and orientation, timed correctly
Vicinity is clear

This can be tested with objects that have been found, such as these:

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!
(Gabriel's p138 simply requires an octomino II in the correct orientation and location and no interference, and that's it)

Note that objects that must be far from the soup, such as the four-fold p54 shuttle, should be penalized, although blocks and ships less so because of B-heptominoes. Also note constellations; e.g. bi-blocks are more common than two blocks individually.
User:HotdogPi/My discoveries

Periods discovered: 5-16,⑱,⑳G,㉑G,㉒㉔㉕,㉗-㉛,㉜SG,㉞㉟㊱㊳㊵㊷㊹㊺㊽㊿,54G,55G,56,57G,60,62-66,68,70,73,74S,75,76S,80,84,88,90,96
100,02S,06,08,10,12,14G,16,17G,20,26G,28,38,47,48,54,56,72,74,80,92,96S
217,486,576

S: SKOP
G: gun

hotdogPi
Posts: 1586
Joined: August 12th, 2020, 8:22 pm

Re: Script request thread

Post by hotdogPi » October 12th, 2021, 8:27 pm

Sorry for double posting, but the test case done by hand on Discord was very accurate to the real numbers. A script could definitely be written.

The test: 22P36
C2_4 soups: 140 billion
Fishhook frequency (we're looking for exact fishhooks, so no integrals): 1 in 473×(5756/3.094)×8 = 1 in 7 million (http://conwaylife.com/ref/mniemiec/p1.htm) (473 is the block in specific location frequency; 8 because fishhooks are asymmetric)
Divide the two: 20000 soups will have the fishhooks in the correct place. 22P36 is only C2 symmetric, so multiply by 4: 80000.
2/3 of blinkers are from traffic lights, and blinkers are approximately as common as blocks, so 80000/(473×4×1.5) = 28.

The actual number found in C2_4? 25. Extremely close. There are two potentially canceling factors we haven't considered yet. One is that the 22P36 has to survive. The other is that a phi spark placed correctly also works. If the first is a greater factor, we would expect fewer than 28, and this is the case; we have 25, not 28.

(If you read the Discord, these steps were done in a slightly different order, but since it's all multiplication and division, it works out the same.)
User:HotdogPi/My discoveries

Periods discovered: 5-16,⑱,⑳G,㉑G,㉒㉔㉕,㉗-㉛,㉜SG,㉞㉟㊱㊳㊵㊷㊹㊺㊽㊿,54G,55G,56,57G,60,62-66,68,70,73,74S,75,76S,80,84,88,90,96
100,02S,06,08,10,12,14G,16,17G,20,26G,28,38,47,48,54,56,72,74,80,92,96S
217,486,576

S: SKOP
G: gun

AlbertArmStain
Posts: 1228
Joined: January 28th, 2022, 7:18 pm
Location: Planet Z

Re: Script request thread

Post by AlbertArmStain » February 3rd, 2022, 4:19 pm

Can someone make a syringe finder?
I would really like to see a g-to-pi or g-to-r.

User avatar
yujh
Posts: 3066
Joined: February 27th, 2020, 11:23 pm
Location: I'm not sure where I am, so please tell me if you know
Contact:

Re: Script request thread

Post by yujh » February 3rd, 2022, 4:35 pm

AlbertArmStain wrote:
February 3rd, 2022, 4:19 pm
Can someone make a syringe finder?
I would really like to see a g-to-pi or g-to-r.
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.
Rule modifier

B34kz5e7c8/S23-a4ityz5k
b2n3-q5y6cn7s23-k4c8
B3-kq6cn8/S2-i3-a4ciyz8
B3-kq4z5e7c8/S2-ci3-a4ciq5ek6eik7

Bored of Conway's Game of Life? Try Pedestrian Life -- not pedestrian at all!

User avatar
pzq_alex
Posts: 792
Joined: May 1st, 2021, 9:00 pm
Location: tell me if you know

Re: Script request thread

Post by pzq_alex » April 30th, 2022, 8:30 am

GUYTU6J wrote:
September 3rd, 2021, 12:36 pm
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.

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.
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.
2)To access Windows files, e.g. D:/some/path/to/file, use /mnt/d/some/path/to/file.

The makefile is a special file that contains information about how to compile the code. The Linux make utility understands the format, and running make directly compiles the program for you.
\sum_{n=1}^\infty H_n/n^2 = \zeta(3)

How much of current CA technology can I redevelop "on a desert island"?

User avatar
ClippyCosmologist
Posts: 22
Joined: May 7th, 2022, 5:24 pm

Re: Script request thread

Post by ClippyCosmologist » May 14th, 2022, 7:24 pm

Cyclotrons wrote:
September 1st, 2021, 3:15 pm
Cyclotrons wrote:
August 25th, 2021, 12:12 pm
Would 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.
I decided to do it myself instead.[...]
Thank you for the useful script!
However, it seems to sometimes place parallel LWSSs close enough to destroy each other before colliding with anything else.
For example, in this soup:

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$!
There is one such pair coming in from the left near the bottom, and another from the right slightly below the centre.
This was generated with the parameters

Code: Select all

./shipcolls -g 'b2o$3o$2obo$b3o$2bo!' -n 30 -dmin 5 -dmax 10 -dscale 1 -r b3s238 -t 0
"Human beings, five hundred years after the Scientific Revolution, are only just starting to match their wits against the billion-year heritage of biology." -- E. Yudkowsky

atavoidirc
Posts: 49
Joined: April 14th, 2022, 3:09 pm

Re: Script request thread

Post by atavoidirc » July 13th, 2022, 7:03 pm

multistate-apgsearch, i;e apgsearch but the starting soup contains all possible states

User avatar
yujh
Posts: 3066
Joined: February 27th, 2020, 11:23 pm
Location: I'm not sure where I am, so please tell me if you know
Contact:

Re: Script request thread

Post by yujh » July 15th, 2022, 2:54 pm

atavoidirc wrote:
July 13th, 2022, 7:03 pm
multistate-apgsearch, i;e apgsearch but the starting soup contains all possible states
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.

User avatar
pzq_alex
Posts: 792
Joined: May 1st, 2021, 9:00 pm
Location: tell me if you know

Re: Script request thread

Post by pzq_alex » July 16th, 2022, 5:03 am

yujh wrote:
July 15th, 2022, 2:54 pm
atavoidirc wrote:
July 13th, 2022, 7:03 pm
multistate-apgsearch, i;e apgsearch but the starting soup contains all possible states
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.
Alternatively, you can use an stdin script to generate soups with all states in them — see the LifeWiki tutorial.
\sum_{n=1}^\infty H_n/n^2 = \zeta(3)

How much of current CA technology can I redevelop "on a desert island"?

Post Reply