Re: Script request thread
Posted: April 16th, 2023, 10:17 am
Pipe into apgsearch running some stdin symmetry.
Pipe into apgsearch running some stdin symmetry.
The bulk of code responsible for separating patterns into objects belongs to https://gitlab.com/apgoucher/lifelib/-/ ... assifier.h . It uses a disjoint-set-union data structure.hkoenig wrote: April 19th, 2023, 9:12 pm On my list of things to do is a rewrite/replacement of my partition and census functions, if I can find the time. The methods I wrote date back to the last century and could use an update. I'd like to look at how apgsearch (or lifelib) does this and look for ideas to steal. Pointers to the relevant files and functions would be appreciated. Or broad descriptions of what it is doing.
That's an easy hack from glider-rewinder.py:atavoidirc wrote: June 29th, 2023, 2:02 pm A script that takes a glider synthesis and convert it to Quadlife by coloring the gliders according to direction.
Code: Select all
# glider-colorizer-by-direction-QuadLife.py
# https://conwaylife.com/w/index.php?title=Rule:QuadLife&action=raw
#
# If you have a selection, then only the gliders inside the selection will get updated.
# The others will stay in state 1, which is supposed to be the color for NW-traveling gliders
import golly as g
import os
import itertools
from glife import *
lib=[["NW","bo$2o$obo!"],["NE","2o$b2o$o!"],["SE","obo$b2o$bo!"],["SW","2bo$2o$b2o!"]]
def getenvelope(pat):
env=[]
if len(pat)%2:
g.exit("Must be a 2-state list.")
for i in range(0,len(pat)-1,2):
for x in range(-1,2):
for y in range(-1,2):
if abs(x)!=0 or abs(y)!=0: # add eight neighbors of each ON cell to the mask
if [pat[i]+x,pat[i+1]+y] not in env:
env.append([pat[i]+x,pat[i+1]+y])
for i in range(0,len(pat),2):
if [pat[i],pat[i+1]] in env:
env.remove([pat[i],pat[i+1]]) # take original pattern back out of mask
# else: # with the reduced envelope, this will now happen, e.g. with *WSS singleton sparks
# g.note("Technical error: " + str([pat[i],pat[i+1]])+ " not in envelope:" + str(env) + " \n\n" + str(pat))
return list(itertools.chain.from_iterable(env))
r=g.getselrect()
if len(r)==0:
r=g.getrect()
if len(r)==0: g.exit("No pattern, nothing to do.")
sel = g.getcells(r)
if len(sel)==0: g.exit("Nothing in selection.")
if len(sel)%2: g.exit("Can't do colorization starting with a multistate rule. Try Alt+J / Option+J first.")
all = g.getcells(g.getrect())
allcoords=[]
for i in range(0,len(all),2):
allcoords.append([all[i],all[i+1]])
# g.show("Processing object library...")
odict=dict()
for i in range(len(lib)):
# g.show("Processing object " + lib[i][0])
# run and normalize each library object until a duplicate of the original pattern appears
# The number of ticks to duplication, and the offset, give all the information needed to rewind...
obj = g.parse(lib[i][1])
basex, basey,ticks,newobj=obj[0],obj[1],0,[]
baseobj = g.transform(obj,-basex,-basey)
basepat = pattern(baseobj) # use glife to avoid having to add a layer in Golly
# TODO: figure out the actual right way to compare in Python 3.x... baseobj>newobj or baseobj<newobj, maybe?
while str(baseobj) != str(newobj):
ticks+=1
newpat=basepat[ticks]
newlist = list(newpat)
newobj=g.transform(newpat,-newlist[0],-newlist[1])
if ticks>999:
g.exit(obj[0] + " in library has no reasonable repeat time.")
stridex,stridey=newlist[0],newlist[1]
# odict key is name+phase, and there's an entry for each phase of each object
# Contains list of repeat, stridex, stridey, dx, dy, clist, envclist.
# By convention, the first ON cell in phase 0 is at (0,0) and dx and dy are also 0,0.
# The first ON cell in other phases is also 0,0 but dx and dy will be altered appropriately.
odict[lib[i][0]+"_0"]=[ticks, stridex, stridey, 0, 0, baseobj, getenvelope(baseobj)]
for t in range(1,ticks):
newlist=list(basepat[t])
normalized=g.transform(newlist,-newlist[0],-newlist[1])
odict[lib[i][0]+"_"+str(t)]=[ticks,stridex,stridey,newlist[0],newlist[1],normalized,getenvelope(normalized)]
g.show("")
# make a list of coordinate pairs that might be Objects of Interest (gliders or LWSSes)
coords=[]
for i in range(0,len(sel),2):
coords.append([sel[i],sel[i+1]])
rewindable=[]
# now go through the selection and find all the recognizable patterns
i=0
while i<len(coords):
x0,y0=coords[i][0], coords[i][1]
for k, v in list(odict.items()):
clist = v[5] # object cell list
match=1
for j in range(0,len(clist),2):
if [x0+clist[j],y0+clist[j+1]] not in coords:
match=0
break # a cell in this object is not in the selected pattern
if match:
envclist=v[6] # object envelope cell list
for j in range(0,len(envclist),2):
if [x0+envclist[j],y0+envclist[j+1]] in allcoords: # could use coords instead, but selection should be increased 2 cells all around
match=0
break # a cell in the surrounding must-be-OFF area is ON
if match:
# remove all recognized cells from coords
for j in range(0,len(clist),2):
crd=[x0+clist[j],y0+clist[j+1]]
if crd in coords:
coords.remove(crd)
else:
g.exit("A coordinate that should have been there wasn't: " + str(crd) + "\n\n" + str(coords))
rewindable.append([k,x0-v[3],y0-v[4]])
break # no need to go through rest of items in dictionary
if not match:
i+=1 # only increment index if current coord has not been removed due to a match
g.setrule("QuadLife")
# color all gliders
for item in rewindable:
lookup=odict[item[0]]
# odict[name+phase]=[ticks, stridex, stridey, dx, dy, clist, getenvelope(clist)]
clist = lookup[5]
# lookup[1] and lookup[2] will contain each glider's x and y offsets every four ticks --
# convert those numbers into a value from 1 to 4
color = (lookup[1]*4+lookup[2]*2 + 10) // 4
for i in range(0,len(clist),2):
g.setcell(clist[i]+item[1]+lookup[3],clist[i+1]+item[2]+lookup[4],color)Code: Select all
Set n to some preset number (16?)
While necessary {
Repeat 1000 times {
Run a random n*n soup
Check if it stabilises
}
If a majority of soups do not stabilise {
Choose larger n
} Else {
Choose smaller n
}
}
Return smallest n such that a majority of n*n soups do not stabiliseCode: Select all
import random
################################################################################
# The number of cellstates:
N_STATES = 16
# The rulestring to be used:
RULESTRING = "QuadB3S23"
# The number of columns:
RLE_WIDTH = 16
# The number of rows:
RLE_HEIGHT = 16
# The number of RLEs to generate (set to 0 to run 'forever'; set to 10 to generate 10 RLEs, etc.)
N_RLES = 0
################################################################################
def random_cellstate():
return random.randrange(0, N_STATES)
S1 = ["", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y"]
S2 = "ABCDEFGHIJKLMNOPQRSTUVWX"
def cellstate_to_rle(c):
if c == 0:
return "."
return S1[(c - 1) // 24] + S2[(c - 1) % 24]
def random_rle():
rle = ""
for y in range(RLE_HEIGHT):
rle = rle + "".join(cellstate_to_rle(random_cellstate()) for x in range(RLE_WIDTH))
rle = rle + "{}\n".format("$" if y < RLE_HEIGHT - 1 else "!")
return "x = {}, y = {}, rule = {}\n{}".format(RLE_WIDTH, RLE_HEIGHT, RULESTRING, rle)
def main():
print(random_rle())
i = 1
while i != N_RLES:
print(random_rle())
i += 1
main()
We kind of have that already, though as usual it needs a bit of bug-hunting work -- if you'll allow "Catagolue synthesis RLE" as a substitute for "Shinjuku synthesis".ClippyCosmologist wrote: January 16th, 2024, 9:12 pm A function that converts a multi-step shinjuku synthesis into a single-step synthesis pattern.
I think apgsearch recompiles itself differently depending on the specific rule you choose. That means a user won't be able to choose a different rule later without recompiling the program.H. H. P. M. P. Cole wrote: February 9th, 2024, 1:09 am Can someone please precompile apgsearch v5.41-ll2.5.7? It will be very useful to those who have computers that cannot compile apgsearch. My priorities for this precompiled version are to allow users to enter in their own rule (or a .rule file if a ruletable), and a user-defined standard/inflated symmetry.
You should specify the system on which you are, since the binary will be OS-specific. I'm on Ubuntu.
Okay then, so can you precompile it for Factorio, C1? (And if it is not a burden for you, can you precompile Factorio for every standard symmetry, 2x128, and iC1? My computer cannot compile apgsearch.)confocaloid wrote: February 9th, 2024, 1:24 amI think apgsearch recompiles itself differently depending on the specific rule you choose. That means a user won't be able to choose a different rule later without recompiling the program.H. H. P. M. P. Cole wrote: February 9th, 2024, 1:09 am Can someone please precompile apgsearch v5.41-ll2.5.7? It will be very useful to those who have computers that cannot compile apgsearch. My priorities for this precompiled version are to allow users to enter in their own rule (or a .rule file if a ruletable), and a user-defined standard/inflated symmetry.
I'd say it would be better to investigate the problem to understand why you cannot compile apgsearch for yourself, instead of having to distribute lots of binaries for different rulesym combinations. With three different OSes, it seems there should be a way to compile apgsearch for at least one of them, right? What is the error?H. H. P. M. P. Cole wrote: February 9th, 2024, 1:27 am[...]
Okay then, so can you precompile it for Factorio, C1? (And if it is not a burden for you, can you precompile Factorio for every standard symmetry, 2x128, and iC1? My computer cannot compile apgsearch.)
My computer uses a Windows/Linux/ChromeOS.
I am unable to run any of the steps on the wiki page.confocaloid wrote: February 9th, 2024, 2:02 amI'd say it would be better to investigate the problem to understand why you cannot compile apgsearch for yourself, instead of having to distribute lots of binaries for different rulesym combinations. With three different OSes, it seems there should be a way to compile apgsearch for at least one of them, right? What is the error?H. H. P. M. P. Cole wrote: February 9th, 2024, 1:27 am[...]
Okay then, so can you precompile it for Factorio, C1? (And if it is not a burden for you, can you precompile Factorio for every standard symmetry, 2x128, and iC1? My computer cannot compile apgsearch.)
My computer uses a Windows/Linux/ChromeOS.
That might be because the linked wiki page doesn't give any instructions, and instead just aims to be an encyclopedic article explaining what is apgsearch.H. H. P. M. P. Cole wrote: February 9th, 2024, 5:35 am[...]
I am unable to run any of the steps on the wiki page.
Thanks for the link, Confocal! I will try figuring out how to compile apgsearch on my old computer.confocaloid wrote: February 9th, 2024, 5:59 am That might be because the linked wiki page doesn't give any instructions, and instead just aims to be an encyclopedic article explaining what is apgsearch.
Did you look through Tutorials/Contributing to Catagolue / try the steps listed there?
What would be wrong with a Python-script fuse searcher? With no need for precompiling, a fairly simple Python or Lua script could generate tens of thousands of fuses in a fairly short amount of time (which, honestly, is exactly why nobody has written a script like that yet.)HerscheltheHerschel wrote: February 10th, 2024, 10:44 am This is not a Python script request, but I'm not finding any better thread, so I'm posting it here.
I would like a (user-friendly) fuse search program for Windows. I want it precompiled. (I am fine with command lines)
Sorry. I'm also fine with Python scripts, unless it's a golly script (which means that it has to be a Lua script in that case).dvgrn wrote: February 10th, 2024, 12:07 pmWhat would be wrong with a Python-script fuse searcher? With no need for precompiling, a fairly simple Python or Lua script could generate tens of thousands of fuses in a fairly short amount of time (which, honestly, is exactly why nobody has written a script like that yet.)HerscheltheHerschel wrote: February 10th, 2024, 10:44 am This is not a Python script request, but I'm not finding any better thread, so I'm posting it here.
I would like a (user-friendly) fuse search program for Windows. I want it precompiled. (I am fine with command lines)
What do you want this fuse search program to do, exactly? The easy implementation I'm thinking of would
- start with a selected object in Golly,
- ask the user for a value K specifying how many of that object should be used per unit of fuse,
- maybe ask the user about whether or not to allow rotations or reflections of the object,
- maybe ask for parameters to allow setting up orthogonal/diagonal/oblique/any-of-the-above searches,
- randomly place K objects near each other, and test to make sure they don't interact,
- randomly pick an offset, or enumerate all possible offsets, and make sure that adjacent units of fuse don't interact at that offset,
- start cycling through tests where N units of fuse are drawn in Golly, with a blob of random soup at one end, and the pattern is run for T ticks
- write out to a text file or RLE stamp collection any cases where the unit of fuse farthest away from the soup blob gets destroyed after T ticks.
To be clear, you're fine with Golly Lua scripts, but you don't want a Golly Python script?HerscheltheHerschel wrote: February 10th, 2024, 1:33 pm I'm also fine with Python scripts, unless it's a golly script (which means that it has to be a Lua script in that case).
I'll try the windows troubleshooting guide tomorrow. I'll PM you the results when I try it.dvgrn wrote: February 10th, 2024, 2:02 pmTo be clear, you're fine with Golly Lua scripts, but you don't want a Golly Python script?HerscheltheHerschel wrote: February 10th, 2024, 1:33 pm I'm also fine with Python scripts, unless it's a golly script (which means that it has to be a Lua script in that case).
Is this is because you aren't able to get Python working with Golly on your computer? Might the Windows or Mac Python troubleshooting guides help? (Post there if so.)