Page 1 of 1

Help for Golly script needed

Posted: January 3rd, 2015, 5:57 pm
by HartmutHolzwart
I want to find a way to create a second blinker trail from one 17c/45 pi blinker trail and appropriate gliders.

The best partial result I have so far is the following (just to illustrate where I want to get):

Code: Select all

x = 179, y = 430, rule = B3/S23
8$26bo$26bo$26bo16$25b3o16$26bo$26bo$26bo16$25b3o16$26bo$26bo$26bo16$
25b3o16$26bo$26bo$26bo16$25b3o136b2o$163b2o$165bo4$152b3o$152bo$153bo
3$142bo$141b2o$141bobo3$26bo$26bo103b2o$26bo103bobo$130bo4$119b2o$118b
2o$120bo4$107b3o$107bo$108bo3$25b3o69bo$96b2o$96bobo4$85b2o$85bobo$85b
o4$74b2o$26bo46b2o$25b3o47bo$24b2ob2o3$62b3o$26bo35bo$24bo3bo34bo$22bo
7bo$22bo7bo$22b2ob3ob2o21bo$51b2o$51bobo2$15b2o4b2o7b2o4b2o$15bobob2o
11b2obobo$18b2o5bobo5b2o$20b2o3bobo3b2o$13bo7b2o7b2o7bo$12b2o6bo4bobo
4bo6b2o$12bo7b2o3bobo3b2o7bo$13bobo8bo3bo8bobo$13bo2bo19bo2bo$14b2o21b
2o3$26bo$26bo$26bo3$25b3o$24bo3bo$24b2ob2o3$17bo17bo$15b3o3b2o7b2o3b3o
$14bo4bo2bo7bo2bo4bo$14bo3bo15bo3bo$14bo5b4o5b4o5bo$15b2o4b2o7b2o4b2o$
17b3o13b3o$18b2o13b2o$19bo3bo5bo3bo2$20bo2bo5bo2bo$21bobo5bobo2$26bo$
26bo$26bo6$26bo$26bo$25bobo$21bo9bo$21bo9bo$19b4ob2ob2ob4o$18b2o4bobob
o4b2o$17bo5bo2bo2bo5bo$18b2o2b3o3b3o2b2o$21bo2bo3bo2bo$21bobo5bobo$21b
obo5bobo4$20bo5bo5bo$18b2obo4bo4bob2o$17b3obo4bo4bob3o$15b2o2b2o11b2o
2b2o10$25b3o$25b3o$24bo3bo$24b2ob2o7$21bobo2bo2bobo$21b2o3bo3b2o$22bo
3bo3bo3$15b3ob2o11b2ob3o$15bobob2o11b2obobo$17bo2b2o9b2o2bo$18b6o5b6o$
12b2o5bo13bo5b2o$11bo2bo4b2o2bo5bo2b2o4bo2bo$11b2obo5b3o7b3o5bob2o$11b
2ob2o21b2ob2o6$25b3o2$25bobo$25bobo$24bo3bo$24bo3bo$24b2ob2o4$22bo7bo$
14bob6obo5bob6obo$12b3ob6o9b6ob3o$14bo2bo2b5o3b5o2bo2bo$14bobo4bobo5bo
bo4bobo$15bo21bo$16b3obo11bob3o$17b3o13b3o6$25b3o13$26bo$25b3o$24b2ob
2o!
Note that this example would work, if only the blinker trail were in the other phase!

To more systematically explore the possibilities, I want to write a Golly Python script that basically should work as follows:

# Search for glider collisions with a 17c/45 pi blinker row
# that produce still lifes farther away than 18 cells from the blinker
# the ultimate goal is to produce a second blinker trail for use
# in an alternative caterpillar design
# the algorithm works as follows:
# 1. read and decode next glider pi collison from an appropriate gencols result file
# 2. store pattern
# 3. run pattern for 270 generations
# 4. test result
# 4.1. pi-blinker row survived?
# If no then go to 1.
# 4.2. Debris nearer to blinker row than 15 cells?
# If yes then go to 1.
# 4.3. Debris farther away from blinker row than 18 cells?
# if yes then store result in the resul file and go to 1.
# 5. insert another pi in the blinker row and go to 2.

So further pies are added to the trail of the blinker row until either the debris gets either too close to the blinker row to be useful or too far away to be modified by another pi from the blinker row. The result file should then contain at least the example above, but hopefully some more results.

To implement this idea, I need a way to extract the current debris from the blinker trail (XOR with the pure blinker trail) and determine the distance to the blinker trail.

How can I tackle this?

Re: Help for Golly script needed

Posted: January 4th, 2015, 12:26 pm
by simsim314
You can g.getcells(rect) for the rectangle where your debris could be found. Then you can simply g.putcells into new() golly doc, and use g.getrect(). If rect[0] >= 18 then SUCCESS.

Re: Help for Golly script needed

Posted: January 6th, 2015, 1:26 pm
by HartmutHolzwart
how can I debug a Golly python script?

Re: Help for Golly script needed

Posted: January 6th, 2015, 1:35 pm
by codeholic
Usually I use g.show for displaying variable values I want to track. Or g.exit with a parameter. Another useful trick for debugging is

Code: Select all

g.update()
while g.getkey() == '':
  pass

Re: Help for Golly script needed

Posted: January 6th, 2015, 2:12 pm
by HartmutHolzwart

Code: Select all

# Search for glider collisions with a 17c/45 pi blinker row
# that produce still lifes farther away than 18 cells from the blinker
# the ultimate goal is to produce a second blinker trail for use
# in an alternative caterpillar design
# the algorithm works as follows:
# 1. read and decode next glider pi collison from gencols result file
# 2. store pattern
# 3. run pattern for 270 generations
# 4. test result
# 4.1. pi-blinker row survived?
# If no then go to 1.
# 4.2. Debris nearer to blinker row than 15 cells?
# If yes then go to 1.
# 4.3. Debris farther away from blinker row than 18 cells
# if yes then store result and go to 1.
# 5. insert another pi in the blinker row and go to 2. 

from glife.base import *

rule("B3/S23")

one_pi = pattern ("""
14bo$14bo$14bo16$13b3o16$14bo$14bo$14bo16$13b3o13$14bo$13b3o$12b2ob2o
4$14bo$12bo3bo$10bo7bo$10bo7bo$10b2ob3ob2o4$3b2o4b2o7b2o4b2o$3bobob2o
11b2obobo$6b2o5bobo5b2o$8b2o3bobo3b2o$bo7b2o7b2o7bo$2o6bo4bobo4bo6b2o$
o7b2o3bobo3b2o7bo$bobo8bo3bo8bobo$bo2bo19bo2bo$2b2o21b2o!
""")
pi_bnd = getminbox (one_pi)

# 2.
# a test pattern
current_pi_glider_coll = pattern("""
4$20bo$20bo$20bo16$19b3o16$20bo$20bo$20bo16$19b3o16$20bo$20bo$20bo16$
19b3o16$20bo$20bo$20bo16$19b3o16$20bo$20bo$20bo16$19b3o16$20bo$20bo$
20bo16$19b3o16$20bo$20bo$20bo16$19b3o16$20bo$20bo$20bo16$19b3o13$20bo$
19b3o$18b2ob2o4$20bo$18bo3bo$16bo7bo$16bo7bo$16b2ob3ob2o21bo$45b2o$45b
obo2$9b2o4b2o7b2o4b2o$9bobob2o11b2obobo$12b2o5bobo5b2o$14b2o3bobo3b2o$
7bo7b2o7b2o7bo$6b2o6bo4bobo4bo6b2o$6bo7b2o3bobo3b2o7bo$7bobo8bo3bo8bob
o$7bo2bo19bo2bo$8b2o21b2o!
""",0,0)

TRAILX = 20 # position of primary blinker trail

current_work_pattern = pattern ()
all_deb = pattern()
d_bnd = rect()

#3. run pattern for 180 generations

current_work_pattern = current_pi_glider_coll[180]
current_work_pattern.display ("start loop ")
count = 0
while True:
  cwp_bnd = getminbox (current_work_pattern)

#4 test pattern
#4.1 test whether pi blinker row ist still intact
# to be implemented
#4.2 extract debris
  debris = pattern(golly.getcells([25,230,70,200]))
  all_deb += debris(count*50,400)
  d_bnd = getminbox (debris)
  if (d_bnd.left < 35): break # too close
  if (d_bnd.left > 38): break # too far 
  dy = -19
  current_work_pattern += one_pi (6,cwp_bnd.top + cwp_bnd.height -34 + dy)
  current_work_pattern.put

  cwp_bnd = getminbox (current_work_pattern)
  GEN = 90*(int((cwp_bnd.top + cwp_bnd.height - d_bnd.top + 67)/68)+2)

#  if (count == 6): break
  current_work_pattern = current_work_pattern[GEN]
  current_work_pattern.put
  golly.update
  count += 1
  if (count > 6): break

# cwp_bnd = getminbox (current_work_pattern)
all_deb += current_work_pattern
all_deb.display ("current_pattern " + str(count))

golly.show("count: " + str(count) + " cwp left: " + str(cwp_bnd.left) + " top: " + str(cwp_bnd.top) + " width: " + str(cwp_bnd.width) + " height: " + str(cwp_bnd.height) +
           " debris left: " + str(d_bnd.left) + " top: " + str(d_bnd.top) + " width: " + str(d_bnd.width) + " height: " + str(d_bnd.height) + " gen: " + str(GEN))
 
The debris pattern is not updated in the while-loop. Why?

Re: Help for Golly script needed

Posted: January 6th, 2015, 2:19 pm
by simsim314
You have also g.note().

Debugging script could be frustrating at first. I would also suggest to make "unit tests" for each dedicated function.

Many times I write my script in steps. Say I want to create HBK gun so I do the following steps:

1. Read SLs into list.
1a. Read single SL and see what I get with g.show()
1b. Read several SLs
1c. Read the hole spaceship and rebuilt it again - see if everything worked. If not see what went wrong -> back to step 1a+1b.

2. Than I need to build a gun, I also divide the script into steps:

2a. Place single gun and see where the glider is.
2b. Place several guns and see how they interact.
2c. Use guns to generate single recipe for SL.
2d. Place several recipes and see if there are problems.
2e. Place the whole gun.

----

Each step is verified with g.show(), and other indications, which make me confident enough to move to the next phase.

Obviously this is not exactly linear sequence, you can get back and forth, you may also skip steps in the middle. But this is the "general" approach I take. And if something goes wrong, I make sure I go back step or two, and figure out where I went wrong. Having simple cases to play with, and make sure everything working up until some point - while advancing slowly is the best way to go for coding in general.

If you need debugging, it's already "bad" sign. Not saying you always don't need to debug, but debugging is kinda treating the symptoms instead of the disease - which is bad coding and development habits. Of course I also use traces and debug stuff, just saying you should avoid the "need" for debug, and find a way to develop your code systematically enough, and cleanly enough, that if something goes wrong, you will know very fast where to look, and look, using cases and tests.

Take a look at test driven development concept to get a grasp of what I'm talking about. I'm not suggesting to use this concept, I personally dislike many of the ideas in it, but understanding the basic concept, gives you a lot of tools to free you from the "extreme need for debug".

Actually there is something bad about debugging. You fix small and single case, without verifying everything else works properly, without "learning". Instead you can create extra test, to make sure everything works right. If you "start" from test cases, and make sure they work - even if you have a bug, you will know to add extra test case to your tests list, and make sure this will not happen again + you will know everything else is still working properly.

Re: Help for Golly script needed

Posted: January 6th, 2015, 2:45 pm
by simsim314
HartmutHolzwart wrote:The debris pattern is not updated in the while-loop. Why?
You don't update your state in golly. The only place you have added something into golly state, is in the line:

Code: Select all

current_work_pattern.display ("start loop ")
After this you just manipulate pattern, move them, add them but you don't update golly state at all.

So the value of:

Code: Select all

golly.getcells([25,230,70,200])
Will obviously not change. The value of all_deb is changing in the while loop.

By the way why don't you just place the same pattern into golly, run it a bit (untill the pattern left it's envelope + delta), place the same pattern again in the moved place to adjust to blinkers movement (maybe have two patterns to avoid parity problems with blinkers), run again etc. I think it will make your life so much easier.

Also don't afraid to add bunch of gliders, you can add them into the initial pattern. It could influence the performance, but not so much - and you will not need to think about stuff like all_deb += debris(count*50,400). Which is by the way slower than placing the pattern into golly and run it. The reason is that golly is written in c, so it will work faster than adding lists in python (while evolving the patterns uses the same golly mechanism so no optimization is expected there).

Re: Help for Golly script needed

Posted: January 6th, 2015, 3:11 pm
by HartmutHolzwart
the all_deb is just meant as a debugging aid.

I'm sure there are a lot of other (and maybe simpler) ways to do the same thing:

Modify the debris with further pies until either the debris is to close (and will destroy the next pi) or too far away to be reached by following pies.

What should I do such that the debris pattern is updated with the current debris after applying the last pi?

Re: Help for Golly script needed

Posted: January 6th, 2015, 3:53 pm
by simsim314
They way you wrote it, you should "apply" the last pi into golly. You join the pattern objects but you don't place them into golly. On the other hand you take the debris from golly state, which is not updated. Just use display or put and only then getcells.

Re: Help for Golly script needed

Posted: January 6th, 2015, 4:08 pm
by HartmutHolzwart
... adding a display-command did the trick!

Thanks for your help!

That was just a first try.

What I actually should do is to update the original pattern and write out rthe result to a file.

Then write a routine to read through the gencols output, decode into golly line by line, run it through the routine and write out all positive results...

And then hope that one of the results is a simple blinker.

Re: Help for Golly script needed

Posted: January 6th, 2015, 4:10 pm
by simsim314
Oh sorry, this one is annoying...

use current_work_pattern.put() instead of current_work_pattern.put. I think it looks correct, after this fix.

Re: Help for Golly script needed

Posted: January 6th, 2015, 4:41 pm
by HartmutHolzwart
thanks again!!!

Re: Help for Golly script needed

Posted: February 20th, 2015, 10:59 am
by Scorbie
I came here to post another help needed in Golly Script.
I started to write a script for GUI frontends in general, that allows loading, editng and saving input files.
Currently it is in a very early stage. I'll attatch the code here for someone who's interested. Any kind of advice is welcome.

Code: Select all

import golly as g
import time
import os

class FileManager:
    
    def __init__(self):

        self.filepath = None
        
        
    def load(self):
        
        self.filepath = g.opendialog()
        
        
    def save(self):
        
        g.savedialog()
        
class SettingManager:
    def __init__(self):
        pass
        
    def restoresettings(self):
        pass
        
        
class TabManager:
    pass
class EventHandler:
    
    def __init__(self):
        '''TODO: finish docsting of EventHandler'''
        
        g.setoption('drawingstate', 1)
        
        filemanager = FileManager()
        settingmanager = SettingManager()
        tabmanager = TabManager()
        
        # Dict of reserved actions
        # The keys are user inputs, and the values are actions as
        # zero-parameter functions. The docstrings of these functions
        # are shown in the help message.
        # Note that drawstatefunc(x) itself is a zero-param function.
        self.reserved_actions = {\
            'key 0 none': self.drawstatefunc(0),\
            'key 1 none': self.drawstatefunc(1),\
            'key 2 none': self.drawstatefunc(2),\
            'key 3 none': self.drawstatefunc(3),\
            'key 4 none': self.drawstatefunc(4),\
            'key 5 none': self.drawstatefunc(5),\
            'key a none': self.selectall,\
            'key delete none': self.clearinsel,\
            'key delete shift': self.clearoutsel,\
            'key tab none': self.step,\
            'key h none': self.showhelp,\
            #'key i none': self.showparams,\
            #'key i ctrl': self.showparams,\
            #'key s ctrl': filemanager.save,\
            #'key o ctrl': filemanager.load\
            }
    
    def keyrepr(self, event):
        '''Represent keyboard actions as appropriate strings.'''
        string = ''
        evt, button, mods = event.split()
        if evt != 'key':
            raise TypeError(\
                "function 'keyrepr' only takes keyboard events.")
        if 'alt' in mods:
            string += 'Alt+'
        if 'ctrl' in mods:
            string += 'Ctrl+'
        if 'shift' in mods:
            string += 'Shift+'
        string += button
        return string
            
            
    # Keyboard actions
    
    def drawstatefunc(self, x):
        def f():
            g.setoption('drawingstate', x)
        f.__doc__ = '''set drawing state to ''' + str(x)
        return f

    def showhelp(self):
        '''Show help and list of keyboard shortcuts.'''
        helpcontent = '<html>'+\
            '<title>GUI Keyboard Shortcuts</title>'+\
            '<body bgcolor="#FFFFCE">'+\
            '<p><font size=+1>'+\
            '<b>Keyboard shortcuts</b></font>'+\
            '<p>Use to change the following keyboard shortcuts:'+\
            '<p><center>'+\
            '<table cellspacing=1 border=2 cols=2 width="90%">'+\
            '<tr><td align=center>Key Combination</td>'+\
                '<td align=center>Action</td></tr>'
        for event in self.reserved_actions:
            helpcontent += '<tr>'+\
                '<td align=right>'+self.keyrepr(event)+'&nbsp;</td>'+\
                '<td>&nbsp;'+self.reserved_actions[event].__doc__+\
                '</td></tr>'
        helpcontent += '</table></center></body></html>'
        helppath = os.path.join(g.getdir('temp'),\
            'BellmanGUI_keyboard.html')
        try:
            with open(helppath, 'w') as helpfile:
                helpfile.write(helpcontent)
                g.open(helppath)
        except:
            raise
        
    def showparams(self):
        '''Show the settings in the bellman file.'''    
        # Finish this
        pass
        
    def selectall(self):
        '''Select all'''
        g.select(g.getrect())
        
    def clearinsel(self):
        '''Clear inside selection'''
        g.clear(0)
        
    def clearoutsel(self):
        '''Clear outside selection'''
        g.clear(1)
        
    def step(self):
        '''Next step'''
        g.step()
        
    # Action
    
    def getevent(self):
        '''Get user key event and do appropriate actions.'''

        self.event = g.getevent()
        
        # Handle mouse events
        if self.event.startswith('click'):
            evt, x, y, button, mods = self.event.split()
            x = int(x)
            y = int(y)
            if button == 'left':
                drawingstate =  g.getoption('drawingstate')
                if g.getcell(x, y) == drawingstate:
                    g.setcell(x, y, 0)                
                else:
                    g.setcell(x, y, drawingstate)
            elif button == 'right':
                # TODO: implement selection
                pass
        # Handle key events
        elif self.event in self.reserved_actions:
            self.reserved_actions[self.event]()
        else:
            g.doevent(self.event)
            
        # For event analysis
        #g.show(self.event)
        #time.sleep(0.3)
           
# Start here
g.autoupdate(True)

eventhandler = EventHandler()
while True:
    eventhandler.getevent()
I have this question: after running the script and pressing 'h', golly writes a file in golly's temp directory and shows it with g.open(). However, Golly opens a blank white page. Something stranger is that golly opens the page correctly after going to 'contents' then '<' which means that the html itself probably doesn't have any problems. Any ideas?

Re: Help for Golly script needed

Posted: February 21st, 2015, 3:19 am
by Andrew
Try inserting "helpfile.close()" before calling "g.open(helppath)".

Re: Help for Golly script needed

Posted: February 21st, 2015, 7:03 am
by Scorbie
Andrew wrote:Try inserting "helpfile.close()" before calling "g.open(helppath)".
Thanks! That worked perfectly!
(And since python's with file as filename statement automatically closes the file at the end of the block, merely unindenting g.open() once would do the same.)

Re: Help for Golly script needed

Posted: April 27th, 2015, 6:14 am
by Scorbie
Hi. I am currently working on a Golly GUI front end with almost the same feel as Golly itself. I am wondering whether it is possible to implement key_up events? i.e. in dragging or selecting.

Re: Help for Golly script needed

Posted: April 27th, 2015, 7:44 am
by simsim314
Scorbie wrote:I am wondering whether it is possible to implement key_up events?
I think this is the most frequent request for golly python .

Anyway you could select using the regular selection tool and then use g.getselrect().

Re: Help for Golly script needed

Posted: April 27th, 2015, 8:38 am
by Scorbie
simsim314 wrote:Anyway you could select using the regular selection tool and then use g.getselrect().
Hehe I was thinking about interactive selection. i.e. naturally selecting by mouse:-)
simsim314 wrote:I think this is the most frequent request for golly python.
Not implemented yet, I guess! Hope to find a way to bypass it.

EDIT: Oh, and a far more important thing: Any ideas for Undo/Redo implementation?

Re: Help for Golly script needed

Posted: April 27th, 2015, 9:29 am
by simsim314
Scorbie wrote: Any ideas for Undo/Redo implementation?
It's very complicated. If you want to allow your script to be non-destructive, just save the existing pattern into cells array, and let the user choose - Cancel all operations and return to the original state before your script started to work.

I would also suggest to make save-load functionality using dump into json - if possible (every python script has two things: the state of the internal data + golly - So you just need save-load for your script state, to allow to come back from where the user has stopped). This is simple workaround without having to implement undo-redo.

Re: Help for Golly script needed

Posted: April 27th, 2015, 10:43 am
by Scorbie
simsim314 wrote:I would also suggest to make save-load functionality using dump into json - if possible
Thanks for the suggestion! I originally thought to load/edit/save the .in files directly. Is there some difference between this and json dump file? To me, json dump files "feel" safer somehow... maybe because it seems easier to backup?

Re: Help for Golly script needed

Posted: April 27th, 2015, 11:08 am
by simsim314
Scorbie wrote: json dump files "feel" safer somehow
Json is the standard and very simple. But you don't have to use Json. Your standard could benefit from flexibility and user friendliness that you can provide built in better than Json.

Re: Help for Golly script needed

Posted: December 1st, 2015, 2:39 am
by Scorbie
Sorry for dragging up an old thread. I decided to pick up a long dormant project, and decided to ask for advice before doing so. If you look at the gollygui code above, it's basically the following:

Class EventHandler
  • dict containing keystrokes and functions
  • the functions as a method of this class
  • function to parse keystrokes (not important)
(Or is it? I don't have experience in OOP, or programming in general.)

I'm trying to make this so that one could override the default actions as the following example.
bellmanspecific={"key i none":showInfo(BellmanInputFile)}
bellman = EventHandler(bellmanspecific) # overrides i key to showInfo

My question is, where should I put the dict of keystroke:default actions and the corresponding functions? Outside or inside the class? Currently both are inside the class, but when the user instantiates EventHandler, the overriding function is defined outside the class, which doesn't seem consistent. But again, it seems more structured when I put them inside the class.