Script request thread

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
Saka
Posts: 3627
Joined: June 19th, 2015, 8:50 pm
Location: Indonesia
Contact:

Script request thread

Post by Saka » February 4th, 2016, 8:52 am

This thread is for requesting python scripts, I would like to request a apgcode to rle and if possible rle to apgcode

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

Re: Script request thread

Post by dvgrn » February 4th, 2016, 11:28 am

Saka wrote:This thread is for requesting python scripts, I would like to request a apgcode to rle and if possible rle to apgcode
The necessary pieces are already available, but kind of scattered around in several threads. Here's a quick-and-dirty attempt to put the apgcode-to-cell-list and cell-list-to-RLE functions together:

apgcode-to-clipboard-RLE-Python3.py:

Code: Select all

# apgcode-to-clipboard-RLE-Python3.py
#   takes an input apgcode, and copies equivalent RLE (with a header line)
#   into the clipboard, ready to be pasted into Golly.
# https://conwaylife.com/forums/viewtopic.php?p=27197#p27197
# -- see also the following post for "biggiemac's script" -- rle-to-apgcode.
#
# decodeCanon function:  creates a pattern cell list from a canonical apgcode,
#   an alphanumeric representation used in apgsearch by Adam P. Goucher
#
# By Arie Paap 
# Sept. 2014
# 
# ord2() from apgsearch, by Adam P. Goucher
#
# patched together by Dave Greene, 4 February 2016,
#   https://conwaylife.com/forums/viewtopic.php?p=27197#p27197
# and Python3 update also by Dave Greene, 13 May 2022

import golly as g

g.setrule("Life")

def decodeCanon(canonPatt):
    chars = "0123456789abcdefghijklmnopqrstuvwxyz"
    
    ox = 0
    x = 0
    y = 0
    clist = []
    
    ii = 0
    
    while ii < len(canonPatt):
        c = canonPatt[ii]
        if (c == 'y'):
            ii += 1
            x += 4 + ord2(canonPatt[ii])
            
        elif (c == 'x'):
            x += 3
        
        elif (c == 'w'):
            x += 2
        
        elif (c == '0'):
            x += 1
        
        elif (c == 'z'):
            x = ox
            y += 5
            
        else:
            u = ord2(c)
            v = 1
            for jj in range(0,5):
                if (u & v):
                    clist += [x, y+jj]
                v = v << 1
            x += 1
            
        ii += 1
    
    return clist

# Converts a base-36 case-insensitive alphanumeric character into a
# numerical value.
def ord2(char):

    x = ord(char)

    if ((x >= 48) & (x < 58)):
        return x - 48

    if ((x >= 65) & (x < 91)):
        return x - 55

    if ((x >= 97) & (x < 123)):
        return x - 87

    return -1

# Python function to convert a cell list to RLE
# Author: Nathaniel Johnston (nathaniel@nathanieljohnston.com), June 2009.
#          DMG: Refactored slightly so that the function input is a simple cell list.
#               No error checking added.
#               TBD:  check for multistate rule, show appropriate warning.
# --------------------------------------------------------------------

def chunks(l, n):
    for i in range(0, len(l), n):
        yield l[i:i+n]

# --------------------------------------------------------------------

def giveRLE(clist):
   clist_chunks = list (chunks (g.evolve(clist,0), 2))
   mcc = min(clist_chunks)
   rl_list = [[x[0]-mcc[0],x[1]-mcc[1]] for x in clist_chunks]
   rle_res = ""
   rle_len = 1
   rl_y = rl_list[0][1] - 1
   rl_x = 0
   for rl_i in rl_list:
      if rl_i[1] == rl_y:
         if rl_i[0] == rl_x + 1:
            rle_len += 1
         else:
            if rle_len == 1: rle_strA = ""
            else: rle_strA = str (rle_len)
            if rl_i[0] - rl_x - 1 == 1: rle_strB = ""
            else: rle_strB = str (rl_i[0] - rl_x - 1)

            rle_res = rle_res + rle_strA + "o" + rle_strB + "b"
            rle_len = 1
      else:
         if rle_len == 1: rle_strA = ""
         else: rle_strA = str (rle_len)
         if rl_i[1] - rl_y == 1: rle_strB = ""
         else: rle_strB = str (rl_i[1] - rl_y)
         if rl_i[0] == 1: rle_strC = "b"
         elif rl_i[0] == 0: rle_strC = ""
         else: rle_strC = str (rl_i[0]) + "b"
         
         rle_res = rle_res + rle_strA + "o" + rle_strB + "$" + rle_strC
         rle_len = 1

      rl_x = rl_i[0]
      rl_y = rl_i[1]
   
   if rle_len == 1: rle_strA = ""
   else: rle_strA = str (rle_len)
   rle_res = rle_res[2:] + rle_strA + "o"
   
   return rle_res+"!"

canonPatt = g.getstring('Enter apgcode','xp2_31e8gzoo1vg54','')
canonPatt = canonPatt.strip().lower()
canonPatt = canonPatt.split('_')[-1]

if not canonPatt:
    g.exit('Pattern is empty')

patt = decodeCanon(canonPatt)

RLE = giveRLE(patt)
header="x = " + str(max(patt[0::2])-min(patt[0::2])+1)+", y = " + str(max(patt[1::2])-min(patt[1::2])+1)+", rule = B3/S23\n"
g.setclipstr(header + RLE)
g.show(RLE)
In this implementation, the input is a Golly dialog box, and the output goes to the clipboard. It would be easy to change it so that the input comes from the clipboard also.

It would probably be good to add some error checking in that case -- make sure that what's on the clipboard really looks like an apgcode, before you go trying to convert it. This version should work okay (based on my very minimal testing so far) as long as the input really is a valid apgcode.

The conversion in the other direction is somewhat simpler. You can dig most of it straight out of the old Python version of apgsearch. Can someone else throw that one together?

User avatar
biggiemac
Posts: 515
Joined: September 17th, 2014, 12:21 am
Location: California, USA

Re: Script request thread

Post by biggiemac » February 4th, 2016, 7:11 pm

This'll probably work. I tested it for spaceships, still lives and oscillators. Just select a rectangle in golly containing only the pattern you care about (plus any amount of empty space) and the apgcode of the object will go to your clipboard. As a side effect, the script makes a new layer.

You can certainly get nonsense out of it, by selecting an active object or multiple disjoint objects. But if you use it well it'll do the right thing.

Code: Select all

import golly as g

# Golly selection to apgcode (in clipboard)
# stolen shamelessly from apgsearch.  Thanks Adam!

def bijoscar(maxsteps):

    initpop = int(g.getpop())
    initrect = g.getrect()
    if (len(initrect) == 0):
        return 0
    inithash = g.hash(initrect)

    for i in xrange(maxsteps):

        g.run(1)

        if (int(g.getpop()) == initpop):

            prect = g.getrect()
            phash = g.hash(prect)

            if (phash == inithash):

                period = i + 1

                if (prect == initrect):
                    return period
                else:
                    return -period
    return -1


def canonise():
    
    p = bijoscar(1000)

    representation = "#"
    for i in range(abs(p)):
        rect = g.getrect()
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1], 1, 0, 0, 1))
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0]+rect[2]-1, rect[1], -1, 0, 0, 1))
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1]+rect[3]-1, 1, 0, 0, -1))
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0]+rect[2]-1, rect[1]+rect[3]-1, -1, 0, 0, -1))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0], rect[1], 0, 1, 1, 0))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0]+rect[2]-1, rect[1], 0, -1, 1, 0))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0], rect[1]+rect[3]-1, 0, 1, -1, 0))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0]+rect[2]-1, rect[1]+rect[3]-1, 0, -1, -1, 0))
        g.run(1)
    
    if (p<0):
        prefix = "q"+str(abs(p))
    elif (p==1):
        prefix = "s"+str(g.getpop())
    else:
        prefix = "p"+str(p)

    g.setclipstr("x"+prefix+"_"+representation)

# A subroutine used by canonise:
def canonise_orientation(length, breadth, ox, oy, a, b, c, d):

    representation = ""

    chars = "0123456789abcdefghijklmnopqrstuvwxyz"

    for v in xrange(int((breadth-1)/5)+1):
        zeroes = 0
        if (v != 0):
            representation += "z"
        for u in xrange(length):
            baudot = 0
            for w in xrange(5):
                x = ox + a*u + b*(5*v + w)
                y = oy + c*u + d*(5*v + w)
                baudot = (baudot >> 1) + 16*g.getcell(x, y)
            if (baudot == 0):
                zeroes += 1
            else:
                if (zeroes > 0):
                    if (zeroes == 1):
                        representation += "0"
                    elif (zeroes == 2):
                        representation += "w"
                    elif (zeroes == 3):
                        representation += "x"
                    else:
                        representation += "y"
                        representation += chars[zeroes - 4]
                zeroes = 0
                representation += chars[baudot]
    return representation

# Compares strings first by length, then by lexicographical ordering.
# A hash character is worse than anything else.
def compare_representations(a, b):

    if (a == "#"):
        return b
    elif (b == "#"):
        return a
    elif (len(a) < len(b)):
        return a
    elif (len(b) < len(a)):
        return b
    elif (a < b):
        return a
    else:
        return b

g.duplicate()
g.clear(1)
canonise()

Or, for the extra lazy, a script that will take you directly to the catagolue page.

Code: Select all

import golly as g
import webbrowser

# Golly selection directly to catagolue page
# stolen shamelessly from apgsearch.  Thanks Adam!

def bijoscar(maxsteps):

    initpop = int(g.getpop())
    initrect = g.getrect()
    if (len(initrect) == 0):
        return 0
    inithash = g.hash(initrect)

    for i in xrange(maxsteps):

        g.run(1)

        if (int(g.getpop()) == initpop):

            prect = g.getrect()
            phash = g.hash(prect)

            if (phash == inithash):

                period = i + 1

                if (prect == initrect):
                    return period
                else:
                    return -period
    return -1


def canonise():

    p = bijoscar(1000)

    representation = "#"
    for i in range(abs(p)):
        rect = g.getrect()
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1], 1, 0, 0, 1))
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0]+rect[2]-1, rect[1], -1, 0, 0, 1))
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1]+rect[3]-1, 1, 0, 0, -1))
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0]+rect[2]-1, rect[1]+rect[3]-1, -1, 0, 0, -1))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0], rect[1], 0, 1, 1, 0))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0]+rect[2]-1, rect[1], 0, -1, 1, 0))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0], rect[1]+rect[3]-1, 0, 1, -1, 0))
        representation = compare_representations(representation, canonise_orientation(rect[3], rect[2], rect[0]+rect[2]-1, rect[1]+rect[3]-1, 0, -1, -1, 0))
        g.run(1)
    
    if (p<0):
        prefix = "q"+str(abs(p))
    elif (p==1):
        prefix = "s"+str(g.getpop())
    else:
        prefix = "p"+str(p)

    rule = str.replace(g.getrule(),"/","").lower()
    
    webbrowser.open_new("http://catagolue.appspot.com/object?apgcode=x"+prefix+"_"+representation+"&rule="+rule)

# A subroutine used by canonise:
def canonise_orientation(length, breadth, ox, oy, a, b, c, d):

    representation = ""

    chars = "0123456789abcdefghijklmnopqrstuvwxyz"

    for v in xrange(int((breadth-1)/5)+1):
        zeroes = 0
        if (v != 0):
            representation += "z"
        for u in xrange(length):
            baudot = 0
            for w in xrange(5):
                x = ox + a*u + b*(5*v + w)
                y = oy + c*u + d*(5*v + w)
                baudot = (baudot >> 1) + 16*g.getcell(x, y)
            if (baudot == 0):
                zeroes += 1
            else:
                if (zeroes > 0):
                    if (zeroes == 1):
                        representation += "0"
                    elif (zeroes == 2):
                        representation += "w"
                    elif (zeroes == 3):
                        representation += "x"
                    else:
                        representation += "y"
                        representation += chars[zeroes - 4]
                zeroes = 0
                representation += chars[baudot]
    return representation

# Compares strings first by length, then by lexicographical ordering.
# A hash character is worse than anything else.
def compare_representations(a, b):

    if (a == "#"):
        return b
    elif (b == "#"):
        return a
    elif (len(a) < len(b)):
        return a
    elif (len(b) < len(a)):
        return b
    elif (a < b):
        return a
    else:
        return b

g.duplicate()
g.clear(1)
canonise()
EDIT by dvgrn: A version of this updated for Python 3.x, Golly 4.0+, can be found here.

TODO item: figure out why this fails with an error when trying to recognize something as large as a p43 Snark loop.
Physics: sophistication from simplicity.

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » February 6th, 2016, 2:37 pm

Period determiner (the pattern to catalogue script only counts to 4500)?

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

Re: Script request thread

Post by dvgrn » February 6th, 2016, 5:07 pm

drc wrote:Period determiner (the pattern to catalogue script only counts to 4500)?
What about oscar.py, in Golly's Scripts/Python folder? Should work for any rule you have defined in Golly, for any reasonable period, as long as you're sufficiently patient. Are there other requirements that I'm not understanding?

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » February 6th, 2016, 5:19 pm

dvgrn wrote:
drc wrote:Period determiner (the pattern to catalogue script only counts to 4500)?
What about oscar.py, in Golly's Scripts/Python folder? Should work for any rule you have defined in Golly, for any reasonable period, as long as you're sufficiently patient. Are there other requirements that I'm not understanding?
Ok, that's a very confusing name, which is why I didn't notice it.

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » March 6th, 2016, 1:12 pm

A script that tallies the current objects on screen and outputs them apgsearch-style

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » March 13th, 2016, 9:17 pm

Is there a script that gives out push-pull reactions for replicators? preferrably python please people

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

Re: Script request thread

Post by dvgrn » March 13th, 2016, 11:33 pm

drc wrote:Is there a script that gives out push-pull reactions for replicators? preferrably python please people
Yes, chris_c has written a Python search script (I think this is a vaguely relevant link, anyway -- looks like there's semi-official code in GitHub also) to enumerate elbow INC and DEC reactions, for 10hd and 0hd construction arms. Paul Chapman did something similar back in 2010 to produce the 9hd construction toolkit used in the linear propagator.

The current single-channel construction arm is still a work in progress -- last I heard, simeks was working on a fast C search program to generate elbow operations. Single-channel seems like the place where searches are most needed. I'm not sure anyone will ever even go back to the very recent 0hd toolkit (pairs of gliders following each other closely on a single lane) -- because you still need two edge-shooting inserters to build those pairs -- or at least one glider stream and one inserter, I suppose.

With the single-channel toolkit, any glider output can be a construction arm -- you don't need any inserters at all. The actual elbow operations are significantly more expensive in terms of the total number of gliders needed, but it looks like that will be more than made up for by not needing to build complex circuitry to synchronize two separate streams of gliders.

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » March 14th, 2016, 3:52 pm

That's cool, but not what I meant. I meant like the second image on this page:

http://pentadecathlon.com/lifeNews/2013 ... ities.html

Code: Select all

x = 189, y = 197, rule = B36/S23
7bo5bo$6bobo3bobo$6b2o5b2o2$6b2o5b2o$6bobo3bobo$7bo5bo14bo$27b3o$5bo
20b3obo$4b3o18b2o2b3o$3b3obo16b2o3b2o$2b2o2b3o14b3o2b2o$b2o3b2o16bob3o
$3o2b2o18b3o$bob3o20bo$2b3o$3bo9bo$12b3o$11b3obo$10b2o2b3o$9b2o3b2o$8b
3o2b2o$9bob3o30bo$10b3o30b3o$11bo9bo20b3obo$20b3o18b2o2b3o$19b3obo16b
2o3b2obo$18b2o2b3o14b3o2b2ob3o$17b2o3b2obo14bob3ob3obo$16b3o2b2ob3o14b
3ob2o2b3o$17bob3ob3obo14bob2o3b2obo$18b3ob2o2b3o14b3o2b2ob3o$19bob2o3b
2o16bob3ob3obo$20b3o2b2o18b3ob2o2b3o$21bob3o20bob2o3b2obo$22b3o22b3o2b
2ob3o$23bo24bob3ob3obo$49b3ob2o2b3o$50bob2o3b2o$51b3o2b2o$37bo14bob3o$
36b3o14b3o$35b3obo14bo$34b2o2b3o$33b2o3b2obo$32b3o2b2ob3o$33bob3ob3obo
24bo$34b3ob2o2b3o22b3o$35bob2o3b2obo20b3obo$36b3o2b2ob3o18b2o2b3o$37bo
b3ob3obo16b2o3b2obo$38b3ob2o2b3o14b3o2b2ob3o$39bob2o3b2obo14bob3ob3obo
$40b3o2b2ob3o14b3ob2o2b3o$41bob3ob3obo14bob2o3b2o$42b3ob2o2b3o14b3o2b
2o$43bob2o3b2obo14bob3o$44b3o2b2ob3o14b3o$45bob3ob3obo14bo$46b3ob2o2b
3o$47bob2o3b2obo$48b3o2b2ob3o$49bob3ob3obo$50b3ob2o2b3o$51bob2o3b2o$
52b3o2b2o$53bob3o$54b3o$55bo2$92bo$91b3o$69bo20b3obo$68b3o18b2o2b3o$
67b3obo16b2o3b2o$66b2o2b3o14b3o2b2o$65b2o3b2o16bob3o$64b3o2b2o18b3o$
65bob3o20bo9bo$66b3o30b3o$67bo30b3obo$97b2o2b3o$96b2o3b2o$95b3o2b2o$
96bob3o$97b3o$98bo9bo$107b3o$106b3obo$105b2o2b3o$104b2o3b2obo$103b3o2b
2ob3o$89bo14bob3ob3obo$88b3o14b3ob2o2b3o$87b3obo14bob2o3b2obo$86b2o2b
3o14b3o2b2ob3o$85b2o3b2o16bob3ob3obo$84b3o2b2o18b3ob2o2b3o$85bob3o20bo
b2o3b2obo$86b3o22b3o2b2ob3o$87bo24bob3ob3obo$113b3ob2o2b3o$114bob2o3b
2o$115b3o2b2o$101bo14bob3o$100b3o14b3o$99b3obo14bo9bo$98b2o2b3o22b3o$
97b2o3b2o22b3obo$96b3o2b2o22b2o2b3o$97bob3o22b2o3b2o$98b3o22b3o2b2o$
99bo24bob3o$125b3o$126bo2$113bo$112b3o$111b3obo$110b2o2b3o$109b2o3b2o$
108b3o2b2o$109bob3o30bo$110b3o30b3o$111bo9bo20b3obo$120b3o18b2o2b3o$
119b3obo16b2o3b2obo$118b2o2b3o14b3o2b2ob3o$117b2o3b2obo14bob3ob3obo$
116b3o2b2ob3o14b3ob2o2b3o$117bob3ob3obo14bob2o3b2obo$118b3ob2o2b3o14b
3o2b2ob3o$119bob2o3b2o16bob3ob3obo$120b3o2b2o18b3ob2o2b3o$121bob3o20bo
b2o3b2o$122b3o22b3o2b2o$123bo9bo14bob3o$132b3o14b3o$131b3obo14bo9bo$
130b2o2b3o22b3o$129b2o3b2o22b3obo$128b3o2b2o22b2o2b3o$129bob3o22b2o3b
2obo$130b3o22b3o2b2ob3o$131bo9bo14bob3ob3obo$140b3o14b3ob2o2b3o$139b3o
bo14bob2o3b2obo$138b2o2b3o14b3o2b2ob3o$137b2o3b2o16bob3ob3obo$136b3o2b
2o18b3ob2o2b3o$137bob3o20bob2o3b2obo$138b3o22b3o2b2ob3o$139bo24bob3ob
3obo$165b3ob2o2b3o$166bob2o3b2o$167b3o2b2o$153bo14bob3o$152b3o14b3o$
151b3obo14bo9bo$150b2o2b3o22b3o$149b2o3b2o22b3obo$148b3o2b2o22b2o2b3o$
149bob3o22b2o3b2obo$150b3o22b3o2b2ob3o$151bo9bo14bob3ob3obo$160b3o14b
3ob2o2b3o$159b3obo14bob2o3b2o$158b2o2b3o14b3o2b2o$157b2o3b2obo14bob3o$
156b3o2b2ob3o14b3o$157bob3ob3obo14bo$158b3ob2o2b3o$159bob2o3b2obo$160b
3o2b2ob3o$161bob3ob3obo$162b3ob2o2b3o$163bob2o3b2obo$164b3o2b2ob3o$
165bob3ob3obo$166b3ob2o2b3o$167bob2o3b2o$168b3o2b2o$169bob3o$170b3o$
171bo4$185bo$184b3o$183b3obo$182b2o2b3o$181b2o3b2o$180b3o2b2o$181bob3o
$182b3o$183bo!

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

Re: Script request thread

Post by Sokwe » March 14th, 2016, 7:47 pm

drc wrote:I meant like the second image on this page
I actually found this particular reaction by hand (amazingly). I did write a script for searching for pushes in highlife, but I can't find it right now. The script was extremely simple. Basically, it took an input stationary object and then formed all binary sequences (that start with '1') up to a certain length. The binary sequence represented the placement of the replicator units, so the sequence "111011001" would give

Code: Select all

x = 37, y = 37, rule = B36/S23
2b3o$bo2bo$o3bo$o2bo$3o3b3o$5bo2bo$4bo3bo$4bo2bo$4b3o3b3o$9bo2bo$8bo3b
o$8bo2bo$8b3o4$18b3o$17bo2bo$16bo3bo$16bo2bo$16b3o3b3o$21bo2bo$20bo3bo
$20bo2bo$20b3o8$34b3o$33bo2bo$32bo3bo$32bo2bo$32b3o!
It would then test every collision of this sequence with the stationary object and would check to see if the stationary object had moved diagonally after a certain fixed number of generations. It also checked to see if the the stationary object moved, but also flipped over the center diagonal (to find glide-symmetric pushes with two replicators, like Hickerson's (8,8) push).

As I recall, all my search managed to do was rediscover the above push, and find a few block pushes that flipped the block over the center diagonal, but left a bunch of extra debris which interacted too heavily with the replicators, making any clean push reaction difficult. It might have been possible to create a very long sequence of replicators that would slowly clear this debris, but it would probably have been difficult to do without destroying the front block.

I suppose this method could be applied to other rules with replicators, but the code would need to be reworked to match that rule. Anyway, my code wasn't great, and certainly could have missed some things. It might be better if someone just wrote a new script.

I never looked for pull reactions, since we already had such a nice one, but the method would essentially be the same. However, with pull reactions, I think one would have less of an ability to clean up trailing debris, because the pulled object would get in the way of the replicators, not allowing them to clear any debris behind them.
-Matthias Merzenich

User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Re: Script request thread

Post by Apple Bottom » March 17th, 2016, 8:01 am

biggiemac wrote:This'll probably work. I tested it for spaceships, still lives and oscillators. Just select a rectangle in golly containing only the pattern you care about (plus any amount of empty space) and the apgcode of the object will go to your clipboard. As a side effect, the script makes a new layer.

You can certainly get nonsense out of it, by selecting an active object or multiple disjoint objects. But if you use it well it'll do the right thing.
It's not working for me. No matter what object I'm trying this one (except for the block, that's working somehow), I'm getting the following error:

Code: Select all

Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "apgcode-to-clipboard.py", line 113, in <module>
        canonise()
    File "apgcode-to-clipboard.py", line 41, in canonise
        representation = compare_representations(representation, canonise_orientation(rect[2], rect[3], rect[0], rect[1], 1, 0, 0, 1))
IndexError: list index out of range
Any ideas?
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

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

Re: Script request thread

Post by dvgrn » March 17th, 2016, 9:15 am

Apple Bottom wrote:IndexError: list index out of range...
Any ideas?
Is it possible that you selected the block, but did not select the other objects?

The only way I can think of that that line of code could return a list index out of range error, is if the selection list comes back as [] (no selection) instead of [x,y,w,h].

User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Re: Script request thread

Post by Apple Bottom » March 17th, 2016, 6:09 pm

dvgrn wrote:Is it possible that you selected the block, but did not select the other objects?

The only way I can think of that that line of code could return a list index out of range error, is if the selection list comes back as [] (no selection) instead of [x,y,w,h].
Ah, no, I found it; Golly was still set to a different rule, one in which the block happened to exist as a still life but where other objects didn't behave as in CGoL.

Thanks for the help, and sorry for the fuss. ;)
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » April 7th, 2016, 6:11 pm

drc wrote:A script that tallies the current objects on screen and outputs them apgsearch-style
anybody have this? sorry for being annoying

User avatar
gameoflifeboy
Posts: 474
Joined: January 15th, 2015, 2:08 am

Re: Script request thread

Post by gameoflifeboy » April 8th, 2016, 11:51 pm

Here's a script I made for that based on Nathaniel's pre-soup-search census program. It'll be improved later, but for now it opens a text file containing a list of all the distinct patterns displayed of period less than 47. It isn't good at separating objects yet.

Code: Select all

import golly as g
cens_list = []
clist = []
axx = [1,1,-1,-1,0,0,0,0]
ayy = [1,-1,1,-1,0,0,0,0]
axy = [0,0,0,0,1,1,-1,-1]
ayx = [0,0,0,0,1,-1,1,-1]

census_path = g.getdir('temp') + "census.txt"

# --------------------------------------------------------------------

def getRLE(rl_list):
   rle_res = ""
   rle_len = 1
   rl_list.sort(cmp = lambda x,y: (x[0]-y[0])+500*(x[1]-y[1]))
   rl_y = rl_list[0][1] - 1
   rl_x = 0
   for rl_i in rl_list:
      if rl_i[1] == rl_y:
         if rl_i[0] == rl_x + 1:
            rle_len += 1
         else:
            if rle_len == 1: rle_strA = ""
            else: rle_strA = str (rle_len)
            if rl_i[0] - rl_x - 1 == 1: rle_strB = ""
            else: rle_strB = str (rl_i[0] - rl_x - 1)

            rle_res = rle_res + rle_strA + "o" + rle_strB + "b"
            rle_len = 1
      else:
         if rle_len == 1: rle_strA = ""
         else: rle_strA = str (rle_len)
         if rl_i[1] - rl_y == 1: rle_strB = ""
         else: rle_strB = str (rl_i[1] - rl_y)
         if rl_i[0] == 1: rle_strC = "b"
         elif rl_i[0] == 0: rle_strC = ""
         else: rle_strC = str (rl_i[0]) + "b"
         
         rle_res = rle_res + rle_strA + "o" + rle_strB + "$" + rle_strC
         rle_len = 1

      rl_x = rl_i[0]
      rl_y = rl_i[1]
   
   if rle_len == 1: rle_strA = ""
   else: rle_strA = str (rle_len)
   rle_res = rle_res[2:] + rle_strA + "o"
   
   return rle_res

# --------------------------------------------------------------------

def chunks(l, n):
    for i in range(0, len(l), n):
        yield tuple(l[i:i+n])

# --------------------------------------------------------------------

def census():
   keylist = []

   # Set cct_limit to the maximum number of generations that you want to look for oscillation
   # when building the census. Can be made precise in conjunction with Golly's included oscar.py script
   cct_limit = 46
   
   cct = 1
   cens = {}
   clist = list (chunks (g.getcells (g.getrect()), 2))
   
   cens_list = set(clist[:])
   while cct <= cct_limit:
      g.run(1)
      clist = list (chunks (g.getcells (g.getrect()), 2))
      cens_list = cens_list | set (clist)
      cct += 1
   cens_list = list(cens_list)
   
   while len(cens_list) > 0:
      wt = {}
      curcells = [cens_list.pop(0)]
      for j in curcells:
         g.dokey( g.getkey() )            # allow keyboard interaction
         wu = {}
         tlist=cens_list[:]
         for i in tlist:
            c_dist = [abs(i[0] - j[0]), abs(i[1] - j[1])]
            if (max(c_dist) == 2):
               try:
                  if(wt[i] == 1):
                     curcells.append (i)
                     cens_list.remove (i)
               except:
                  wt[i] = 1
               wu[i] = 1
            elif (max(c_dist) <= 1):         
               curcells.append (i)
               cens_list.remove (i)
         if(len(wu) >= 2):
            for i in wu:
               if not i in curcells:
                  curcells.append (i)
                  cens_list.remove (i)
         
      tccells = curcells[:]
      for j in tccells:
         if not j in clist:
            curcells.remove(j)
     
      if len(curcells) > 0:
         pllist = []
         rlelist = []
         for i in range(0,len(curcells)):
            pllist.append(curcells[i][0])
            pllist.append(curcells[i][1])

         for i in range(0,8):
            rotlist = list (chunks (g.transform(pllist,0,0,axx[i],axy[i],ayx[i],ayy[i]), 2))
            mcc = min(rotlist)
            rotlist = [[x[0]-mcc[0],x[1]-mcc[1]] for x in rotlist]
            curRLE = getRLE(rotlist)
            rlelist.append(curRLE)

         intlist = list(set(keylist) & set(rlelist))
         
         if(len(intlist) > 0):
            cens[intlist[0]] += 1
         else:
            keylist.append(curRLE)
            cens[curRLE] = 1
      
   return cens

censdict = census()

cens = []

for rle in censdict:
   cens.append((rle, censdict[rle]))

cens.sort(key=lambda tup: tup[1])

cens.reverse()

f = open(census_path, 'w')

for tup in cens:
   f.write("%s\t%d\n" % (tup[0], tup[1]))

f.close()

g.open(census_path)

shouldsee
Posts: 406
Joined: April 8th, 2016, 8:29 am

Re: Script request thread

Post by shouldsee » April 9th, 2016, 9:33 pm

Is there any script capable of searching under 3-state totalistic rules?

Sample patterns of my interest: flashbf7

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » April 13th, 2016, 8:52 pm

Is there a non-totalistic explosive rule oscillator search? (and link if available)

shouldsee
Posts: 406
Joined: April 8th, 2016, 8:29 am

Re: Script request thread

Post by shouldsee » April 24th, 2016, 7:00 am

How do I measure cleanness (of puffers) in multi-state rules?

Update:
I also need a script to generate reactions between objects. At the moment I am thinking about reacting a engine with itself. But I am stuck in varying the phases of the engine.

My current script for such function:

Code: Select all

# ship=g.parse(g.getstring("RLE string for your seed","3bo$2b4o$b9o$6ob2ob2o$b9o$2b4o$3bo!"))
def add_ship(x,y):
	g.putcells(ship, x, y, 1, 0, 0, 1, "or")
	

def add_ships(x_1,y_1,x_2,y_2):
	g.select([-10,10,20,20])
	g.clear(1)
	g.clear(0)
	add_ship(0,0)
	add_ship(x_1,y_1)
	add_ship(x_1+x_2,y_1+y_2)


shouldsee
Posts: 406
Joined: April 8th, 2016, 8:29 am

Re: Script request thread

Post by shouldsee » May 4th, 2016, 12:40 pm

I would like a script that output a video as a .mc file according to a series of cellist.

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » June 5th, 2016, 11:37 am

n-cell Spatially connected pattern search.

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

Re: Script request thread

Post by dvgrn » June 5th, 2016, 11:51 am

drc wrote:n-cell Spatially connected pattern search.
Meaning, a script that exhaustively enumerates all n-cell polyplets?

Or will you want to do something with the polpylets once you have them, like run them through apgsearch and see what comes out?

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » June 5th, 2016, 12:17 pm

dvgrn wrote:
drc wrote:n-cell Spatially connected pattern search.
Meaning, a script that exhaustively enumerates all n-cell polyplets?

Or will you want to do something with the polpylets once you have them, like run them through apgsearch and see what comes out?
Not exactly polyplets, for example:

Code: Select all

x = 3, y = 2, rule = B3/S23
o$2bo!
That is not a polyplet, but it is spatially connected. Pretty much, search every pattern of n cells, but throw away the ones that have a cell that is isolated by 2 neighbours, to prevent it searching things like this forever:

Code: Select all

x = 192, y = 47, rule = B3/S23
191bo46$o!

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

Re: Script request thread

Post by dvgrn » June 5th, 2016, 2:43 pm

drc wrote:
dvgrn wrote:
drc wrote:n-cell Spatially connected pattern search.
Meaning, a script that exhaustively enumerates all n-cell polyplets?
Not exactly polyplets... Pretty much, search every pattern of n cells, but throw away the ones that have a cell that is isolated by 2 neighbours...
Does that apply to sufficiently separated groups of cells? Maybe a pattern with isolated groups of two cells should also be thrown away, since it's bound to be equivalent to the same pattern without the domino or diagonal spark... but isolated groups of three or more cells we have to keep, unless it can be shown that they disappear quickly without interacting with anything (?).

What about orientation? It's pretty easy to throw out seven out of eight orientations of most spatially connected patterns, on the grounds that it's equivalent to another pattern that sorts lower on a list (according to some arbitrary sort criteria.)

And again, is the idea to run each of these through apgsearch, or something else?

drc
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm

Re: Script request thread

Post by drc » June 5th, 2016, 2:51 pm

No for the two cell, yes for the symmetry discarding, and yes for apgsearch. Sorry if I wasn't clear

Post Reply