Euclidean CA (ECA)
Posted: November 20th, 2018, 5:43 pm
There is an interesting sort of CA that comes when one considers an infinite universe, where the cells have less and less of an effect as their Euclidean Distance becomes greater.
This script runs CA with the following rules:
-The 'heat' or neighbour count of a cell is the total sum of all reciprocals of quarted(^4) euclidean distances to other live cells.
-It chooses to birth or survive cells based on thresholds specified by the rule. For example, ECA:B(1,2)(3,4)/S(3,6) would birth if the heat was between 1 and 2 (including both of those), or 3 and 4, and survive if between 3 and 6.
There are optimizations, but I will briefly explain some properties I have noticed.
Thresholds
A cell with maximum heat would be surrounded by infinitely many cells. This 'maximum heat' number is finite, but I do not yet know its value. A 511x511 block of cells yields the number 6.0267726589419..., but that's not even close to a good estimate. I have settled on using 7 when engineering day and night-esque rules.
Another threshold that isn't yet known is being able to expand outside its bounding box.
EDIT 11/30/2018: Thanks to Caenbe and Freywa for pointing out that the maximum heat is (2/3)*pi^2*C, where C = Catalan's constant. Wolfram says this is the value to 1000 digits:[/i]
Lonely patterns
Ah, yes, a big problem. I had to choose between either having patterns that can only exist alone on a grid, or having patterns behave way differently when alone. Yes, there are patterns that, due to having maximized or minimized heat within a range, can only exist alone. You could engineer this for any pattern, really. For example, here is a glider (quite vast in its rule range) that can exist only by itself in this rule:
The speed of light
This one may bother calcyman and Apple Bottom and the like. The speed of light in this rule is infinite, so it is way more comfortable to use one cell per generation. To demonstrate it is infinite, a single cell in the rule ECA:B(.01,7)/S (I've nicknamed this family of quite redundant rules 'Target', this would be 'Target.01') turns into this monstrosity in 5 generations:
Rules & Other miscellany
This rulespace is infinitely big. To start, here's a rule with a rhomblicator and the aforementioned T-glider:
I guess I'll post more rules later once I've done more research.
This script runs CA with the following rules:
-The 'heat' or neighbour count of a cell is the total sum of all reciprocals of quarted(^4) euclidean distances to other live cells.
-It chooses to birth or survive cells based on thresholds specified by the rule. For example, ECA:B(1,2)(3,4)/S(3,6) would birth if the heat was between 1 and 2 (including both of those), or 3 and 4, and survive if between 3 and 6.
Code: Select all
--This is a preliminary version. If sufficiently interesting behaviours show
--up, it would be nice to get a full simulating algorithm in better-written
--softawre like Golly. Speaking of Golly, make sure you have a version that
--supports Lua, so you can run this script. Stinky.
--TERMS TO KNOW:
--Heat - The number returned when the previous equation is ran on all of the
-- other cells in relation to the given cell (basically what count()
-- does)
local g = golly()
local gp = require "gplus"
local rulesB = {.01, 7}
local rulesS = {}
function count(x1, y1) --determine cell's heat
local pat
local total = 0
if g.getcell(x1, y1) == 1 then --ok i know it's ugly but it saves a lot of processing time than doing a conditional
g.setcell(x1, y1, 0)
pat = g.getcells(g.getrect())
g.setcell(x1, y1, 1)
else
pat = g.getcells(g.getrect())
end
for i = 1, #pat, 2 do
local x2 = pat[i]
local y2 = pat[i+1] --ugly
total = total+1 / ((x2-x1)^2+(y2-y1)^2)^2 --i know i said i was using fourth powers, however the square root and fourth power cancel out leaving just a stray ^2
end
return total
end
function ring(r) --basically, it returns a 'outer moore birth ring' of the given size
local pat = g.getcells(g.getrect())
local x, y, w, h = table.unpack(r) --there a better way to do this?
g.select({x-1, y-1, w+2, h+2})
g.randfill(100)
g.select({x, y, w, h})
g.clear(0)
local nring = g.getcells(g.getrect())
g.putcells(pat)
g.clear(1)
g.select({})
return nring
end
function step()
--hoooo boy i hated writing this
--don't read it if you don't want to get lost
local pat = g.getcells(g.getrect())
if g.getpop() == "0" then
g.exit("All cells are dead.")
return
end
local rulesBclone = rulesB
table.sort(rulesBclone)
local minrulesB = rulesBclone[1] --math.min but with an array
local lx, ly, lw, lh = table.unpack(g.getrect())
while true do --this loop determines how far to check for births
local localmax = 0
local localring = ring({lx, ly, lw, lh})
for i = 1, #localring, 2 do
local localcount = count(localring[i], localring[i+1])
if localcount > localmax then
localmax = localcount
end
end
if localmax < minrulesB then
break
end
lx = lx - 1
ly = ly - 1
lw = lw + 2
lh = lh + 2
end
--gosh that took me months to make, now onto processing
g.select({lx, ly, lw, lh})
g.randfill(100)
g.putcells(pat, 0, 0, 1, 0, 0, 1, --[[ugh why]] "xor")
local area = g.getcells(g.getrect())
g.clear(0)
g.putcells(pat)
--NOW LET'S FINALLY PROCESS BIRTH, aka the reason that hellhole of lines above had to be done
local localcells = {}
for i = 1, #area, 2 do
local localcount = count(area[i], area[i+1])
for j = 1, #rulesB, 2 do
if localcount >= rulesB[j] and localcount <= rulesB[j+1] then
table.insert(localcells, area[i])
table.insert(localcells, area[i+1]) --can't think of a way to insert two at once
end
end
end
--and survival, the easy part
for i = 1, #pat, 2 do
local localcount = count(pat[i], pat[i+1])
for j = 1, #rulesS, 2 do
if localcount >= rulesS[j] and localcount <= rulesS[j+1] then
table.insert(localcells, pat[i])
table.insert(localcells, pat[i+1])
end
end
end
g.select(g.getrect())
g.clear(0)
g.putcells(localcells)
g.select({})
g.setgen(tonumber(g.getgen())+1)
end
while true do
step()
g.update()
step()
Thresholds
A cell with maximum heat would be surrounded by infinitely many cells. This 'maximum heat' number is finite, but I do not yet know its value. A 511x511 block of cells yields the number 6.0267726589419..., but that's not even close to a good estimate. I have settled on using 7 when engineering day and night-esque rules.
Another threshold that isn't yet known is being able to expand outside its bounding box.
EDIT 11/30/2018: Thanks to Caenbe and Freywa for pointing out that the maximum heat is (2/3)*pi^2*C, where C = Catalan's constant. Wolfram says this is the value to 1000 digits:
Code: Select all
6.0268120396919401235462601927282855839417908072537241239789823989168652037814250418764946630938418433906127747493598517914519884043536868495100966503449541972750061912676710610851774101700255398481455670182612361266898875483352921070069449008114281527829434299322822560251114200149117706817994764236876636117413174159952976496849741988010861076557834927010493267788390209735731100040920526016251643211225971568622986661712279082923986446238998997768676990659832983376483731474723643953842741351597605714161337207790707042631552431695921352276400390580604568489239229700788071861541187775637812405539300590870406433494222017883382946074250172136911832633689703956037954481037629038480262769680362849773653130682557719791223453092147760706480221366950515486440933396727770173048557378012773452636411632552957204199179226582314343628445920394854336019550159007480469325289524410543403938235788421982263661511011524075413030449483389003139678799601958658704861812673964630612466034108439517982559502176303...
Lonely patterns
Ah, yes, a big problem. I had to choose between either having patterns that can only exist alone on a grid, or having patterns behave way differently when alone. Yes, there are patterns that, due to having maximized or minimized heat within a range, can only exist alone. You could engineer this for any pattern, really. For example, here is a glider (quite vast in its rule range) that can exist only by itself in this rule:
Code: Select all
#C rule = ECA:B(1.15,1.5625)/S(1.6,3)
x = 2, y = 3, rule = B/S012345678
bo$2o$bo!
Code: Select all
#C rule = ECA:B(1.15,1.5625)/S(1.6,3)
x = 9, y = 3, rule = B/S012345678
bo$2o6bo$bo!
This one may bother calcyman and Apple Bottom and the like. The speed of light in this rule is infinite, so it is way more comfortable to use one cell per generation. To demonstrate it is infinite, a single cell in the rule ECA:B(.01,7)/S (I've nicknamed this family of quite redundant rules 'Target', this would be 'Target.01') turns into this monstrosity in 5 generations:
Code: Select all
#C rule = ECA:B(.01,7)/S
x = 57, y = 57, rule = B/S012345678
23b11o$19b19o$17b23o$15b27o$13b31o$12b33o$10b37o$9b15o9b15o$8b13o15b
13o$7b12o19b12o$6b11o23b11o$6b10o25b10o$5b9o29b9o$4b9o31b9o$4b8o12b9o
12b8o$3b9o10b13o10b9o$3b8o9b17o9b8o$2b8o9b19o9b8o$2b8o8b21o8b8o$b8o8b
23o8b8o$b8o7b10o5b10o7b8o$b7o8b8o9b8o8b7o$b7o7b8o11b8o7b7o$8o7b7o13b7o
7b8o$7o7b7o15b7o7b7o$7o7b7o6b3o6b7o7b7o$7o7b6o6b5o6b6o7b7o$7o7b6o5b7o
5b6o7b7o$7o7b6o5b3ob3o5b6o7b7o$7o7b6o5b7o5b6o7b7o$7o7b6o6b5o6b6o7b7o$
7o7b7o6b3o6b7o7b7o$7o7b7o15b7o7b7o$8o7b7o13b7o7b8o$b7o7b8o11b8o7b7o$b
7o8b8o9b8o8b7o$b8o7b10o5b10o7b8o$b8o8b23o8b8o$2b8o8b21o8b8o$2b8o9b19o
9b8o$3b8o9b17o9b8o$3b9o10b13o10b9o$4b8o12b9o12b8o$4b9o31b9o$5b9o29b9o$
6b10o25b10o$6b11o23b11o$7b12o19b12o$8b13o15b13o$9b15o9b15o$10b37o$12b
33o$13b31o$15b27o$17b23o$19b19o$23b11o!
This rulespace is infinitely big. To start, here's a rule with a rhomblicator and the aforementioned T-glider:
Code: Select all
#C rule = B(1.15,1.2)(1.3,1.4)(1.5,1.6)/S(1.603,2.5)(3,4)
x = 2, y = 13, rule = B/S012345678
bo$2o$bo8$o$2o$bo!