Circuit Editor in Golly

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Circuit Editor in Golly

Post by simsim314 » December 17th, 2014, 8:08 am

Golly is cell level editor. In GOL many times we have "logical components" (like reflectos, duplicators, blockic seeds etc.). So we need more tools to allow "Smart Editing". By Smart Editing I mean tools that allow move reflectors, duplicators, place reflectors from gliders, and even manage Hershels from inside golly using input-output interfaces style.

This thread is made to make collection (and collect more request) for logical editors scripts for Golly.

----

For starters, I've wrote a small script that allows moving reflectors while maintaining their function (recognizing them, iterating, keeping on the correct lane).

Code: Select all

#This script recognize set of reflectors, and allows only according movement, while iterating it. 
#Written by Michael Simkin 2014
import golly as g 
import copy

data = []
data.append(["2o5b2o$2o5bo$5bobo$5b2o$b2o$bobo$2bo2$5b3o$5b3o$5b3o$8b3o$8b3o$8b3o!", "P8 Reflector"])
data.append(["22b2o$22bo$11b2o7bobo$11bobo6b2o$6b2o4b3o$5bo2bo4b3o$7bo4b3o$3bo7bobo$2bob2o5b2o$2bo$b2o!", "P30 Reflector", [(1, -1)]])
data.append(["13bo$11b3o$10bo$10b2o3$18b2ob2o$19bob2o$19bo$11b2o4b3o$11b2o3bo3b2o$16b4o2bo$2b2o15bob2o$bobo12b3o2bo$bo13bo5bo$2o14b5o$18bo!", "Snark1"])
data.append(["13bo$11b3o$10bo$10b2o3$18b2o$19bo$19bob2o$11b2o4b3o2bo$11b2o3bo3b2o$16b4o$2b2o15bo$bobo12b3o$bo13bo$2o14b5o$20bo$18bo$18b2o!", "Snark2"])

def FindPeriod(obj):
   evolved = g.evolve(obj, 1)
   
   for i in xrange(1, 1000):
      if str(evolved) == str(obj):
         return i
         
      evolved = g.evolve(evolved, 1)
   
   return -1
   
def GetSize(obj):
   maxX = -1
   maxY = -1
   minX = 1000
   minY = 1000
   
   for i in xrange(0, len(obj), 2):
      if obj[i] > maxX:
         maxX = obj[i]
      
      if obj[i + 1] > maxY:
         maxY = obj[i + 1]
      
      if obj[i] < minX:
         minX = obj[i]
      
      if obj[i + 1] < minY:
         minY = obj[i + 1]
   
   return (maxX - minX, maxY - minY)
   
def GetTransList():
   transList = []
   
   for i in xrange(-1, 2, 2):
      for j in xrange(-1, 2, 2):
         transList.append((i, 0, 0, j))
         transList.append((0, i, j, 0))
   
   return transList
   
def GetObjectClickArray(obj, objName, t, period):
      
   result = []
   
   
   for i in xrange(0, len(obj), 2):
      x = obj[i]
      y = obj[i + 1]
      
      l = copy.copy(obj)
      
      for j in xrange(0, len(obj), 2):
         l[j] -= x
         l[j + 1] -= y
         
      result.append([l, objName, t, period])
   
   return result
   

def GetObjectArray(iniobj):
   result = []
   transList = GetTransList()
   period = FindPeriod(iniobj[0])
   for i in xrange(0, period):
      
      obj = g.evolve(iniobj[0], i)
      
      for t in transList:
         dxx, dxy, dyx, dyy = t
         curobj = g.transform(obj, 0, 0, dxx, dxy, dyx, dyy)
         
         result.extend(GetObjectClickArray(curobj, iniobj[1], t, period))
      
   return result 
   
def IsObjectExists(objectArray, x, y):
   for obj, objName, t, p in objectArray:
      found = True
      
      for i in xrange(0, len(obj), 2):
         dx = obj[i]
         dy = obj[i + 1]
         
         if g.getcell(x + dx, y + dy) == 0:
            found = False
            break

      if found:
         return [obj, objName, x, y, t, p]
   
   return None
   
def GetObjectByClick(event):   
   
   x = int(event.split()[1])
   y = int(event.split()[2]) 
   
   found = False
   
   for i in [0, -1, 1, -2, 2]:
      for j in [0, -1, 1]:
         if found:
            break
            
         o =  IsObjectExists(objectArray, x + i, y + j)
         
         if o != None:
            g.show("found!")
            
            for k in xrange(0, len(o[0]), 2):
               dx = o[0][k]
               dy = o[0][k + 1]
               
               g.setcell(x + i + dx, y + j + dy, 0)
               
            found = True

            g.update()
            
            
   if    found:
      return o
   else :
      return None
      
def ClearRect(x, y, w, h):
   for i in xrange(0, w):
      for j in xrange(0, h):
         g.setcell(x + i, y + j, 0)

def GetDirection(t):
   dxx, dxy, dyx, dyy = t
   
   if dxy == 0:
      return dxx * dyy
   else:
      return dxy * dyx

def GetEvolveDirection(t):
   dxx, dxy, dyx, dyy = t
   
   if dxy == 0:
      return -dxx
   else:
      return -dxy 

def FinishMove(d, w, h, x0, y0, p, t):
	
   under = d[0]
   obj = d[1]
   x = d[2]
   y = d[3]
   
   if under != -1:
      g.putcells(under)
	  
   g.putcells(g.evolve(obj, p + GetEvolveDirection(t) * ((4 * (x - x0)) % p)), x, y)
   
   g.update()
   
def UpdateMove(d, w, h, x0, y0, p, t):
   
   under = d[0]
   obj = d[1]
   x = d[2]
   y = d[3]
   
   
   if under != -1:
      ClearRect(x - w, y - h, 2 * w + 1, 2 * h + 1)
      g.putcells(under)
   
   
   val = g.getxy()
   
   if val == "":
      return 
      
   
   x1 = int(val.split()[0])
   y1 = y0 + GetDirection(t) * (x1 - x0)
   
   d[0] = g.getcells([x1 - w, y1 - h, 2 * w + 1, 2 * h + 1])
   
   #ClearRect(x1 - w, y1 - h, 2 * w + 1, 2 * h + 1)
   
   g.putcells(g.evolve(obj, p + GetEvolveDirection(t) * ((4 * (x1 - x0)) % p)), x1, y1)
   
   g.update()
   
   d[2] = x1
   d[3] = y1
   
def InitUpdateMove(obj, x, y):
   return [-1, obj, x, y]
   
   
objectArray = []

for d in data:
   objectArray.extend(GetObjectArray([g.parse(d[0]), d[1]]))
   
moving = False
g.show("Select known object with left click, exit with right click")
handling = False
searching = False

while True:

   event = g.getevent()
   
   if handling or searching:
      continue 
      
   handling = True

   if "click" in event:
   
      if "right" in event:
         g.show("finish smart movement")
         
         g.exit()
         
      if not moving:
         searching = True
         g.show("searching...")
         g.update()
         
		 
         found = GetObjectByClick(event)
         if found != None:
            p = found[5]
            t = found[4]
            curMove = InitUpdateMove(found[0], found[2], found[3])
            g.show("Found: "  + str(found[1]) + ", click left to place and continue, right to place and exit")
            w, h = GetSize(found[0])
            moving = True
			
         searching = False
		 
      else:
         if "left" in event and not searching:
            moving = False
            FinishMove(curMove, w, h, found[2], found[3], p, t)
            g.show("Object moved, select known object with left click, exit with right click")
            g.update()
         
         
   if moving and event == "":
      UpdateMove(curMove, w, h, found[2], found[3], p, t)
   
   handling = False
Test it with this sample:

Code: Select all

x = 298, y = 155, rule = B3/S23
234b2o3b2o$234b2o2bob3o$238bo4bo$234b4ob2o2bo$234bo2bobobob2o$237bobob
obo$238b2obobo$242bo2$228b2o$229bo7b2o$229bobo5b2o$230b2o7$240b2o$240b
o$241b3o$243bo15$214b2o$213bobo$215bo34$296bo$3o292bo$3o292b3o$3o10bo$
3b3o5b3o$3b3o4bo$3b3o4b2o264bo$276b3o$8bo270bo$7bobo268b2o$8b2o2b2o
136bobo$12b2o136b2o$151bo118b2o$270bo$267b2obo$267bo2b3o4b2o$268b2o3bo
3b2o$270b4o$270bo15b2o$271b3o12bobo$274bo13bo$269b5o14b2o$269bo$271bo$
270b2o11$116bo$116b3o$119bo$118b2o7$120b3o$119bo3bo$118bo5bo$118b2obob
2o6$123b2o$123bo$124b3o$126bo22$75b2o$74b2o$76bo!

I've also cerate Git repository to manage Logical Editors in GOL


@dvgrn - I've fixed the erasing bug. Wanted special thread to manage all the logical editors. I'll add output tree search a bit later.

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

Re: Circuit Editor in Golly

Post by dvgrn » December 17th, 2014, 5:08 pm

simsim314 wrote:@dvgrn - I've fixed the erasing bug. Wanted special thread to manage all the logical editors. I'll add output tree search a bit later.
Looks good! A good goal to look at might be the idea of making a circuit editor that would actually be helpful at tightening up the guns in the new p160 dart gun.

An edge shooter isn't technically a reflector, but it needs exactly the same kind of phasing adjustment if it's moved diagonally. If a component as large as an individual edge shooter can be recognized, then dragging it a few steps closer to a neighbor should be easy enough. The trick is that really close placements tend to require welding or other customization.

Once a weld has been put in place,

A) the edge shooter isn't an exact match for the standard model any more, and
B) the edge shooter and its neighbor should really be considered as one unit for future moves. Or if they're broken apart, the welds should be removed (but maybe remembered in case they get shoved back to minimum distance again later?)

That starts getting pretty tricky. Maybe the first step is to include a library json-or-whatever to which new reflector patterns can be added, and see if a workable GUI can be designed to shove around things as big as guns or edge shooters.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 17th, 2014, 6:55 pm

The guns are a bit different creatures.

We want to leave the "output" glider at place, and adjust the gun relative to it. So we need few scripts:

1. Click on a glider and the gun will appear automatically at some "safe distance". Right click and the gun "flips" to shoot the same glider form other side (or shows the next available gun). Click another glider, and once again gun is added in even further "safe" distance etc.

2. Take a gun, and move it along a diagonal, while adding and erasing gliders if they recognized as his output, while moving it, you can press "space" and check out the output after say 1000 generations (or gun period *5). This way you can "micro adjust" your gun pretty quickly. Also we should allow more accurate movement by typing the move step (or arrow keys to move it one cell diagonally).

---

Regarding the performance search issue: One way to optimize the search is to have "hash table" around the area of the click. Having say 5x5 square hashed, will reduce the search options very quickly.

Obviously json is important addition. Having 160 period with 100 cells gun, and 8 orientations - becomes somewhere around 12M of data. We can define the gun itself in the script, just need to save json first time the script executes. Next time the script will initialize much faster.

---

Do you think we need more functionality?

EDIT I was thinking about it again. We don't need smart pattern recognition functionality. It's great that we have one, but what we need is "metadata" per cell. We want to know for each cell (or to maximum cells), to which pattern it belongs. i.e. what is the pattern, where it's placed, how it's oriented, what its input and output, what its current internal state etc. We also want the document to hold array of patterns instead of array of cells. When you start from array of gliders, the only thing that needs recognition is the glider. For guns that you place according to the gliders, you can store it all in the metadata. Once you finish, you save the metadata, and once you want to continue working you load the metadata. In general one can "code" any metadata inside the cells of the pattern itself, just place them at distance 2 from each other, but I don't like this idea too much (still we can store something like path to json inside the pattern).

This can also allow working with different prepared patterns, this array of patterns can be part of json. I don't think we need to store the p160 in our constant array of recognizable objects. What we need is to store array of recognizable object inside the json of the current document, and initialize it inside metadata constructor.

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

Re: Circuit Editor in Golly

Post by dvgrn » December 17th, 2014, 10:00 pm

simsim314 wrote:EDIT I was thinking about it again. We don't need smart pattern recognition functionality. It's great that we have one, but what we need is "metadata" per cell. We want to know for each cell (or to maximum cells), to which pattern it belongs. i.e. what is the pattern, where it's placed, how it's oriented, what its input and output, what its current internal state etc.
That seems right. We only need to store one orientation and phase of each object, plus the fact that it's periodic, emits gliders/spaceships/whatever, or is capable of performing a conversion of input object A into output object B.

I've played around with the idea of saving Life patterns as structures off and on for quite a while now, but haven't come up with anything really useful yet. It would be nice to come up with a structured pattern format that's so obviously a good idea that a parser for it can be included in Golly, or at least in Golly's glife package.

Possibly this kind of pattern definition could shrink some large patterns down to where they could be included in Golly's pattern collection. As the link above says, I've always wondered how big a complete high-level description of the Caterpillar would be.

Anyway, yes, the really handy thing would be an editor that groups cells into objects, and small objects into constellations and larger objects, and so on. It could allow editing operations on the highest-level objects only, with an option to ungroup a chosen object into a collection of lower-level objects. Not sure what the GUI would look like for this grouping/ungrouping idea, but the pattern could be displayed in a multistate rule in Golly -- it doesn't have to be instantly runnable, just has to be convertible into a Life pattern on demand. Edits would be saved only as metadata, not (necessarily) as bit patterns.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 17th, 2014, 11:03 pm

Hmm this is interesting - because I was concerned more with logical representation, and you with hierarchy.

Let me explain what is more or less the difference: take the replicator for example. It has some "serial" input output components, but it's not "very" hierarchical. It's of course built out of N herschel conduits and reflectors etc, but you can approach it as series of input->Transormer->output way. You don't need deeply nested hierarchy.

On the other hand you can see that replicator input signal is very versatile and yet has some very distinct "logical meaning". So the "versatility" will come not from hierarchy, but from complex input encoding sequences. So what's actually need logical representation is the glider sequence, that encodes another sequence for slow salvo, which encodes SL building order. This is all part of "smart input" encoding, and less about object hierarchy.

Obviously this is specific property of the replicator, for the universal computer (or take the pi calculator), the hierarchical representation is much more relevant - but still I think this is point we should pay attention to.

---

Anyway I definitely like the idea of switching rules, and representing data in special rule, although the metadata approach could make a lot of micromanagement itself as well, so you will not need anything special shown in golly except the basic pattern itself - unless you just want to colorize the logical entities for the data representation.

I was thinking about how a GUI for logical herschel conduit construction would look like - the problem that there is a lot of conduits, so just displaying not ordered list of conduits is a bad idea. So GUI is definitely an issue, and golly is not really helping out - we need to add side menu of our own, although golly has place for such things in pattern/script menu.

I was also considering to compile Golly myself, to tweak it a bit (for starters to add more events like shift up or mouse up) but I guess it's kinda dead end, asking people to download my version of golly, is a bad direction, and starting to tweak golly sound like story without ending.

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

Re: Circuit Editor in Golly

Post by dvgrn » December 18th, 2014, 8:16 pm

simsim314 wrote:Hmm this is interesting - because I was concerned more with logical representation, and you with hierarchy.

Let me explain what is more or less the difference: take the replicator for example. It has some "serial" input output components, but it's not "very" hierarchical. It's of course built out of N herschel conduits and reflectors etc, but you can approach it as series of input->Trans[f]ormer->output way. You don't need deeply nested hierarchy.
The linear replicator seems like kind of a special case, though. First, the circuitry has been cut down to a bare minimum so there isn't much of a circuit hierarchy. And second, everything is placed very carefully to match a custom construction recipe, so there's really no editing that could usefully be done.

Let's take a different example, where a circuit editor would actually be quite handy: the dart gun currently in progress. One of the standard edge-shooter guns for this project looks like this:

Code: Select all

x = 102, y = 92, rule = B3/S23
39b3o$41bo$40bo19$67b2o$66bobo$60b2o4bo$58bo2bo2b2ob4o$58b2obobobobo2b
o$61bobobobo$61bobob2o$62bo2$32b2o41b2o$32bo15bo9bo7b2o7bo$30bobo15b3o
5b3o7b2o5bobo$30b2o19bo3bo17b2o$50b2o3b2o2$53bo$9b2o41bobo$9b2o41bobo$
53bo$31bo31b2o$29bobo32bo$29b3o9b2o18b3o$29bo11b2o18bo$53b2o$52bo2bo
20b2o$53b2o4b2o14b2o$4b2o5b2o46bobo15bo$5bo5b2o48bo$5bobo53b2o$6b2o43b
2o$10b2o9b2o29bo$9bobo9bo27b3o$6b2o2bo11b3o24bo$24bo4bo$5bo3bo17b3o$4b
o4bo16bo70bo$3bobobo18b2o5bo45b2o14b5o$2bobobo26b2o45bo13bo5bo$o4bo26b
obo45bobo12b3o2bo$o3bo76b2o15bob2o$95b4o2bo$2b2o86b2o3bo3b2o$90b2o4b3o
$16b2o80bo$15bobo5b2o73bob2o$15bo7b2o72b2ob2o$14b2o2$28bo42bo17b2o$24b
2obobo39b3o17bo$23bobobobo38bo21b3o$20bo2bobobob2o37b2o22bo$20b4ob2o2b
o$24bo4bo34bo$20b2o2bob3o36b2o$20b2o3b2o37b2o3$58b2o$57bobo5b2o$57bo7b
2o$56b2o2$70bo$66b2obobo$65bobobobo$62bo2bobobob2o$62b4ob2o2bo$66bo4bo
$62b2o2bob3o$62b2o3b2o!
-- but it's perfectly okay for it to look like this instead, if that fits better:

Code: Select all

x = 122, y = 97, rule = B3/S23
59b3o$61bo$60bo5$101b2o$100bobo$94b2o4bo$92bo2bo2b2ob4o$92b2obobobobo
2bo$95bobobobo$95bobob2o$96bo2$109b2o$100bo8bo$99b3o5bobo$98b5o4b2o$
97b2o3b2o$96b3o3b3o$97b2o3b2o$98b5o$99b3o$98b3o$97b2o$98bo$95b3o19bo$
95bo2b3o14b5o$52b2o43bo2bo13bo5bo$52bo15bo9bo17b2o2bobo12b3o2bo$50bobo
15b3o5b3o22b2o15bob2o$50b2o19bo3bo39b4o2bo$70b2o3b2o33b2o3bo3b2o$110b
2o4b3o$73bo44bo$29b2o41bobo43bob2o$29b2o41bobo42b2ob2o$73bo$51bo$49bob
o57b2o$49b3o9b2o46bo$49bo11b2o47b3o$73b2o37bo$72bo2bo$73b2o4b2o$79bobo
$81bo$81b2o$71b2o$41b2o29bo$41bo27b3o$42b3o24bo$44bo$77bo$75b3o5b2o$
53bo20bo9b2o$53b2o19b2o7bo$52bobo6$64b2o$63bobo5b2o$4b2o5b2o50bo7b2o$
5bo5b2o49b2o$5bobo5bo$6b2o3b2o63bo$10b5o57b2obobo$9bo2bob2o55bobobobo$
6b2o2b5o53bo2bobobob2o$11b3o15bo38b4ob2o2bo$5bo3bo17b3o42bo4bo$4bo4bo
16bo41b2o2bob3o$3bobobo18b2o40b2o3b2o$2bobobo$o4bo$o3bo2$2b2o2$16b2o$
15bobo5b2o$15bo7b2o$14b2o2$28bo$24b2obobo$23bobobobo$20bo2bobobob2o$
20b4ob2o2bo$24bo4bo$20b2o2bob3o$20b2o3b2o!
Or you could even put a twist in the loop, and then there are various movable pairs of reflectors that can be adjusted. Actually that trick does look as if it can save half a dozen rows in the p160 dart gun... I'm not sure how to make an intuitive GUI that can flip over a reflector and add two more flanking Snarks, though, so probably that would have to start out as a different gun variant:

Code: Select all

x = 121, y = 86, rule = B3/S23
39b3o$41bo$40bo19$67b2o$66bobo$60b2o4bo$58bo2bo2b2ob4o$58b2obobobobo2b
o$61bobobobo$61bobob2o$62bo$91b2o$32b2o41b2o14bobo$32bo15bo9bo7b2o7bo
17bo4b2o$30bobo15b3o5b3o7b2o5bobo13b4ob2o2bo2bo$30b2o19bo3bo17b2o14bo
2bobobobob2o$50b2o3b2o35bobobobo$93b2obobo$53bo43bo$9b2o41bobo$9b2o41b
obo28b2o$53bo30bo7b2o$31bo31b2o19bobo5b2o17bo$29bobo32bo20b2o22b3o$29b
3o9b2o18b3o44bo$29bo11b2o18bo46b2o$53b2o$52bo2bo20b2o$53b2o4b2o14b2o
25bo13b2o$4b2o5b2o46bobo15bo25b2o12bo$5bo5b2o48bo33b2o5b2o13bob2o$5bob
o53b2o32bo13b2o4b3o2bo$6b2o43b2o43b3o10b2o3bo3b2o$10b2o9b2o29bo40bo4bo
15b4o$9bobo9bo27b3o41b4obob2o15bo$6b2o2bo11b3o24bo47bobobo12b3o$24bo4b
o65b2o2bo13bo$5bo3bo17b3o64bo2b3o14b5o$4bo4bo16bo67b3o21bo$3bobobo18b
2o5bo63bo18bo$2bobobo26b2o61b2o18b2o$o4bo26bobo$o3bo2$2b2o$65bo$16b2o
45b3o$15bobo5b2o37bo43b2o$15bo7b2o37b2o35b2o5bobo$14b2o83b2o7bo$57bo
50b2o$28bo27b2o$24b2obobo25bob6obo30bo$23bobobobo24b3o2bob2o2b2o27bobo
b2o$20bo2bobobob2o23b2o4bo4bo28bobobobo$20b4ob2o2bo22b3ob2o5b2o26b2obo
bobobo2bo$24bo4bo21bobo4bo3bo28bo2bo2b2ob4o$20b2o2bob3o22bo6bobobo30b
2o4bo$20b2o3b2o23b2o7b3o37bobo$60bo39b2o$64bo$60b2obobo$59bobobobo$56b
o2bobobob2o$56b4ob2o2bo$60bo4bo$56b2o2bob3o$56b2o3b2o!
Let's say that a circuit-editor GUI knows the basic hierarchy:

edge-shooter = [ [G-to-H + H-to-G#1] + Snark1 + Snark2 + Snark3 + [reflector-p8 + Snark4] ]

Maybe it would work to have a mechanism to "unlock" some sub-objects while leaving others locked. If you unlock just Snark3, it won't be movable -- but if you unlock Snark2 and Snark3 and turn off the period-160 constraint, you can move either Snark2 or Snark3 diagonally and the other Snark will come along automatically.

If you don't turn off the period-160 constraint, then ideally the two Snarks could still be moved, but they'd snap to just every 40th position on the diagonal. Or if you unlock Snark1, Snark2, and Snark3 but keep the period-160 constraint, then it ought to be possible to move Snark2 vertically, with the other two moving diagonally to compensate (!).

A complete gun is one or two steps up in the hierarchy. It's probably more interesting to think about representing it successfully with metadata, than to actually edit the full gun pattern and work down through that many levels:

dartgun = [shotgunNW + shotgunNE + shotgunSE + shotgunSW]
shotgunSW = [gun1 + gun2 + gun3 + gun4 + gun5 + gun6 + gun7 + gun8]

(plus orientation and X, Y, T offsets for each object...)

<wild weld tangent>I really love the idea of a library of known welds, where as you're dragging a Snark (let's say) closer to another Snark, an appropriate weld automatically appears, and disappears again when you drag it further away. If no workable weld is known, the object would presumably snap to the closest position that doesn't need a weld.

An automatic search for weld solutions would be impressive, but a terrible headache -- objects not only have to be stable in proximity to each other, but the original function of each must not be damaged... A more likely impressive feature would be a way to turn off the proximity alarm, drag the object into the right position, draw a weld in by hand, and have it automatically added to the database of known solutions.

-- Sorry, all of the weld speculations are pretty unlikely in the short term, I suppose. Might be something to think about once the basic circuit editor is working and the metadata format is worked out.</wild weld tangent>
simsim314 wrote:Anyway I definitely like the idea of switching rules, and representing data in special rule, although the metadata approach could make a lot of micromanagement itself as well, so you will not need anything special shown in golly except the basic pattern itself - unless you just want to colorize the logical entities for the data representation.
Colorization is the main thing, I think -- we could easily have a different color for each of dozens of separate components. Or there could be patches of background color showing where one component leaves off and another begins. Background colors could be altered to show that an item has been selected or changed status, while still leaving the select tool available to make a second selection. The rule table itself could be empty, so that nothing at all would happen if you ran the pattern.
simsim314 wrote:I was thinking about how a GUI for logical herschel conduit construction would look like - the problem that there is a lot of conduits, so just displaying not ordered list of conduits is a bad idea. So GUI is definitely an issue, and golly is not really helping out - we need to add side menu of our own, although golly has place for such things in pattern/script menu.

I was also considering to compile Golly myself, to tweak it a bit (for starters to add more events like shift up or mouse up) but I guess it's kinda dead end, asking people to download my version of golly, is a bad direction, and starting to tweak golly sound like story without ending.
I've been seriously considering putting some time into creating a simple programmable toolbar in Golly, where you can choose a bitmap and assign a script to any of an adjustable number of buttons -- maybe just in the blank part of the existing toolbar? I wouldn't say no to a floating toolbar, but wouldn't want it enough to deal with the code for docking and undocking it.

The really nice trick would be to allow programmable access to the toolbar buttons, so that some buttons would be visible only when a script is running. Seems as if that would make it a lot easier to write really good editing and search tools.

My experience with the Golly project has been that whenever I really wanted to contribute code for some minor new functionality, Andrew has been really nice about fixing any obvious silly mistakes I might have made, and rolling the changes into the next official release. Seems to me if there are obvious holes in Golly's abilities that you'd like to try patching, then that isn't necessarily a dead end at all.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 18th, 2014, 8:35 pm

I've created a script for "logical gun building". In particular using two recipes for p160 from gvrn:

Code: Select all

import golly as g 
import copy
import json 
import os 

def CellKeyFromXY(x, y):
	return str(x) + ":" + str(y)

def XYIterator():
	
	yield (0, 0)
	
	for i in xrange(-1, 2):
		for j in xrange(-1, 2):
			if i != 0 and j != 0:
				yield (i, j)

	
def GetDirection(t):
	dxx, dxy, dyx, dyy = t
	
	if dxy == 0:
		return dxx * dyy
	else:
		return dxy * dyx

def GetPositive(t):
	dxx, dxy, dyx, dyy = t
	
	return -(dxx + dxy)
	
def TrnasformDirection(direction, trans):

	dxx, dxy, dyx, dyy = trans 
	x, y = direction	
	
	return (dxx * x + dxy * y, dyx * x + dyy * y)
		
def TrnasformDirectionList(list, trans):
	return [TrnasformDirection(x, trans) for x in list]
	
def NewLogicalPatternRLE(rle, diff, inputs, outputs, period):
	result = LogicPattern()
	x, y = diff
	result.cells = g.parse(rle, x, y)
	result.inputs = inputs
	result.outputs = outputs
	result.period = period 
	
	return result
	
def NewLogicalPattern(cells, inputs, outputs, period, t):
	result = LogicPattern()
	result.cells = cells
	result.inputs = inputs
	result.outputs = outputs
	result.period = period 
	result.t = t 
	
	return result
	
class LogicPattern:
	
	def __init__(self):
		self.cells = []
		self.inputs = []
		self.outputs = []
		self.period = -1 
		self.t = ()

	def ToDict(self):
		return self.__dict__
		
	def FromDict(self, dict):
		for key in dict:
			self.__setattr__(key, dict[key])
		
		
	def GetListByOption(self, op):
		
		if op == "in":
			return self.inputs
		else:
			return self.outputs
	
	def Evolve(self, numIters):
		self.cells = g.evolve(self.cells, numIters)
			
class MovementData:
	def __init__(self, initX, initY, initPat):
		self.under = []
		self.curPat = []
		self.dx = -1
		self.dy = -1
		self.initX = initX 
		self.initY = initY
		self.initPat = initPat
		self.delta = 0 
		
	def RevertState(self):
		for i in xrange(0, len(self.curPat), 2):
			g.setcell(self.curPat[i] + self.dx, self.curPat[i + 1] + self.dy, 0)
		
		g.putcells(self.under)
		
	def UpdateState(self, newPat, dx, dy):
		self.under = []
		self.curPat = newPat
		self.dx = dx
		self.dy = dy
		
		for i in xrange(0, len(self.curPat), 2):
		
			if g.getcell(self.curPat[i] + self.dx, self.curPat[i + 1] + self.dy) == 1:
				self.under.append(self.curPat[i] + self.dx)
				self.under.append(self.curPat[i + 1] + self.dy)
				
			g.setcell(self.curPat[i] + self.dx, self.curPat[i + 1] + self.dy, 1)
		
		g.update()
	
	def UpdateCellDictionary(self, curdict, obejctIdx):
	
		for i in xrange(0, len(self.curPat), 2):
			x = self.curPat[i]
			y = self.curPat[i + 1]
			
			curdict[CellKeyFromXY(x + self.dx, y + self.dy)]  = obejctIdx

	def ClearCellDictionary(self, curdict, obejctIdx):
	
		before = len(curdict)
		removeList = [key for key in curdict if curdict[key] == obejctIdx]
		
		for key in removeList:
			x, y = key.split(":")
			g.setcell(int(x), int(y), 0)
			del curdict[key]
		
		after = len(curdict)
		g.show("size change: " + str(before)  + "," + str(after) + "," + str(obejctIdx))
		
class PlacementSnippet:
	id = 0 
	
	def __init__(self, attachedPatList, idx, moveData):
		self.moveData = moveData
		self.idx = idx 
		self.attachedPatList = attachedPatList
		self.id = PlacementSnippet.id 
		PlacementSnippet.id += 1
	
	def Update(self, attachedPatList, idx, moveData):
		self.moveData = moveData
		self.idx = idx 
		self.attachedPatList = attachedPatList

class LogicalDoc:
	def __init__(self, sigMan, recognizables):
		self.patterns = []
		self.snippets = [] 
		self.smarCells = {}
		self.sigMan = sigMan
		self.recognizables = recognizables

	def ToDict(self):
		dict = self.__dict__
		dict["sigMan"] = self.sigMan.ToDict()
		dict["recognizables"] = self.recognizables.ToDict()
		
		return str(dict)
	
	def FromDict(self):
		
		for key in dict:
			self.__setattr__(key, dict[key])
		
		self.sigMan = SignalManager()
		self.recognizables = LogicPatternCollection()
		
		self.sigMan.FromDict(dict["sigMan"])
		self.recognizables.FromDict(dict["recognizables"])
		
		return str(dict)
	
	def Save(self, file):

		with open(file, 'wb') as fp:
			json.dump(self.ToDict(), fp)
	
	
	def Load(self, file):

		with open(file, 'rb') as fp:
			data = json.load(fp)

		self.FromDict(data)
			
	def Main(self):
		
		g.show("left click on a pattern to change, 'h' for help")
		gollyMode = False
		
		while True:
		
			event = g.getevent()
			
			if ("key" in event and "return" in event) or (gollyMode and " a " in event):
				gollyMode = not gollyMode
				
				if gollyMode:
					g.show("In golly mode")
					g.update()

				else: 
					g.show("left click on a pattern, right click to finish")
					g.setrule("B3/S23")
					g.setalgo("HashLife")
					g.reset()
				
					g.update()
				
				continue 
				
			if gollyMode:
				
				if " delete " in event: 
					g.clear(0)
					
				if "click" in event and "ctrl" in event and g.getxy() != "":
					
					x, y = g.getxy().split()
					
					cell = g.getcell(int(x), int(y))
					
					if cell >= 0 and cell <= 1:
						g.setcell(int(x), int(y), 1 - cell)
					
					g.update()
				
				if " c " in event and "ctrl" in event and g.getselrect() != []:	
					g.copy()
				
				if " v " in event and "ctrl" in event and g.getxy() != "":
				
					x, y = g.getxy().split()
					
					g.paste(int(x), int(y), "or")
				
				if " space " in event:	
					if "ctrl" in event:
						g.run(10)
					else:
						g.run(1)
						
				g.doevent(event)
				continue 
				
			
			if "click" in event:
				
				if "left" in event:
					
					if self.ExistinCircuitHandler() == None:
						if self.SignalClickHandler(event) == None:
							g.show("left click on a pattern, h for help")
		
		
			elif "key" in event:
				if " space " in event:
					for i in xrange(0, 30):
						g.run(60)
						g.update()
						
					g.reset()
					g.update()		
					
				if " a " in event:
					
					if g.getrule() == "Perrier":
						g.setrule("B3/S23")
						g.setalgo("HashLife")
						g.update()
						
						
					else:
						g.setrule("Perrier")
						
						for key in self.smarCells:
							x, y = key.split(":")
							g.setcell(int(x), int(y),  self.smarCells[key] + 2)
						
						gollyMode = True
						g.show("In golly mode")
						g.update()
				
				if " s " in event:
					fname = os.path.join(g.getdir("data"), "MetadataManager.json")
					#self.Save(fname)
				
				if " h " in event:
					noteMessage = "Viewing and Selecting\n\n"
					noteMessage += "'left click' to chose gun or glider\n"
					noteMessage += "'a' to see in colors, a to go back \n"
					noteMessage += "'space' see ahead 1800 generations \n"
					noteMessage += "'enter' gollyMode, stays in the script \n"
					
					noteMessage += "\n Editing Gun \n\n"
					noteMessage += "'left click' to place\n"
					noteMessage += "'right click' to switch gun/orientation \n"
					noteMessage += "'delete' to delete the gun \n"
					noteMessage += "'left-right arrow' - one step adjustment\n"
					
					noteMessage += "\n In Golly Mode \n\n"
					noteMessage += "'delete' to clear selection\n"
					noteMessage += "'ctrl' + 'click' to draw \n"
					noteMessage += "'ctrl' + 'c' to copy selection \n"
					noteMessage += "'ctrl' + 'v' to paste in mouse location \n"
					noteMessage += "'space' + to run 1 generation \n"
					noteMessage += "'ctrl' +'space' to run 10 generations \n"
				
					g.note(noteMessage)
					
	def ExistinCircuitHandler(self):
		snip = self.ExitingSnippet()
		
		if snip == None:
			return None
		
		snip.moveData.ClearCellDictionary(self.smarCells, snip.id)
		self.ManageSnippet(snip)
		
	def ExitingSnippet(self):
	
		if g.getxy() == "":
			return None
			
		xs, ys = g.getxy().split()
		x = int(xs)
		y = int(ys)
					
		
		for i, j in XYIterator():
			key = CellKeyFromXY(x + i, y + j)
			if key in self.smarCells:
				return self.snippets[self.smarCells[key]]
	
		return None
		
	def SignalClickHandler(self, event):
		sigIn = sigMan.GetClickOnSignal(event)
		
		if sigIn != None:
			sig, op = sigIn
			pats = recognizables.GetPatternsBySignalClick((sig, op), sigMan)
			self.ManagePlacement(pats)
	
	def GetMovementData(self, attachedPatList, idx):
		
		return MovementData(attachedPatList[idx].x, attachedPatList[idx].y,	attachedPatList[idx].logicPat.cells)
			
	def ManagePlacement(self, attachedPatList):
		idx = 0
		movementData = self.GetMovementData(attachedPatList, idx)
		self.Placement(movementData, idx, attachedPatList, None)
		
	def ManageSnippet(self, snippet):

		self.Placement(snippet.moveData, snippet.idx, snippet.attachedPatList, snippet)
		
		
	def Placement(self, movementData, idx, attachedPatList, snip):
		
		while True:
		
			event = g.getevent()
			
			if event == "":
				self.ManageMove(attachedPatList[idx], movementData)
				
			elif "click" in event:
				
				if "right" in event: 
			
					movementData.RevertState()
					idx = (idx + 1) % len(attachedPatList)
					
					movementData = self.GetMovementData(attachedPatList, idx)
					self.ManageMove(attachedPatList[idx], movementData)
					
				elif "left" in event: 
					
					if snip == None:
						snip = PlacementSnippet(attachedPatList, idx, movementData)
						self.snippets.append(snip)
					else:
						snip.Update(attachedPatList, idx, movementData)
						
					movementData.UpdateCellDictionary(self.smarCells, snip.id)
					
					return 
				
			elif "key" in event:
				if "space" in event:
					for i in xrange(0, 30):
						g.run(60)
						g.update()
						
					g.reset()
					g.update()
				
				elif "right" in event:
					movementData.delta += 1
					
				elif "left" in event:
					movementData.delta -= 1
				
				elif "delete" in event: 
				
					movementData.RevertState()
					g.update()
					return 
			
				
	def ManageMove(self, attachedPat, movementData):
		
		val = g.getxy()
		
		if val == "":
			return 
		
		x1 = int(val.split()[0]) + movementData.delta
		self.MoveToX(attachedPat, x1, movementData)
		
		
	def MoveDelta(self, attachedPat, movementData, delta):
		movementData.RevertState()
		movementData.dx += delta * GetPositive(attachedPat.logicPat.t)
		self.MoveToX(attachedPat, movementData.dx, movementData)
		
	def MoveToX(self, attachedPat, x1, movementData):
		
		if  (x1 - movementData.initX) * GetPositive(attachedPat.logicPat.t)  < 0:
			x1 = movementData.initX
		
		y1 = movementData.initY + GetDirection(attachedPat.logicPat.t) * (x1 - movementData.initX)
		
		movementData.RevertState()
		movementData.UpdateState(g.evolve(movementData.initPat, 4 *  (x1 - movementData.initX) * GetPositive(attachedPat.logicPat.t)), x1, y1)
		
		
	def DrawAll(self):
		for pat in self.patterns:
			x, y = pat.location
			g.putcells(g.evolve(pat.attachedPat.logicPat.cells, pat.internal), x, y)

class AttachedLogicPat:
	def __init__(self, pat, i, option, x, y):
		self.logicPat = pat
		self.option = option 
		self.index = i
		self.x = x
		self.y = y 
	
	def ToDict(self):	
		dict = self.__dict__

		dict["logicPat"] = self.logicPat.ToDict()
		
	def FromDict(self, dict):	

		for key in dict:
			self.__setattr__(key, dict[key])
		
		self.logicPat = LogicPat()
		self.logicPat.FromDict(dict["logicPat"])
		 
	def Evolve(self, numIter):
		self.logicPat.Evolve(numIter)
		
	
class LogicPatternCollection:
	def __init__(self):
		self.patterns = []
		self.transList = []

		for i in xrange(-1, 2, 2):
			for j in xrange(-1, 2, 2):
				self.transList.append((i, 0, 0, j))
				self.transList.append((0, i, j, 0))

	
	def ToDict(self):
		dict = self.__dict__
		dict["patterns"] = [x.ToDict() for x in self.patterns]
		
		return dict 
		
	def FromDict(self, dict):
		for key in dict:
			self.__setattr__(key, dict[key])
		
		for i in xrange(0, len(self.patterns)):
			dict = self.patterns[i]
			self.patterns[i] = LogicPattern()
			self.patterns[i].FromDict(dict)
			
	def Add(self, logicPat):
		
		for t in self.transList:
			dxx, dxy, dyx, dyy = t 
			
			cells = g.transform(logicPat.cells,0, 0, dxx, dxy, dyx, dyy)
			
			if dxx == 0:
				cells = g.transform(g.evolve(cells, 2), -dxy, 0)
				
			inT = TrnasformDirectionList(logicPat.inputs, t)
			outT = TrnasformDirectionList(logicPat.outputs, t)
			p = logicPat.period
			pat = NewLogicalPattern(cells, inT, outT, p, t)
			
			self.patterns.append(pat)
	
	def FilterByDirection(self, dir, option):
		
		result = []
		
		for pat in self.patterns:

			filterList = pat.GetListByOption(option)
			
			for i in xrange(0, len(filterList)):
				if dir == filterList[i]:
					result.append(AttachedLogicPat(pat, i, option, 0, 0))
		
		return result 
				
	def  GetPatternsBySignalClick(self, sigClick, sigMan):
		physSig, option = sigClick
		cells, i, j, k, idx = sigMan.GetSignalFullData(physSig.signal)
		
		#bug fix not to evolve the setup data
		result = copy.deepcopy(self.FilterByDirection(TrnasformDirection((1, 1), (i, 0, 0, j)), option))

		for r in result:
			r.Evolve(k)
			r.x = physSig.x
			r.y = physSig.y
			
		return result
		
		
class PhysicalSignal:
	def __init__(self, sig, x, y):
		self.signal = sig
		self.x = x 
		self.y = y
		
	def Location(self):
		return (self.x, self.y)
		
class SignalManager:
	def __init__(self):
		self.signalsFullData = []
		self.signals = []
		
		self.components =  [g.parse("bo$2bo$3o!", -1, -1)]

		for idx in xrange(0, len(self.components)):
			comp = self.components[idx]
			
			for i in xrange(-1, 2, 2):
				for j in xrange(-1, 2, 2):
					for k in xrange(0, 4):
						self.signalsFullData.append((g.transform(g.evolve(comp, k), 0, 0, i, 0, 0, j), i, j, k, idx))
						self.signals.append(g.transform(g.evolve(comp, k), 0, 0, i, 0, 0, j))

						
	def ToDict(self):
		return self.__dict__
	
	def FromDict(self, dict):
		for key in dict:
			self.__setattr__(key, dict[key])
			
		
	def GetSignalFullData(self, sig):
		
		for i in xrange(0, len(self.signals)):
				if sig == self.signals[i]:
					return self.signalsFullData[i]
		
		return None
		
	def SignalAt(self, x, y):
		
		for s in self.signals:
			found = True
			
			for i in xrange(0, len(s), 2):
				xs = s[i]
				ys = s[i + 1]
				
				if g.getcell(x + xs, y + ys) == 0:
					found = False
					break
			
			
			if found:
				return s
				
		return None
		
	def SignalInArea(self, x, y):
	
		for i in xrange(x - 1, x + 2):
			for j in xrange(y - 1, y + 2):
				sig = self.SignalAt(i, j)
				
				if sig != None:
					return PhysicalSignal(sig, i, j)
					
		
		return None 
	
	def Remove(self, phisSig):
		
		for i in xrange(0, len(phisSig.signal), 2):
			xs = phisSig.signal[i]
			ys = phisSig.signal[i + 1] 
			
			g.setcell(phisSig.x + xs, phisSig.y + ys, 0)

	
	def GetClickOnSignal(self, event):
		
		xs, ys = g.getxy().split()
		x = int(xs)
		y = int(ys)
		
		sig = sigMan.SignalInArea(x, y)
		
		if sig != None:
			
			#sigMan.Remove(sig)
			
			if "left" in event:
				return (sig, "out")
			if "right" in event:
				return (sig, "out")

sigMan = SignalManager()
recognizables = LogicPatternCollection()

#rle_htog_1 = "31b2o$31b2obo$35bo8bo$32bo9b3o$33bob2o4bo$35b2o4b2o2$39bo13b2o$38bobo12b2o$39b2o2b2o$43b2o2$24bo$24b3o$27bo$26b2o3$15b2ob2o$15b2obo20b2o$18bo19bobo$18b3o4b2o11bo$16b2o3bo3b2o10b2o$15bo2b4o$15b2obo15b2o$16bo2b3o12bobo$16bo5bo13bo11b3o$17b5o14b2o10b3o$19bo28bo2bo6b2o$49b3o6bo$49b2o8b3o$32bobo26bo$33b2o$33bo4$91bo$92bo$48b2o40b3o$48b2o6$59b2o$38b2o19bo$39bo17bobo$39bobo15b2o$40b2o4bo6b2o$45bobo4bo2bo$45bobo5b2o$46bo10b2o$9bo47bobo$9b3o47bo$12bo46b2o5b2o$11b2o31b2o20bo$45bo22bo$42b3o3b2o14b5o$2ob2o37bo6bo13bo$2obo45bobo12b3o$3bo12bo33b2o15bo$3b3o4b2o2b2o48b4o$b2o3bo3b2o3b2o42b2o3bo3b2o$o2b4o52b2o4b3o2bo$2obo15b2o46bob2o$bo2b3o12bobo45bo$bo5bo13bo44b2o$2b5o14b2o$4bo$58b2o$58bo$45b2o12b3o$46b2o13bo$45bo2$34bo$32b3o$31bo$31b2o7$21b2o$20bobo5b2o$20bo7b2o$19b2o2$33bo$29b2obobo$28bobobobo$25bo2bobobob2o$25b4ob2o2bo$29bo4bo$25b2o2bob3o$25b2o3b2o!"
#rle_fx119 = "29$59b2o$60bo$60bobo$61b2o4$94bo$92b2o$60b2o$60b2o4b2o$66b2o4$65b2o$61b2o2b2o$60bobo16b3o$60bo12b2o4b3o$59b2o11bobo4bo2bo$72bo7b3o$71b2o7b2o7$122bo$123bo$121b3o6$81b2o$81b2o2$88bob2o$88b2obo3$70b2o$71bo$71bobo$72b2o2$38b2o5b2o$39bo5b2o39b2o$39bobo44bobo$40b2o46bo$44b2o42b2o$45bo4bo$43b2o3bobo$40bo8b2o$39b3o$38bob3o$37bo3bo$36bo3bo42b2o$35b3obo43bo$36b3o45b3o$37bo48bo8$73b2o$73b2o5$74bo$73b3o8b2o$63b2o7b2ob2o7bo$64bo6b2o2bo6bobo$64bobo4b2ob2o6b2o$65b2o5bo5bo$51bo23b2obo$50bo24b2o$50b3o22b2o5b2o$34bo47bobo$34b3o47bo$37bo46b2o$36b2o31b2o22b2o$70bo20bo2bo$67b3o3b2o14b5o$28b2o37bo6bo13bo$28bo45bobo12b3o$25b2obo46b2o15bo$25bo2b3o4b2o52b4o$26b2o3bo3b2o47b2o3bo3b2o$28b4o52b2o4b3o2bo$28bo15b2o46bob2o$29b3o12bobo45bo$32bo13bo44b2o$27b5o14b2o$26bo2bo$26b2o55b2o$83bo$84b3o$86bo3$59bo$57b3o$56bo$56b2o4$59b3o$61bo$60bo$46b2o$45bobo5b2o$45bo8bo$44b2o2$58bo$54b2obobo$53bobobobo$50bo2bo3bob2o$50b4ob2o2bo$54bo4bobo$52bobo5b2o$52b2o!"
#recognizables.Add(NewLogicalPatternRLE(rle_htog_1, (-91, -38), [], [(1, 1)], 160))
#recognizables.Add(NewLogicalPatternRLE(rle_fx119, (-122, -58), [], [(1, 1)], 160))

rle_htog_1 = "31b2o$31b2obo$35bo8bo$32bo9b3o$33bob2o4bo$35b2o4b2o2$39bo13b2o$38bobo12b2o$39b2o2b2o$43b2o$54b2o$24bo15b2o11bo4bo$24b3o13bobo9bo5bo4b2o$27bo12bo11b2ob2obo3bo2bo$26b2o33b2obo4bo$55bo6bobo5bo$55bo7b3o2b3o$15b2ob2o34bo10bo$15b2obo20b2o11b2o$18bo19bobo13bo$18b3o4b2o11bo13b2o$16b2o3bo3b2o10b2o$15bo2b4o$15b2obo15b2o$16bo2b3o12bobo$16bo5bo13bo$17b5o14b2o$19bo38b2o$58bo$59b3o$61bo8$48b2o$38bo9b2o$36b2o$37b2o4$59b2o$38b2o19bo$39bo17bobo$39bobo15b2o$40b2o4bo$45bobo$45bobo$46bo10b2o$9bo47bobo$9b3o47bo$12bo41b2o3b2o5b2o$11b2o31b2o7b2o11bo$45bo9bo12bo$42b3o3b2o14b5o$2ob2o37bo6bo13bo$2obo45bobo12b3o$3bo46b2o15bo$3b3o4b2o52b4o$b2o3bo3b2o47b2o3bo3b2o$o2b4o52b2o4b3o2bo$2obo15b2o46bob2o$bo2b3o12bobo45bo$bo5bo13bo44b2o$2b5o14b2o$4bo$58b2o$58bo$59b3o$61bo3$34bo$32b3o$24bo6bo$25b2o4b2o$24b2o6$21b2o$20bobo5b2o$20bo7b2o$19b2o2$33bo$29b2obobo$28bobobobo$25bo2bobobob2o$25b4ob2o2bo$29bo4bo$25b2o2bob3o$25b2o3b2o!"
rle_fx119 = "34b2o$35bo$35bobo22b2o$36b2o21bo4bo$58bo5bo4b2o$58b2ob2obo3bo2bo$48b4o15b2obo4bo$47b3ob2o8bo6bobo5bo$45bo3bo2b2o7bo7b3o2b3o$35b2o8bo2bo3bo7bo10bo$35b2o8bobo3bo6b2o$60bo$58b2o3$40b2o$36b2o2b2o$35bobo24b2o$35bo12b2o12b2o$34b2o11bobo$47bo$46b2o10$44bo$42b2o$43b2o3$56b2o$56b2o2$63bob2o$63b2obo3$45b2o$46bo$46bobo$47b2o2$13b2o5b2o31bo$14bo5b2o30b3o6b2o$14bobo34bo2bo6bobo$15b2o33b3o2b2o6bo$19b2o30bo2b3o6b2o$18bobo31b2o2b2o$19bo35b3o$15bo36b4obo$14b3o35b2o2b2o$13bob3o37b2o$12bo3bo$11bo3bo42b2o$10b3obo33bo9bo$11b3o33bo11b3o$12bo34b3o11bo8$48b2o$43bo4b2o$41bobo$42b2o4$59b2o$38b2o19bo$39bo17bobo$39bobo15b2o$40b2o4bo6b2o$45bobo4bo2bo$45bobo5b2o$46bo10b2o$9bo47bobo$9b3o47bo$12bo46b2o$11b2o31b2o22b2o$45bo20bo2bo$42b3o3b2o14b5o$3b2o37bo6bo13bo$3bo45bobo12b3o$2obo5b2o39b2o15bo$o2b2o6bo52b4o$b2o2bo2bob2o47b2o3bo3b2o$3bob2o52b2o4b3o2bo$3bobo13b2o31b3o12bob2o$4b3o12bobo32bo12bo$7bo6bo6bo31bo12b2o$2b5o8bo5b2o$bo2bo8b3o$b2o55b2o$58bo$59b3o$61bo3$34bo$32b3o$31bo$31b2o7$21b2o$20bobo5b2o$20bo7b2o$19b2o2$33bo$29b2obobo$28bobobobo$25bo2bobobob2o$25b4ob2o2bo$29bo4bobo$27bobo5b2o$27b2o!"
recognizables.Add(NewLogicalPatternRLE(rle_htog_1, (-69, -16), [], [(1, 1)], 160))
recognizables.Add(NewLogicalPatternRLE(rle_fx119, (-75, -7), [], [(1, 1)], 160))

doc = LogicalDoc(sigMan, recognizables)
#fname = os.path.join(g.getdir("data"), "MetadataManager.json")

#if os.path.exists(fname):
#	doc.Load(fname)

#doc.Save(fname)

doc.Main()




The code is divided nicely into classes. And made no assumption for the pattern library - so it can easily be adjusted to any gun building task. I took few "shortcuts" (obviously) - one of the is the assumption that the input patetrns ouput glider center, is at (0, 0). It's easy to adjust - just need to be known. Another shortcut is that for now I've no input, or two output option (although the data structure supports it)- the script was optimized for p160 gun building in few places. Obviously it's pretty easy to improve it, the code is maintainable, and very systematic.

To use:

Start from glider synth, click on gliders to get gun, move guns freely (they iterate internally automatically), hit space to see the near future, hit arrow keys to adjust guns with small step, hit c to look at each gun with separate color. Hit 'h' for help. Enjoy.
Last edited by simsim314 on December 19th, 2014, 8:14 pm, edited 3 times in total.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 18th, 2014, 9:03 pm

This is interesting point you're making. I was thinking about it as "logical builder" but actually, we have "hierarchical" builder. While the gun editing phase, is just one of many phases in the "same" hierarchy building process.

I understood the point of colorizing pretty quickly playing with my script . Used some rule with 69 states, and nice colors for the first states.

Python is surprisingly ill supported to all that concern a little bit more advanced serialization.

I'll see if there is something simple I can tweak in golly. Golly is huge projects anyway...I guess I much more prefer to invest my time in LifeAPI.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 27th, 2014, 6:43 pm

I was thinking a little bit about Logical Editors issue.

I'm coming to conclusion that we not only need a nice GUI for logical editors - but some sort of high programming language, or an API for designing large patterns.

Also in high level design, many times one wants to make simple searches - like what is the minimal distance from where the design will work, or what is the best SL reflector to place somewhere, or what is the optimal order of placement. Those things don't need to be done by hand, we need some set of tools (GUI/Programming), that will do the work in user friendly manner.

Say for the enginless caterpillar, I've *WSS edge shooters recipes, and *WSS recipes, and slow salvo recipes. But I still need to work really hard to combine them all together, into one coherent design.

And obviously some works is needed, but I think we need some sort of standard tool/library, that will do many of the things automatically, or even half automatically - we're doing too much things by hand.

HartmutHolzwart
Posts: 841
Joined: June 27th, 2009, 10:58 am
Location: Germany

Re: Circuit Editor in Golly

Post by HartmutHolzwart » December 27th, 2014, 7:44 pm

How about redesigning robocat for a start?

I.e. designing something that uses the basic design elements of robocat, but generalizes these appropriately?

robocat has it all" built in", but at least does the alignment of the parts and calculates the necessary adjustments.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 28th, 2014, 7:40 am

HartmutHolzwart wrote:How about redesigning robocat
I'm not familiar with robocat (and couldn't find anything that seems relevant on google). Do you have a link?

Anyway taking some parts and playing with them, the basic data structure design was already made in gun script. Basically the guns are adjusted according to the output glider.

But it seems to me it's not the only thing that we need. We need not only adjustment, and placement - but also small search utilities, and high level input-output language/data structure.

Think of universal constructor it has four stages:

1. List of SLs.
2. Recipes to construct each SL and order of construction. This should be done by some search utility.
3. Recipes for arm movements. The recipe list should be cost input for the search utility.
4. Recipes from glider stream to glider pairs. This should be done with some "auto translation" - output to X becomes input to Y. And you just concatenate inputs.

Now for the caterpillars is very similar:

1. List of *WSS recipes to produce.
2. Recipes to produce each *WSS with edge shooters.
3. Recipes to place the "basic interaction" stream, to generate edge shooters with slow salvo.
4. For each glider in slow salvo recipe - place SL, and concatenate the SLs.

- It seems to me we're solving a lot of similiar problem writing almost the same script over and over again.

HartmutHolzwart
Posts: 841
Joined: June 27th, 2009, 10:58 am
Location: Germany

Re: Circuit Editor in Golly

Post by HartmutHolzwart » December 28th, 2014, 8:27 am

http://www.gabrielnivasch.org/fun/life/caterpillar

at the end of Gabriel's explanation there is a link to the source code

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Circuit Editor in Golly

Post by simsim314 » December 28th, 2014, 9:05 am

@HartmutHolzwart - thx for the link. I saw the code a little bit, and it seems there are few general classes there, that can be put into some sort of library, but many of them are caterpillar oriented.

Anyway this is c++ implementation. I don't think that for high level designer we need c++, actually python+golly seems to be a better option for such things, and it also allows nicer user experience overall.

But you bring up an interesting question: maybe someone who designed high level complex designes (dvgrn, calcyman, chris_s, biggiemac, codeholic(?)), can post here their generation scripts, to analyze them.

I think even my Serizawa linear replicator generation script uses pretty nice classes, or the Geminoid Particles Geminoid.

Still it feels they're missing something. All of them are very implementation oriented, and it's hard to see how to make general usage function library for them. Especially many small searches that were done in preparation are omitted from the final scripts.

EDIT Maybe someone has an idea for data structure / library of functions / GUI design that are needed as "tool set" of logical editors. I've more or less the concept of single level data structure with auto-adjustable for timing input-output (you can see it in the glider gun script). But this is just a very small part of what is really needed for high level design. Except of the hierarchical concept of input-output devices built one on top of the other, maybe some people have more ideas.

EDIT2 I think to see what kind of tools are needed for high level enginless, and try to write the script as generic as possible, hopefully providing a general purpose tool set.

Post Reply