Glider Guns of large periods

For discussion of specific patterns or specific families of patterns, both newly-discovered and well-known.
User avatar
dvgrn
Moderator
Posts: 10687
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Glider Guns of large periods

Post by dvgrn » April 2nd, 2014, 2:35 pm

simsim314 wrote:I was also thinking returning to the previous stable technology using gliders, it's somehow feels more natural to me to bend patterns with those rather than with Herschels. But on the other hand I've a little experience with Herschels so it might be just that.
Those diagonal Herschel-track binary multipliers are really fairly easy to bend -- it would only take ten minutes or so to get Hersrch to put together a working sample 90-degree corner.

But I have to admit, I've been thinking the same thing about my suggested switch to Herschel-based binary multipliers. It would be much nicer to use semi-Snarks. That way, at each bit the signal would get converted to a Herschel (still have to do that or we don't have a convenient transparent reflector for the optional back-shooter gliders to fire through) -- but then it would get switched right back to a glider again, and we could bounce it around between Snarks as much as we needed to.

One big reason why I've been designing binary multipliers with Herschel-based period doublers is that there was no obvious replacement for a semi-Snark. Snarks are color-preserving reflectors where semi-Snarks are color-changing. So if we want a base loop that mimics the binary multiplier -- i.e., if we want to add the "same thing" to the binary multiplier and the base loop with every added bit -- then we have to replace semi-Snarks with Silver reflectors, and probably also chains of Snarks to get the timing adjustment exactly right to mimic a semi-Snark.

Silver reflectors are big and awkward, so that basically stopped me from putting together a really tight binary multiplier using semi-Snarks; all things considered, the diagonal Herschel track was the most efficient design I could come up with.

-- Actually I just thought of two possible ways of working around this problem. One is that there's a known small H-to-2G component, so quite possibly we could keep the semi-Snarks in place, but just send twice as many gliders to them on the back-shooting half of the binary multiplier.

The other is that the signal could be split at the top of the multiplier, to send two signals back down two back-shoot chains, again to double the inputs to the semi-Snarks on the second half of the circuit. I don't think that will be necessary, but it's another possible way to design a more compact binary-multiplier bit.

More later --

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

Re: Glider Guns of large periods

Post by simsim314 » April 2nd, 2014, 4:21 pm

OK finally I think this one is working perfectly:

Code: Select all

import golly as g
from glife import *
import random
from glife.text import *


class Glider:
	def __init__(self, x, y, dx, dy, gen, state):
		self.x = x
		self.y = y
		self.gen = gen
		self.state = state 
		self.dx = dx
		self.dy = dy
	def Place(self):
		gld = g.parse("3o$2bo$bo!", 0, 0, self.dx, 0, 0, self.dy)
		gld = g.evolve(gld, self.state)
		g.putcells(gld, self.x, self.y)
	def PlaceD(self, deltax, deltay):
		gld = g.parse("3o$2bo$bo!", 0, 0, self.dx, 0, 0, self.dy)
		gld = g.evolve(gld, self.state)
		g.putcells(gld, self.x + deltax, self.y + deltay)
		
	def Description(self):
		return " x {0} , y {1} , gen {2} , state {3}, dx {4}, dy {5} ".format(self.x, self.y, self.gen, self.state, self.dx, self.dy)
	
	def NextIter(self):
		if(self.state < 3):
			self.state += 1
		else:
			self.x += self.dx
			self.y -= self.dy
			self.state = 0
		self.gen += 1
		
	def PrevIter(self):
		if(self.state > 0):
			self.state -= 1
		else:
			self.x -= self.dx
			self.y += self.dy
			self.state = 3
		self.gen -= 1
		
	def NextIters(self, n):
		
		if n == 0: 
			return
		
		if n > 0: 
			for x in xrange(0, n):
				self.NextIter()
		
		if n < 0: 
			for x in xrange(0, -n):
				self.PrevIter()
				
	def BringToGeneration(self, n):
		self.NextIters(n - self.gen)
		
	def Copy(self):
		return Glider(self.x, self.y, self.dx, self.dy, self.gen, self.state)
		
class Snark:
	def __init__(self, glider, dist, isRight):
		self.glider = glider
		self.dist = dist
		self.isRight = isRight ^ (glider.dx == 1) ^ (glider.dy == 1)
		
		self.x = glider.x + dist * glider.dx 
		self.y = glider.y - dist * glider.dy 
		
		if self.isRight:
			self.outputGlider = Glider(self.x + 7 * self.glider.dx, self.y, self.glider.dx, -self.glider.dy, 32 + self.glider.gen + 4 * (dist - 1) + (4 - self.glider.state), 0)
		else: 
			self.outputGlider = Glider(self.x, self.y - 9 * self.glider.dy, -self.glider.dx, self.glider.dy, 40 + self.glider.gen + 4 * (dist - 1) + (4 - self.glider.state), 0)
			
	def Place(self):
		if self.isRight:
			mir = g.parse("5$8b2o3b2o$8b2o2bob3o$12bo4bo$8b4ob2o2bo$8bo2bobobob2o$11bobobobo$12b2obobo$16bo2$2b2o$3bo7b2o$3bobo5b2o$4b2o7$14b2o$14bo$15b3o$17bo!", -10, -20, 1, 0, 0, 1)
		else:
			mir = g.parse("14$22bo$4b2o14b5o$5bo13bo5bo$5bobo12b3o2bo$6b2o15bob2o$20b4o2bo$15b2o3bo3b2o$15b2o4b3o$23bo$23bob2o$22b2ob2o3$14b2o$14bo$15b3o$17bo!", -10, -20, 1, 0, 0, 1)
			
		mir = g.transform(mir, 0, 0, self.glider.dx, 0, 0, self.glider.dy)
		g.putcells(mir, self.x, self.y) 

class StaticMirror:
	def __init__(self, glider, dist, isRight):
		self.glider = glider
		self.dist = dist
		self.isRight = isRight ^ (glider.dx == 1) ^ (glider.dy == 1)
		
		self.x = glider.x + dist * glider.dx 
		self.y = glider.y - dist * glider.dy 
		
		if self.isRight:
			self.outputGlider = Glider(self.x + 78 * self.glider.dx, self.y - 10 * self.glider.dy, self.glider.dx, -self.glider.dy, 359 + self.glider.gen + 4 * (dist - 1) + (4 - self.glider.state), 0)
		else: 
			self.outputGlider = Glider(self.x + 10 * self.glider.dx, self.y - 80 * self.glider.dy, -self.glider.dx, self.glider.dy, 351 + self.glider.gen + 4 * (dist - 1) + (4 - self.glider.state), 0)
			
	def Place(self):
		if self.isRight:
			mir = g.parse("12$69b2o$69b2o9$84b2o$84b2o10$64b2o$65bo$62b3o$13b2o47bo$14bo$14bobo$15b2o8$18bo34bo$16b3o32b3o$15bo34bo$15b2o33b2o20b2o$5b2o56b2o7b2o$6bo57bo$6bobo55bobo$7b2o4b2o44b2o4b2o$12bo2bo44bo20b2o$13b2o45bobo18bo$25b2o34b2o16bobo$25b2o52b2o8$11b2o3b2o32b2o$12bo3bo20b2o11b2o$9b3o5b3o18bo$9bo9bo15b3o35b2o$35bo37b2o2b2o$77bobo$79bo$79b2o5$48b2o$49bo$46b3o$46bo!", -10, -60, 1, 0, 0, 1)
		else:
			mir = g.parse("7$58b2o$58b2o2$26bo$24b3o$8bo14bo$8b3o12b2o$11bo$10b2o3$11b2o$11b2o17b2o$30b2o2$68b2o$68b2o3$27b2o$27bo19b2o$28b3o15bobo$30bo15bo$24b2o19b2o$24bo$25b3o$27bo6$33b2o$33bo$14b2o15bobo$14b2o15b2o$2b2o$bobo$bo$2o8$13b2o$12bobo$12bo$11b2o9$23b2o$23b2o6$12b2o$13bo19b2o$13bobo17bo$14b2o15bobo8b2o$26bo4b2o9bo$25bobo15b3o$25bobo17bo$14b2o10bo$13bobo$13bo$12b2o$27b2o$27bo$28b3o$30bo!", -20, -80, 1, 0, 0, 1)
			
		mir = g.transform(mir, 0, 0, self.glider.dx, 0, 0, self.glider.dy)
		g.putcells(mir, self.x, self.y) 

class ColorSwitch:
	def __init__(self, glider, dist):
		self.glider = glider
		self.dist = dist
		
		self.x = glider.x + dist * glider.dx 
		self.y = glider.y - dist * glider.dy 
		
		self.outputGlider = Glider(self.x + 79 * self.glider.dx, self.y - 50 * self.glider.dy, self.glider.dx, self.glider.dy, 368 + self.glider.gen + 4 * (dist - 1) + (4 - self.glider.state), 0)
			
	def Place(self):
		mir = g.parse("5$66b2o$66b2o11$80b2o$80bobo$82bo$82b2o6$61b2o$62bo$59b3o$59bo3$13b2o$14bo$14bobo$15b2o61b2o$78bo$79b3o$81bo2$15bo34bo$13b3o32b3o$12bo34bo$12b2o33b2o20b2o$2b2o56b2o7b2o$3bo57bo$3bobo55bobo$4b2o4b2o44b2o4b2o$9bo2bo44bo20b2o$10b2o45bobo18bo$22b2o34b2o16bobo$22b2o52b2o8$8b2o3b2o32b2o$9bo3bo20b2o11b2o$6b3o5b3o18bo$6bo9bo15b3o35b2o$32bo37b2o2b2o$74bobo$76bo$2b2o72b2o$2bobo$4bo$4b2o2$45b2o$46bo$43b3o$43bo!", 0, -60, 1, 0, 0, 1)
		mir = g.transform(mir, 0, 0, self.glider.dx, 0, 0, self.glider.dy)
		g.putcells(mir, self.x, self.y) 
		
class UniversalGliderGun():
	def __init__(self, x, y, period):
		self.x = x
		self.y = y
		self.period = period
		self.numBits = 3
	
	def PlaceStart(self, turnOnBit): 
		startPart = g.parse("6$44bo$43bobo$43bobo$44bo18$64b2o$65bo$65bobo$66b2o5$63b2o$64bo$64bobo$65b2o18$104b2o3b2o$102b3obo2b2o$60b2o39bo4bo$59bobo39bo2b2ob4o$59bo25b2o13b2obobobo2bo$58b2o25bo15bobobobo$66b2o15bobo15bobob2o$66b2o15b2o17bo2$115b2o$106b2o7bo$106b2o5bobo$113b2o7$65b2o36b2o$64bobo37bo$64bo36b3o$63b2o36bo2$103b2o3b2o$103b2o2bob3o$107bo4bo$103b4ob2o2bo$103bo2bobobob2o$106bobobobo$107b2obobo$75b2o34bo$75b2o$87b2o8b2o$87bobo8bo7b2o$89bo8bobo5b2o$89b2o8b2o2$64b2o$65bo19b2o$65bobo17bo56bo$66b2o15bobo38b2o14b5o$70b2o6bo4b2o40bo13bo5bo$69bo2bo4bobo29b2o14bobo12b3o2bo$70b2o5bobo29bo16b2o15bob2o$66b2o10bo31b3o27b4o2bo$65bobo44bo22b2o3bo3b2o$65bo69b2o4b3o$64b2o77bo$79b2o62bob2o$79bo62b2ob2o$80b3o$82bo$98b2o34b2o$99bo34bo$99bobo33b3o$100b2o2b2o31bo5bo$104b2o35b3o15bo9bo$140bo18b3o5b3o$127b2o11b2o20bo3bo$127b2o32b2o3b2o8$40bo57b2o52b2o$38b5o14b2o38bobo16b2o34b2o$37bo5bo13bo39bo18bobo45b2o$37bo2b3o12bobo38b2o20bo44bo2bo$36b2obo15b2o55b2o4b2o44b2o4b2o$36bo2b4o69bobo55bobo$37b2o3bo3b2o66bo57bo$39b3o4b2o57b2o7b2o56b2o$39bo65b2o20b2o33b2o$36b2obo88bo34bo$36b2ob2o84b3o32b3o$125bo34bo2$47b2o$48bo$45b3o47b2o$45bo50bo$96bobo$97b2o2$49bo$47b3o$46bo69bo$46b2o66b3o$113bo$113b2o5$36b2o$35bobo5b2o47b2o$35bo7b2o48bo$34b2o57bobo$94b2o$48bo39bo$44b2obobo38b3o$43bobobobo41bo$40bo2bobobob2o39b2o$40b4ob2o2bo$44bo4bo$40b2o2bob3o$40b2o3b2o3$100b2o6b2o$93b2o5bobo5b2o$93b2o7bo$102b2o2$89bo$88bobob2o$88bobobobo$87b2obobobo2bo$88bo2b2ob4o$88bo4bo$89b3obo2b2o$91b2o3b2o26$238bo$236b3o$235bo$235b2o7$225b2o$224bobo5b2o$224bo7b2o$223b2o2$237bo$233b2obobo$232bobobobo$229bo2bobobob2o$229b4ob2o2bo$233bo4bo$229b2o2bob3o$229b2o3b2o!", 0, -60, 1, 0, 0, 1)		
		g.putcells(startPart, self.x, self.y) 
		
		if turnOnBit:
			blocker = g.parse("$b2o$bo$2b3o$4bo!", 60,-43, 1, 0, 0, 1)
			g.putcells(blocker, self.x, self.y) 
	
	def PlaceEnd(self, turnOnBit, numBits): 
		startPart = g.parse("121bo$81b2o38b3o$82bo41bo14bo$82bobo38b2o12b3o$83b2o2b2o47bo$87b2o47b2o3$135b2o$116b2o17b2o$116b2o6$81b2o36b2o$80bobo16b2o19bo$80bo18bobo15b3o$79b2o20bo15bo$95b2o4b2o19b2o$95bobo25bo$97bo22b3o$88b2o7b2o21bo$88b2o7$78b2o$79bo$79bobo$80b2o$96bo$94b3o$93bo$93b2o28b2o$122bobo$122bo29b2o$121b2o29bobo$61b2o91bo$38bo23bo64b2o25b2o$36b3o23bobo61bobo4b2o$35bo27b2o61bo7bo$35b2o88b2o4b3o$131bo$12bo42bo83b2o$12b3o38b3o44b2o36bobo$5bo9bo36bo47b2o36bo$5b3o6b2o23b2o11b2o83b2o$8bo30b2o$7b2o$95b2o$95b2o$99b2o54b2o$99b2o54bobo$157bo$157b2o$64b2o27b2o$3bo23b2o35b2o11b2o14b2o$2bobo22bo49bo$3bo14b2o8b3o47b3o$18bo11bo49bo$19b3o$21bo125b2o$138b2o7b2o$5b2o32b2o98bo$4bobo33bo98bobo$4bo32b3o100b2o$3b2o32bo85bo32b2o$19b2o100b3o32bo$19bobo52b2o21bo22bo33bobo$21bo52b2o21b3o20b2o32b2o$12b2o7b2o40b2o35bo$12b2o50bo34b2o38bo$64bobo72b3o$65b2o63bo11bo$130b3o8b2o14bo$133bo22bobo$132b2o23bo2$2b2o58b2o25b2o$3bo59bo25b2o$3bobo57bobo$4b2o58b2o3$77b2o$77bobo6b2o32b2o$22b2o55bo6bo20b2o11b2o23b2o23bo$22bo56b2o6b3o18bo36bo22b3o$20bobo66bo15b3o38b3o18bo$20b2o83bo42bo18b2o2$124b2o$125bo49b2ob2o$75b2o45b3o51bob2o$75bobo44bo53bo$77bo90b2o4b3o$77b2o89b2o3bo3b2o$173b4o2bo$159b2o15bob2o$158bobo12b3o2bo$158bo13bo5bo$2b2o15b2o38b2o96b2o14b5o$bobo15b2o37bobo114bo$bo25b2o29bo25b2o129b2o$2o25bo29b2o25bo131bo$25bobo37b2o15bobo131bobo$25b2o38b2o15b2o133b2o$242b2o$242b2o2$210bo$208b3o$192bo14bo$192b3o12b2o$195bo$194b2o3$64b2o129b2o$63bobo129b2o17b2o$63bo150b2o$62b2o$252b2o$252b2o3$20b2o58b2o129b2o$20bobo57bobo128bo19b2o$22bo59bo40bo88b3o15bobo$22b2o58b2o39b3o88bo15bo$126bo81b2o19b2o$125b2o81bo$209b3o$18b2o191bo$18bobo93b2ob2o$20bo93b2obo$20b2o50b2o43bo$63b2o7b2o43b3o4b2o$64bo50b2o3bo3b2o$64bobo47bo2b4o96b2o$65b2o47b2obo15b2o82bo$48bo32b2o32bo2b3o12bobo62b2o15bobo$46b3o32bo33bo5bo13bo62b2o15b2o$22bo22bo33bobo34b5o14b2o$22b3o20b2o32b2o37bo$25bo$24b2o38bo$64b3o$55bo11bo$55b3o8b2o14bo$58bo22bobo$57b2o23bo3$197b2o$196bobo$196bo$195b2o2$77b2o$45b2o30bo$32b2o11b2o23b2o6b3o$33bo36bo9bo$30b3o38b3o82b2o$30bo42bo82b2o2$49b2o156b2o$50bo156b2o$47b3o93b2o$47bo96bo$144bobo$145b2o2$196b2o$197bo19b2o5b2o$163b2o32bobo17bo6bo$163b2o15bo17b2o15bobo7b3o$178b3o29bo4b2o10bo$145b2o30bo31bobo$144bobo30b2o30bobo$144bo53b2o10bo$143b2o52bobo$197bo$196b2o$211b2o$154b2o55bo$153bobo56b3o$153bo60bo$152b2o5$174b2o$174bobo$176bo$176b2o17$215b2o$216bo$216bobo$217b2o$242b2o$242b2o2$210bo$208b3o$192bo14bo$192b3o12b2o$195bo$194b2o3$195b2o$195b2o17b2o$214b2o2$252b2o$252b2o3$211b2o$211bo19b2o$212b3o15bobo$214bo15bo$208b2o19b2o$208bo$209b3o$211bo6$217b2o$217bo$198b2o15bobo$198b2o15b2o12$197b2o$196bobo$196bo$195b2o9$207b2o$207b2o6$196b2o$197bo19b2o5b2o$197bobo17bo6bo$198b2o15bobo7b3o$210bo4b2o10bo$209bobo$209bobo$198b2o10bo$197bobo$197bo$196b2o$211b2o$211bo$212b3o$214bo!", 1, -108, 1, 0, 0, 1)		
		g.putcells(startPart, self.x + 75 * numBits, self.y - numBits * 75) 
		
		if turnOnBit:
			blocker = g.parse("$b2o$bo$2b3o$4bo!", 60,-43, 1, 0, 0, 1)
			g.putcells(blocker, self.x + 75 * numBits, self.y - numBits * 75) 
	
	def PlaceBitStream(self, blocks): 
		d = 0
		
		for toBlock in blocks:
			bit = g.parse("87b2o$88bo$43bo44bobo$41b3o45b2o$40bo$40b2o2$17bo42bo$17b3o38b3o15bo$10bo9bo36bo18b3o6b2o$10b3o6b2o23b2o11b2o20bo6bo$13bo30b2o32b2o6bobo$12b2o73b2o5$75b2o$75b2o2$8bo23b2o$7bobo22bo$8bo14b2o8b3o$23bo11bo$24b3o55b2o$26bo56bo$80b3o6bo$10b2o32b2o34bo7bobo$9bobo33bo43bo$9bo32b3o$8b2o32bo$24b2o$24bobo52b2o$26bo52b2o$17b2o7b2o40b2o$17b2o50bo$69bobo$70b2o5$7b2o58b2o25b2o$8bo59bo25b2o$8bobo57bobo$9b2o58b2o3$82b2o$82bobo6b2o$27b2o55bo6bo$27bo56b2o6b3o$25bobo66bo$25b2o4$80b2o$80bobo$82bo$82b2o5$7b2o15b2o38b2o$6bobo15b2o37bobo$6bo25b2o29bo25b2o$5b2o25bo29b2o25bo$30bobo37b2o15bobo$30b2o38b2o15b2o5$12b2o$13bo$13bobo$14b2o4$69b2o$bo66bobo$b3o6b2o56bo$4bo6bo55b2o$3b2o6bobo$12b2o3$25b2o58b2o$25bobo57bobo$2o25bo59bo$2o25b2o58b2o4$23b2o$23bobo$7b2o16bo$8bo16b2o50b2o$5b3o6bo53b2o7b2o$5bo7bobo53bo$14bo54bobo$70b2o$53bo32b2o$51b3o32bo$4b2o21bo22bo33bobo$4b2o21b3o20b2o32b2o$30bo$29b2o38bo$69b3o$60bo11bo$60b3o8b2o14bo$63bo22bobo$62b2o23bo2$19b2o$19b2o5$7b2o73b2o$7bobo6b2o32b2o30bo$9bo6bo20b2o11b2o23b2o6b3o$9b2o6b3o18bo36bo9bo$19bo15b3o38b3o$35bo42bo2$54b2o$55bo$5b2o45b3o$5bobo44bo$7bo$7b2o!", 71, -142, 1, 0, 0, 1)		
			g.putcells(bit, self.x + d, self.y - d) 
			
			if toBlock: 
				blocker = g.parse("$b2o$bo$2b3o$4bo!", 60,-43, 1, 0, 0, 1)
				g.putcells(blocker,self.x + 75 + d, self.y - 75 - d) 
				
			d += 75
	def PlaceReflector(self): 
		blocker = g.parse("9b2o$10bo$10bobo$11b2o2b2o37bo$15b2o35b3o15bo9bo$51bo18b3o5b3o$38b2o11b2o20bo3bo$38b2o32b2o3b2o8$9b2o52b2o$8bobo16b2o34b2o$8bo18bobo45b2o$7b2o20bo44bo2bo$23b2o4b2o44b2o4b2o$23bobo55bobo$25bo57bo$16b2o7b2o56b2o$o15b2o20b2o33b2o$3o36bo34bo$3bo32b3o32b3o$2b2o32bo34bo6$71b2o$71bobo$73bo$73b2o2$27bo$25b3o$24bo$24b2o10$4b2o$4b2o9$19b2o$19b2o!", 263,-15, 1, 0, 0, 1)
		g.putcells(blocker, self.x - 112, self.y + 112) 
	
	def ZeroPeriodMod8(self, mod8Value): 
		if mod8Value == 0: 
			return 8248
		
		if mod8Value == 1:
			return 8281
		
		if mod8Value == 2:
			return 8642

		if mod8Value == 3:
			return 8115
		
		if mod8Value == 4:
			return 8212
		
		if mod8Value == 5:
			return 8045
		
		if mod8Value == 6:
			return 8414
		
		if mod8Value == 7:
			return 8559
	
	def HoldMechanismGliderPrepare(self, mod8Value):
		
		if mod8Value == 0:
		
			golly.select( [self.x +111 + 75,self.y-140 - 75,4,4] )
			golly.clear(0)
			gld = Glider(self.x +113 + 75,self.y -140 - 75, 1,1,0,0)
			snk = Snark(gld, 15, False)
			snk.Place()
			return snk.outputGlider
			
		if mod8Value == 1:
		
			golly.select( [self.x +111,self.y -140,4,4] )
			golly.clear(0)
			gld = Glider(self.x +113, self.y -140, 1,1,0,0)
			snk = Snark(gld, 15, False)
			snk.Place()
			return snk.outputGlider
			
		if mod8Value == 2:
			
			golly.select( [self.x +111 +  75,self.y-140 - 75,4,4] )
			golly.clear(0)
			gld = Glider(self.x +113 +  75, self.y-140 -  75, 1,1,0,0)
			snk = Snark(gld, 15, False)
			snk.Place()
			return snk.outputGlider
			
		if mod8Value == 3:

			golly.select( [self.x +111 + 75,self.y-140 - 75,4,4] )
			golly.clear(0)
			gld = Glider(self.x +113 + 75, self.y-140 - 75, 1,1,0,0)
			snk = Snark(gld, 15, False)
			snk.Place()
			return snk.outputGlider
			
		if mod8Value == 4:

			golly.select( [self.x +78,self.y-100,4,4] )
			golly.clear(0)
			gld = Glider(self.x +80, self.y-100, -1,1,0,0)
			return gld
			
			
		if mod8Value == 5:

			golly.select( [self.x +81,self.y-133,4,4] )
			golly.clear(0)
			gld = Glider(self.x +82,self.y -133, -1,1,0,0)
			return gld 
			
		if mod8Value == 6:
		
			golly.select( [self.x +111,self.y-140,4,4] )
			golly.clear(0)
			gld = Glider(self.x +113, self.y-140, 1,1,0,0)
			snk = Snark(gld, 15, False)
			snk.Place()
			return snk.outputGlider
		
		if mod8Value == 7:
		
			golly.select( [self.x +81,self.y-133,4,4] )
			golly.clear(0)
			gld = Glider(self.x +82, self.y-133, -1,1,0,0)
			return gld
	
	def SnarkSnake(self, Mod8Multiplier, gld):
	
		a = [0,-1, -1, -1, -1, -1, -1]
		
		if self.SnarkSnakeCalculationsNew(Mod8Multiplier, gld, [0], False) <= 0:
			return Mod8Multiplier
		
		i = 0 
		idx = 0 
		while  self.SnarkSnakeCalculationsNew(Mod8Multiplier, gld, a , False) > 0:
			i+= 1
			
			if i > 75 * (self.numBits - 1) - 40:
				idx += 1
				i = 0 
				
			a[idx] = i
			
		
		a[idx] -= 1
		
		return self.SnarkSnakeCalculationsNew(Mod8Multiplier, gld, a, True)

		'''
		bestDist = -1
		bestD = -1 
		
		if not self.SnarkSnakeCalculations(Mod8Multiplier, gld, 0, False):
			return Mod8Multiplier
		
		for d in xrange(0, 75 * (self.numBits - 1) - 40):
			val = self.SnarkSnakeCalculations(Mod8Multiplier, gld, d, False)
			if  val > bestDist:
				val = bestDist
				bestD = d
			
		return self.SnarkSnakeCalculations(Mod8Multiplier, gld, bestD, True)
		'''		
		
	def SnarkSnakeCalculations(self, Mod8Multiplier, gldIn, delta, toPlace):
		
		curDist = Mod8Multiplier
		
		gld = gldIn.Copy()
		
		i = 0 
		x = gld.x
		
		while True: 
			if curDist < 55 + (x - gld.x) + delta: 
				if toPlace: 
					return curDist	
				break
			
			if i == 0: 
				degrees = [(True, 22), (False, 15 + delta), (False, 15), (True, 17 + delta)]
			else: 
				degrees = [(True, 15), (False, 15 + delta), (False, 15), (True, 17 + delta)]
			for deg in degrees: 
				sn = Snark(gld, deg[1], deg[0])
				if toPlace:
					sn.Place()
				gld = sn.outputGlider
		
			curDist -= (26 + delta)
			i += 1
		
		return curDist
	
	def SnarkSnakeCalculationsNew(self, Mod8Multiplier, gldIn, delta, toPlace):
		
		curDist = Mod8Multiplier
		
		gld = gldIn.Copy()
		
		i = 0 
		x = gld.x
		
		for i in xrange(0, len(delta)):
			if delta[i] >= 0:
				if curDist < 75 + (x - gld.x) + delta[i]: 
					return -1
				
				if i == 0: 
					degrees = [(True, 25), (False, 15 + delta[i]), (False, 15), (True, 17 + delta[i])]
				else: 
					degrees = [(True, 15), (False, 15 + delta[i]), (False, 15), (True, 17 + delta[i])]
					
				for deg in degrees: 
					sn = Snark(gld, deg[1], deg[0])
					if toPlace:
						sn.Place()
					gld = sn.outputGlider
			
				curDist -= (26 + delta[i])
				
		return curDist
		
	def PlaceHoldMechanism(self, period0):
		
		mod8Value = period0 % 8 
		Mod8Multiplier = (period0 - self.CalculateZeroPeriod(self.numBits, mod8Value)) / 8
		gld = self.HoldMechanismGliderPrepare(mod8Value)
		Mod8Multiplier = self.SnarkSnake(Mod8Multiplier, gld)
		
		if mod8Value == 0: 
		
			snk = Snark(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			sw = ColorSwitch(snk.outputGlider, 10)
			sw.Place()
			snk = Snark(sw.outputGlider, 88 + 75, False)
			snk.Place()
			return 8248 + 8 * Mod8Multiplier
		
		if mod8Value == 1:
		
			snk = Snark(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			snk = StaticMirror(snk.outputGlider, 122, False)
			snk.Place()
			return 8281 + 8 * Mod8Multiplier
		
		if mod8Value == 2:
			
			snk = StaticMirror(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			sw = ColorSwitch(snk.outputGlider, 10)
			sw.Place()
			snk = StaticMirror(sw.outputGlider, 17 +75, False)
			snk.Place()
			return 8642 + 8 * Mod8Multiplier

		if mod8Value == 3:

			snk = Snark(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			snk = StaticMirror(snk.outputGlider, 122 + 75, False)
			snk.Place()
			return 8115 + 8 * Mod8Multiplier
		
		if mod8Value == 4:

			snk = Snark(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			sw = ColorSwitch(snk.outputGlider, 10)
			sw.Place()
			snk = Snark(sw.outputGlider, 32, False)
			snk.Place()
			return 8212 + 8 * Mod8Multiplier
		
		if mod8Value == 5:
		
			snk = Snark(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			snk = Snark(snk.outputGlider, 124, False)
			snk.Place()
			return 8045 + 8 * Mod8Multiplier
		
		if mod8Value == 6:
		
			snk = Snark(gld, 15 + Mod8Multiplier, False)
			snk.Place()
			sw = ColorSwitch(snk.outputGlider, 10)
			sw.Place()
			snk = Snark(sw.outputGlider, 88, False)
			snk.Place()
			return 8414 + 8 * Mod8Multiplier
		
		if mod8Value == 7:
		
			snk = StaticMirror(gld, 30 + Mod8Multiplier, False)
			snk.Place()
			snk = StaticMirror(snk.outputGlider, 53, False)
			snk.Place()
			return 8559 + 8 * Mod8Multiplier
	
	
	def RotationPeriod(self, numBits):
		return 3415 + 1200 * (numBits - 3)
	
	def RotationPeriodHoldBack(self, numBits):
		return 1200 * (numBits - 3)
	
	def BitHoldBack(self, numBits): 
		return 932 * (numBits - 3)
	
	def CalculateZeroPeriod(self, numBits, periodMod8):
		return self.BitHoldBack(numBits) + self.ZeroPeriodMod8(periodMod8) + self.RotationPeriodHoldBack(numBits)
	
	def CalculateMaxPeriod(self, numBits, periodMod8):
		return self.CalculateZeroPeriod(numBits, periodMod8) + (2**numBits - 1) * self.RotationPeriod(numBits)
	
	def CalculateNumBits(self, period):
		
		while self.CalculateMaxPeriod(self.numBits, period%8) < period:
			self.numBits += 2
		
		return self.numBits
	
	def DoAllCalculations(self):
		period = self.period
		
		if period < self.ZeroPeriodMod8(period % 8):
			golly.exit("The period is too low")
		
		numBits = self.CalculateNumBits(period)
      
		rot = self.RotationPeriod(numBits)
		zero = self.CalculateZeroPeriod(numBits, (period - self.RotationPeriod(numBits)) % 8)

		zeroMultiplier = (zero - zero % rot) / rot
		periodMultipler = (period - period % rot) / rot
		multiplier = periodMultipler - zeroMultiplier - 10
		period -= multiplier * rot 
      
		while period >= self.CalculateZeroPeriod(numBits, period % 8):
			multiplier += 1
			period -= rot     
         
		bits = 2**numBits - multiplier
		
		endBit = bits < 2**(numBits - 1)
		
		if not endBit: 
			bits -= 2**(numBits - 1)
			
		startBit = bits % 2 == 0
		bits = (bits - bits%2) / 2
		
		middlebits = []
		
		for i in xrange(0, self.numBits - 2):
			middlebits.extend([bits % 2 == 0])
			bits = (bits - bits%2) / 2
		
		period0 = period  + rot
		
		#golly.show('{0}, {1}, {2}'.format(startBit, middlebits[0], endBit))
		return [startBit, middlebits, endBit, period0]
		
	def Place(self): 
		values = self.DoAllCalculations();
		self.PlaceStart(values[0])
		self.PlaceBitStream(values[1])
		self.PlaceEnd(values[2],self.numBits - 1)
		self.PlaceReflector()
		gld = Glider(self.x + 167, self.y + 63, -1,-1,0,0)
		gld.Place()
		self.PlaceHoldMechanism(values[3])
		
		periodText = make_text (str(self.period))
		g.putcells(periodText,self.x - 50, self.y + 200) 
	  

gen = g.getstring("Enter Gun Period: ")

g.select([0,0,1,1])
g.clear(1)
g.clear(0)



gun = UniversalGliderGun(0,0,int(gen))
gun.Place()

'''
for x in xrange(0, 100):
	gun = UniversalGliderGun(0,2000 * x,17985 + 12289 *  x)
	gun.Place()
'''

g.fit() 
	
A small detail that messed up some of my checks: I used the goto.py script, which goes from generation 0. My script works from current generation. So trying to use goto.py before setting golly to generation 0 for my script, might be annoyingly frustrating, and yielding false negatives.

User avatar
Extrementhusiast
Posts: 1966
Joined: June 16th, 2009, 11:24 pm
Location: USA

Re: Glider Guns of large periods

Post by Extrementhusiast » April 7th, 2014, 2:00 pm

simsim314 wrote:A small detail that messed up some of my checks: I used the goto.py script, which goes from generation 0. My script works from current generation. So trying to use goto.py before setting golly to generation 0 for my script, might be annoyingly frustrating, and yielding false negatives.
Putting a plus (or minus) sign in front of the number steps the layer forward (backward) that many steps.
I Like My Heisenburps! (and others)

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

Re: Glider Guns of large periods

Post by dvgrn » December 14th, 2014, 5:09 pm

Here's a minor surprise from the dart-synthesis thread, where there's a search on for compact edge-shooting guns.

I didn't expect these pieces to fit together so nicely. Unfortunately the 136+8N can be adjusted to get p168, but not p160, for technical reasons:

Code: Select all

#C Fx119 edge-shooting guns, periods 136+8N, 208+8N, 408+8N
x = 331, y = 74, rule = B3/S23
54b2o3b2o$54b2o2bob3o$58bo4bo$54b4ob2o2bo$54bo2bobobob2o$57bobobobo$
58b2obobo$62bo2$48b2o$49bo7b2o$49bobo5b2o112b2o3b2o$50b2o119b2o2bob3o
111b2o3b2o$175bo4bo110b2o2bob3o$171b4ob2o2bo114bo4bo$171bo2bobobob2o
109b4ob2o2bo$174bobobobo110bo2bobobob2o$175b2obobo113bobobobo$179bo
115b2obobo$60b2o22bo214bo$60bo21b3o80b2o$61b3o17bo84bo7b2o109b2o$63bo
17b2o83bobo5b2o110bo7b2o$73bo93b2o117bobo5b2o$74b2o211b2o$73b2o14b2ob
2o68bo$33bo56bob2o67b3o118bo$90bo69bob3o$31b3obo46b2o4b3o56b2obo8bo3bo
116b3obo$18b2obo8bob2o48b2o3bo3b2o55bob3o5bo3bo104b2obo8bob2o$19bob3o
6b2obo53b4o2bo35bo18bo4bo3b3obo15b2o89bob3o6b2obo$o18bo4bo3bob3o40b2o
15bob2o35b3o6b2o6b3o3b2o4b3o16bo24bo46bo18bo4bo3bob3o15b2o22bo$3o6b2o
6b3o3b2o47bobo12b3o2bo39bo5b2o5bo13bo18b3o19b3o46b3o6b2o6b3o3b2o23bo
21b3o$3bo5b2o5bo13bo41bo13bo5bo38b2o12b2o8bo24bo18bo52bo5b2o5bo13bo18b
3o17bo$2b2o12b2o8bo44b2o14b5o62bobo42b2o50b2o12b2o8bo24bo17b2o$25bobo
61bo60b2o2b2o118bobo$21b2o2b2o117b2o4b2o118b2o2b2o$15b2o4b2o121b2o16b
2o43b2ob2o52b2o4b2o54b2ob2o$15b2o146b2o43bob2o52b2o61bob2o$32b2o128bo
45bo72b2o44bo$33b2o102b2o28bo32b2o4b3o73b2o35b2o4b3o$32bo5bo97bobo28b
3o30b2o3bo3b2o70bo5bo31b2o3bo3b2o$8b3o27b3o95bo2bo30bo34b4o2bo45b3o27b
3o34b4o2bo$8bo32bo95b2o30b2o20b2o15bob2o45bo32bo19b2o15bob2o$7b2o31b2o
95bo41b2o9bobo12b3o2bo45b2o31b2o18bobo12b3o2bo$6bo2bo40b2o127bo10bo13b
o5bo44bo2bo40b2o8bo13bo5bo$8b2o40bo126bobo9b2o14b5o47b2o40bo8b2o14b5o$
5b5o38bobo120b2o4b2o28bo46b5o38bobo26bo$5b5o32b2o4b2o120bo2bo80b5o32b
2o4b2o$6bo2b2o30bo2bo90b3o33b2o82bo2b2o30bo2bo$7b3o28bo3b2o91bo2b2o19b
2o95b3o32b2o$8bo21b2o7bo10bo85b3o20b2o19bo76bo21b2o18bo$30b2o5b3o10b3o
84bo42b3o96b2o18b3o$53bo129bo118bo$52b2o82bo45b2o117b2o$4b2o36bo87b3o
2b3o115b2o36bo$2bo3bobo32bobo90bob2o49bo63bo3bobo32bobo$2b3obobo2bo29b
obo86bo3b2ob2o46b2o64b3obobo2bo29bobo$3bo2bobobo31bo6b2o81bobo11b2o38b
2o64bo2bobobo31bo$5b3o9b2o29b2o82bobo11b2o20b2o3b2o79b3o9b2o$5bo11b2o
20b2o3b2o4bo81b2o35bo3bo80bo11b2o20b2o3b2o$4b2o34bo3bo17b2o102b3o5b3o
15b2o59b2o34bo3bo17b2o$37b3o5b3o7b2o5bobo101bo9bo8b2o5bobo91b3o5b3o7b
2o5bobo$5b2o30bo9bo7bobo6bo120b2o7bo59b2o30bo9bo7b2o7bo$5bobo56b2o68b
2obo56b2o58bobo56b2o$4bo3bo123b2obobo115bo3bo$4bo46bo83b3o43bo71bo46bo
$4bobob2o40bobob2o76b3o45bobob2o67bobob2o40bobob2o$5b3o42bobob2o124bob
obobo67b3o42bobobobo$47b2obobo3bo2bo117b2obobobobo2bo106b2obobobobo2bo
$47bo2bo2b2ob4o117bo2bo2b2ob4o106bo2bo2b2ob4o$8bo40b2o4bo82bo40b2o4bo
71bo40b2o4bo$9bo45bobo81bo45bobo70bo45bobo$7b3o46b2o79b3o46b2o68b3o46b
2o!
I haven't done a complete survey, but it looks as if there are several improvements to the collection in these various gun families, including p152 and p160:

Code: Select all

#C p152+8N HtoG#1 3-signal edge shooter, adjusted to p160
x = 102, y = 71, rule = B3/S23
62b2o3b2o$62b2o2bob3o$66bo4bo$62b4ob2o2bo$62bo2bobobob2o$65bobobobo$
66b2obobo$70bo2$56b2o$57bo7b2o$57bobo5b2o$58b2o3$20b2o3b2o$20b2o2bob3o
$24bo4bo$20b4ob2o2bo$20bo2bobobob2o37b2o22bo$23bobobobo38bo21b3o$24b2o
bobo39b3o17bo$28bo42bo17b2o2$14b2o66bo$15bo7b2o58b2o12b2ob2o$15bobo5b
2o57b2o14bob2o$16b2o80bo$90b2o4b3o$o89b2o3bo3b2o$3bo91b4o2bo$2bobo76b
2o15bob2o$bo3bo74bobo12b3o2bo$2bo3bo73bo13bo5bo$3bo3bo18b2o51b2o14b5o$
4bo3bo17bo70bo$5bobo19b3o13b2o$6bo17bo4bo14b2o$10bo11b3o18bo5bo$9bobo
2b2o5bo27b3o$10b2o2bobo4b2o29bo$6b2o6bo36b2o$5bobo53b2o$5bo5b2o48bo$4b
2o5b2o46bobo$53b2o4b2o$52bo2bo$53b2o$41b2o18bo$41b2o18b3o$64bo$63b2o$
15b2o$9b2o2bo3bobo38b2o$9b2o2b3obobo2bo34b2o$14bo2bobobo37bo$16b3o$16b
o33b2o3b2o$15b2o13b2o19bo3bo17b2o$30bobo15b3o5b3o7b2o5bobo$16b2o14bo
15bo9bo7b2o7bo$16bobo13b2o41b2o$15bo3bo$15bo46bo$15bobob2o40bobob2o$
16b3o42bobobobo$58b2obobobobo2bo$58bo2bo2b2ob4o$19bo40b2o4bo$20bo45bob
o$18b3o46b2o!

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

Re: Glider Guns of large periods

Post by simsim314 » December 15th, 2014, 3:52 am

@dvgrn - some script is probably needed to compare adjusted guns, with what is currently in the collection. Is there some "optimal" way to adjust the guns? or we need to check all options and take the best with smallest bounding box are?

If you can specify periods with improvements, I'll just add them to the improvements list.

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

Re: Glider Guns of large periods

Post by dvgrn » December 15th, 2014, 12:17 pm

:idea:
simsim314 wrote:@dvgrn - some script is probably needed to compare adjusted guns, with what is currently in the collection.
Jason Summers wrote something along those lines a decade ago, and amazingly it appears not to have succumbed to bit-rot yet -- it's still available for download.

It has several minor blind spots and limitations, but they're all conveniently listed in the readme.txt. The idea is to put a folder of appropriately named new guns in a folder inside a populated guns1j-20121211 folder, along with guntest.exe. You get back a report of which guns in the new folder are smaller in bounding-box area than the known guns in the existing collection, and also which guns don't work as advertised.
simsim314 wrote:Is there some "optimal" way to adjust the guns? or we need to check all options and take the best with smallest bounding box are?
Well... in general there's no one optimal way to fold a signal loop into the smallest possible space. Check out p00424.lif in the current gun collection:

Code: Select all

#C p424 gun based on Dave Greene's p232
#C Scot Ellison - 15 November 2005
x = 111, y = 77, rule = LifeHistory
63.2B3.B$62.3A8.2B$62.3BAB6.BAB$61.A3BAB4.2B3A$51.A8.A.A2BA5.B3ABA$
51.3A4.A2BA.A8.BA2B.A8.A$54.A2.BA3BA11.A.2BAB4.3A$53.2A2.BA3B13.AB3AB
2.A$53.4B2.3A14.3A2B2.2A$55.BAB.2B15.BAB2.4B$54.BABA.B17.2B.BAB$51.2A
.B2A2B19.B.ABAB$51.2A7B19.2B2AB.2A$52.7B19.7B2A$52.7B20.7B$53.6B20.7B
$52.8B19.6B$51.4B2.4B17.8B$50.4B4.4B15.4B2.4B$49.4B6.4B13.4B4.4B19.2A
$48.4B8.4B11.4B6.4B17.3B$47.4B10.4B9.4B8.4B16.A3BA$46.4B12.4B7.4B10.
4B14.A4BA$45.4B14.4B5.4B12.4B12.A.ABAB$44.4B16.4B3.4B14.4B9.BABA.A$
43.4B18.4B.4B16.4B7.A4BA$42.4B20.7B18.4B3.B.BA3BA$41.4B22.5B20.8B3.3B
$40.4B23.5B21.7BAB.2A$39.4B23.7B21.5BABAB$38.4B23.4B.4B20.2A3B2A2B$
37.4B23.4B3.4B18.ABA5B.B2A$36.4B23.4B5.4B16.3BA3B3.BA.A$35.4B23.4B7.
4B14.4B.2B2A5.A$34.4B23.4B9.4B12.4B4.2A5.2A$15.2A16.4B23.4B11.4B10.4B
$8.2A3.2B2AB14.4B23.4B13.4B8.4B$7.B2AB2.4B14.4B23.4B15.4B6.4B$8.2B3.
6B.B9.4B8.A9.A4.4B17.4B4.4B$9.2B2.10B6.2A2B9.3A5.3A3.4B19.4B2.4B$8.2B
2A11B5.ABAB13.A3.A5.4B21.8B$5.B.3B2A12B3.3BA13.2A.B.2A3.4B23.6B$4.2A
18B2.4B14.7B2.4B25.4B$4.2AB.15B2.4B17.3B3.4B25.6B4.2A5.2A$5.B3.19B17.
5B.4B25.8B.2B2A5.A$9.18B18.9B25.4B2.7B3.BA.A$10.19B2.2B3.2B6.9B4.2B
19.4B4.8B.B2A$10.42B5.BAB17.4B6.5B2A2B$11.7B.32B4.2B3A16.4B7.5BABAB$
11.6B2.16B2A14B4.B3ABA14.4B7.7BAB.BA$10.7B.17B2A16B3.BA2B.A12.4B7.8B
3.2AB$10.6B.30B2A4B5.A.2BAB9.4B7.4B3.B.2BAB2A$11.9B7.4B.3B.2B.7BA2BA
4B5.AB3AB7.4B7.4B7.3A2BA$11.8B9.4B6.4B.B.2B2AB2.B2A5.3A3B.B3.4B7.4B9.
BABA.A$10.8B11.4B4.4B4.5B2.BA.A4.BAB3.8B7.4B12.A.ABAB$.A8.7B13.4B2.4B
7.2B6.A5.2B.BA7B7.4B14.A2B3A$.3A6.6B15.8B6.4B6.2A6.BABA5B7.4B16.2ABAB
$4.A4.7B16.6B7.2A16.2B2A5B6.4B17.B2A$3.2A4.7B15.7B8.A14.2AB.8B4.4B19.
AB$3.4B.8B15.7B5.3A14.A.AB3.7B2.4B$5.11B14.2A7B4.A16.A5.2A2B.8B$4.12B
14.2A.B2A2B21.2A5.2A4.6B$4.12B17.BABA.B33.7B$4.11B10.A8.BAB.2B32.7B$
5.7B11.3A6.4B2.BAB30.7B2A$4.10B8.A9.2A2.2BABA31.2B2AB.2A$3.13B6.2A9.A
2.BA3BA29.B.ABAB$.23B6.3A4.BA2B.A27.2B.BAB$.21B8.A8.A.2BAB24.BAB2.4B$
2A21B17.A3BAB23.ABA2B2.2A$2A21B18.ABA2B22.A3BAB2.A$.B.21B17.BAB23.A.
2BAB4.3A$3.9B.7B.4B17.2B21.BA2B.A8.A$9.B7.2B3.4B38.BA3BA$8.3B5.BA2B3.
3BA37.2BABA$8.B2AB4.A.A5.3BA38.BAB$9.2A6.A7.3AB37.2B!
At the time nobody could find a better way to reach period 424 than to fold a p848 glider/Herschel loop into as small a space as possible, with multiple signal crossings, and run two signals in the loop. The existing p320, p328, p344 and p392 guns are in the same series. Probably all of these can be improved now -- but possibly the first two or three will still turn out to be smaller than any alternatives based on the new edge shooters.

The p424 can now be rebuilt much smaller by starting with the p408 from a few posts back, and moving two of the Snark reflectors two diagonal cells each:

Code: Select all

#C period 424 edge shooter = 408+8N, N=2
x = 84, y = 64, rule = B3/S23
42b2o3b2o$42b2o2bob3o$46bo4bo$42b4ob2o2bo$42bo2bobobob2o$45bobobobo$
46b2obobo$50bo2$36b2o$37bo7b2o$37bobo5b2o$38b2o2$33bo2$31b3obo$18b2obo
8bob2o$19bob3o6b2obo$o18bo4bo3bob3o15b2o$3o6b2o6b3o3b2o23bo$3bo5b2o5bo
13bo18b3o22bo$2b2o12b2o8bo24bo20b3o$25bobo43bo$21b2o2b2o44b2o$15b2o4b
2o11b2o$15b2o18b2o$34bo44b2ob2o$8b3o69bob2o$7b2o2bo26bo41bo$6bo31b3o
31b2o4b3o$41bo30b2o3bo3b2o$6bo4bo28b2o35b4o2bo$8b2o40b2o11b2o15bob2o$
50bo11bobo12b3o2bo$48bobo11bo13bo5bo$7bo34b2o4b2o11b2o14b5o$5b2ob2o31b
o2bo34bo$42b2o$8bobo19b2o$5b3o2b2o18b2o$9b2o41bo$6b2ob2o41b3o$2b4ob2o
33bo12bo$bo5bo33bobo10b2o$6bo34bobo$4bo37bo$2b3o12b2o$bo3bo11b2o20b2o
3b2o$2b4o34bo3bo$2b3o32b3o5b3o$4bo32bo9bo16b2o$4b2o51b2o5bobo$6b2o49b
2o7bo$6bob2o56b2o$2bo3bo2bo$3b2obobo44bo$5b3o44bobob2o$52bobobobo$49b
2obobobobo2bo$49bo2bo2b2ob4o$10bo40b2o4bo$11bo45bobo$9b3o46b2o!
If we wanted to make let's say a period 800 gun by adjusting this one, just moving the Snarks diagonally wouldn't give an optimal bounding box any more -- it would work better to fold the loop around a few more corners, as in the old p424. But really there are smaller gun options already known anyway for all p8N periods above 500 or 600, so we don't really have to investigate too many variants.

Adding more corners is very easy to do now, because additional Snarks don't change the timing mod 8. P8N domino-spark reflectors do change the timing -- one tick per reflector, as I recall -- so you can't just unfold the old p424 into a simple loop and have it still work the same.

EDIT: An editor GUI that handles signal circuitry at the circuit level instead of the cell level has been on a lot of people's wish lists for a good while now. Really you want to be able to click and drag a Snark, and have it constrained to diagonal movement only, and have either the previous or the following circuit component (depending on the direction of movement) get automatically adjusted to stay lined up.

If there are oscillating reflectors or Herschel conduits or whatever in the circuit, they should be rephased automatically, and the component being moved would "snap" to only locations corresponding to circuit lengths that work for those oscillators. -- Oh, and if you move an object a little too close to another one, known welds could be applied automatically. (And while I'm wishing, I'd like a small stable glider-to-Herschel converter.)
simsim314 wrote:If you can specify periods with improvements, I'll just add them to the improvements list.
I might get around to sorting this out eventually, but it's not high on my priority list. If anyone can use a little practice building mixed Herschel-and-glider signal circuitry, this would make a very good starter project...!

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

Re: Glider Guns of large periods

Post by simsim314 » December 15th, 2014, 1:13 pm

dvgrn wrote:An editor GUI that handles signal circuitry at the circuit level instead of the cell level has been on a lot of people's wish lists for a good while now. Really you want to be able to click and drag a Snark, and have it constrained to diagonal movement only, and have either the previous or the following circuit component (depending on the direction of movement) get automatically adjusted to stay lined up.
I do agree I would like something of this sort.

There are some technical issues like: allow the movement in the direction of it's input glider or output? You don't want to choose this option all the time.

Also you would probably want something like - given a glider add a snark to it. Or given Hersh choose a circuit to it.

There is also an issue with reflecting oscillators - if you move them, you might want to oscillate them acordingly (and sometimes not).

---

I don't like too much this - micro management, I would prefer pure logical editor. But let me see if I can make something simple and customizable quickly - in the simplest level you're talking about, and maybe someone will take over the project to add more features.

It's really annoying we have nothing of this sort, and it can be VERY simply coded (at least the basic recognition + movement limitation).

---

EDIT As for the gun collection - I want to built single rle for the collection. And script that knows how to extract glider stream from glider gun, and based on that calculate glider gun max area.

Both of the scripts should be pretty simple to write. Maybe we also need something like "LifeAPI" for python. A collection of useful functions, that could be easily reused. Although I don't like to write "nicely" in python, with classes etc. but for reuse and collaboration it's the only way.

EDIT2 I would also like to have a piece of code that take some glider and pattern, and iterates on area of the glider, placing the combination of pattern+perturbated glider into array of results by some step. I'm doing this kind of searches too much by hand myself.

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

Re: Glider Guns of large periods

Post by simsim314 » December 15th, 2014, 7:04 pm

OK for this thread I've created two gun scripts.

Script1 - Evaluates the size of your gun. It finds the period, iterates over all states of the gun, and reports the final bounding box area.

Code: Select all

#Get the Value of gun which should be the only thing present in the current Document.
#Make sure you've saved your work. This script deletes history. 
#This script is made to evaluate glider gun value (area) automatically. 
#Written by Michael Simkin 2014
import golly as g 
import glob

'''Number Placement'''

snakeLineHor = g.parse("2obob2obo$ob2obob2o!")
snakeLineVer = g.transform(snakeLineHor, -3, 3, 0, 1, 1, 0)

figure8 = [snakeLineVer, g.transform(snakeLineVer, 0, 13),  snakeLineHor, g.transform(snakeLineHor, 0, 13), g.transform(snakeLineHor, 0, 26), g.transform(snakeLineVer, 13, 0), g.transform(snakeLineVer, 13, 13)]

def PlaceDigit(digit, x = 0, y = 0):
	digitIdx = [[0,1,2,4,5,6], [5,6],[1,2,3,4,5],[2,3,4,5,6],[0,3,5,6],[0,2,3,4,6],[0,1,2,3,4,6],[2,5,6],[0,1,2,3,4,5,6],[0,2,3,4,5,6]]
	
	if digit >= 0 and digit <= 9:
		for idx  in digitIdx[digit]:
			g.putcells(figure8[idx], x, y)
def NumDigit(num):
	if num < 10: 
		return 1 
	else: 
		return 1 + NumDigit(int((num - (num % 10))/10))
		
def PlaceNumber(number, x = 0, y = 0):
	if number < 0: 
		g.putcells(figure8[3], x, y)
		PlaceNumber(-number, x, y)
		return
	  
	curNum = number
	d = 20 * NumDigit(number)
	
	while True:
		PlaceDigit(curNum%10, x + d, y)
		curNum = (curNum - curNum%10) / 10 
		
		if curNum == 0:
			return 
		
		d -= 20


'''Code starts here''' 

gld = g.parse("bo$2bo$3o!")		
		
def PeriodCalculator():
	
	g.setbase(8)
	g.setstep(3)
	g.step()
	g.step()

	cells = g.getrect()
	
	rect = g.getrect()
	cells = g.getcells(rect)
	
	for i in xrange(0, 10000):
		g.run(1)
		if str(g.getcells(rect)) == str(cells):
			#g.show(str(i + 1))
			#g.reset
			return i + 1
	
	return -1
	
def GunsReader():
	
	result = [] 
	
	for i in xrange(0, 10000):
		cells = g.getcells([0, i * 650, 500, 550])
		
		if len(cells) == 0:
			return result 
		
		g.select([-200, i * 650 - 10, 800, 550])
		g.clear(0)
		
		result.append(cells)
	

def GunPlacer(gunCollection):

	g.new("")
	
	for i in xrange(0, len(gunCollection)):
		g.putcells(gunCollection[i], 0, 0);
		PlaceNumber(i + 14, -150, i * 650)

def EdgeGlider():
	
	for i in xrange(0, 4):
		rect = g.getrect()
		
		x0 = rect[0] + rect[2] - 3
		y0 = rect[1] + rect[3] - 3
		
		gldFound = True
		
		for j in xrange(0, len(gld), 2):
			if g.getcell(x0 + gld[j], y0 + gld[j + 1]) == 0:
				gldFound = False
				break
		
		if gldFound:
			return g.getcells([x0, y0, 3, 3])
			
		g.run(1)
	
	return -1
	
def Erase(glider):
	for j in xrange(0, len(glider), 2):
		g.setcell(glider[j], glider[j + 1], 0)

def DevolveGlider(glider, delta):	
	return g.evolve(g.transform(glider, -delta, -delta), 3 * delta)

def PerformDelete(glider, gunPeriod):

	initCells = g.getcells(g.getrect())
	
	for j in xrange(0, len(glider), 2):
		if g.getcell(glider[j], glider[j + 1]) != 1:
			return False
	
	Erase(glider)
	rect = g.getrect()
	cells = g.getcells(rect)
	g.run(gunPeriod)
	
	if str(g.getcells(rect)) == str(cells):
		g.new("")
		g.putcells(cells)
		return True
	else:
		g.new("")
		g.putcells(initCells)
		return False

def AppendBox(maxBox, rect):

	if maxBox[0] > rect[0]:
		maxBox[0] = rect[0]
	
	if maxBox[1] > rect[1]:
		maxBox[1] = rect[1]
		
	if maxBox[2] < rect[0] + rect[2] - 1:
		maxBox[2] = rect[0] + rect[2] - 1
	
	if maxBox[3] < rect[1] + rect[3] - 1:
		maxBox[3] = rect[1] + rect[3] - 1
	
	return maxBox
	
def BoxValue(box):
	return (box[3] - box[1]) *  (box[2] - box[0])


def GunArea(cells, curGunPeriod):

	maxBox = [10000, 10000, -1000, -1000]
	
	for i in xrange(0, curGunPeriod, 4):
		
		g.new(str(i))
		g.putcells(g.evolve(cells, i))
		
		g.setbase(8)
		g.setstep(3)
		g.step()
		g.step()
		g.step()
		g.step()
		
		
		edgeGlider = EdgeGlider()

		while PerformDelete(edgeGlider, curGunPeriod):
			edgeGlider = DevolveGlider(edgeGlider, curGunPeriod)
		
		for j in xrange(0, 4):
			maxBox = AppendBox(maxBox, g.getrect())
			g.run(1)
		
		if i == 0:
			somegun = g.getcells(g.getrect())
		
	return [BoxValue(maxBox), somegun, maxBox]
	

cells = g.getcells(g.getrect())
curGunPeriod = PeriodCalculator()

if curGunPeriod == -1:
	note("Failed to find gun period")
	g.exit("No gun found")

edgeGlider = EdgeGlider()

if edgeGlider == -1:
	g.note("Please orient the gun properly")
	g.exit("No glider found in bottom right corner")

valueGun = GunArea(cells, curGunPeriod)
g.show("The value = " + str(valueGun[0]) + ", The box = " + str(valueGun[2]) )
Script2 is gun analyzer and adder. To use it open GunCollection.rle (please use either open clipboard in the file menu, or save and open the rle - don't paste it in random place), add to it your gun at some place which is far from the gun collection . Then run the script - if your gun is better, the script will prompt and add it in the place of previously known best gun.

Code: Select all

#Copy-Paste your gun into GunCollection.rle (collection of best guns p14-p1000) and run this script. 
#The script reads gun collection. Analyzes your gun. 
#Compares the best result and your gun - if yours better the script will replace the best by yours. 
#Updates for the latest GunCollection.rle: http://www.conwaylife.com/forums/viewtopic.php?f=2&t=1300&start=0
#Written By Michael Simkin 2014.
import golly as g 
import glob

'''Number Placement'''

snakeLineHor = g.parse("2obob2obo$ob2obob2o!")
snakeLineVer = g.transform(snakeLineHor, -3, 3, 0, 1, 1, 0)

figure8 = [snakeLineVer, g.transform(snakeLineVer, 0, 13),  snakeLineHor, g.transform(snakeLineHor, 0, 13), g.transform(snakeLineHor, 0, 26), g.transform(snakeLineVer, 13, 0), g.transform(snakeLineVer, 13, 13)]

def PlaceDigit(digit, x = 0, y = 0):
	digitIdx = [[0,1,2,4,5,6], [5,6],[1,2,3,4,5],[2,3,4,5,6],[0,3,5,6],[0,2,3,4,6],[0,1,2,3,4,6],[2,5,6],[0,1,2,3,4,5,6],[0,2,3,4,5,6]]
	
	if digit >= 0 and digit <= 9:
		for idx  in digitIdx[digit]:
			g.putcells(figure8[idx], x, y)
def NumDigit(num):
	if num < 10: 
		return 1 
	else: 
		return 1 + NumDigit(int((num - (num % 10))/10))
		
def PlaceNumber(number, x = 0, y = 0):
	if number < 0: 
		g.putcells(figure8[3], x, y)
		PlaceNumber(-number, x, y)
		return
	  
	curNum = number
	d = 20 * NumDigit(number)
	
	while True:
		PlaceDigit(curNum%10, x + d, y)
		curNum = (curNum - curNum%10) / 10 
		
		if curNum == 0:
			return 
		
		d -= 20


'''Code starts here''' 

gld = g.parse("bo$2bo$3o!")		
		
def PeriodCalculator():
	
	g.setbase(8)
	g.setstep(3)
	g.step()
	g.step()
	g.step()
	g.step()
	
	cells = g.getrect()
	
	rect = g.getrect()
	cells = g.getcells(rect)
	
	for i in xrange(0, 10000):
		g.run(1)
		if str(g.getcells(rect)) == str(cells):
			#g.show(str(i + 1))
			#g.reset
			return i + 1
	
	return -1
	
def GunsReader():
	
	result = [] 
	
	for i in xrange(0, 10000):
		cells = g.getcells([0, i * 650, 500, 550])
		
		if len(cells) == 0:
			return result 
		
		g.select([-200, i * 650 - 10, 800, 550])
		g.clear(0)
		
		result.append(cells)
	

def GunPlacer(gunCollection):

	g.new("")
	
	for i in xrange(0, len(gunCollection)):
		g.putcells(gunCollection[i], 0, 0);
		PlaceNumber(i + 14, -150, i * 650)

def EdgeGlider():
	
	for i in xrange(0, 4):
		rect = g.getrect()
		
		x0 = rect[0] + rect[2] - 3
		y0 = rect[1] + rect[3] - 3
		
		gldFound = True
		
		for j in xrange(0, len(gld), 2):
			if g.getcell(x0 + gld[j], y0 + gld[j + 1]) == 0:
				gldFound = False
				break
		
		if gldFound:
			return g.getcells([x0, y0, 3, 3])
			
		g.run(1)
	
	return -1
	
def Erase(glider):
	for j in xrange(0, len(glider), 2):
		g.setcell(glider[j], glider[j + 1], 0)

def DevolveGlider(glider, delta):	
	return g.evolve(g.transform(glider, -delta, -delta), 3 * delta)

def PerformDelete(glider, gunPeriod):

	initCells = g.getcells(g.getrect())
	
	for j in xrange(0, len(glider), 2):
		if g.getcell(glider[j], glider[j + 1]) != 1:
			return False
	
	Erase(glider)
	rect = g.getrect()
	cells = g.getcells(rect)
	g.run(gunPeriod)
	
	if str(g.getcells(rect)) == str(cells):
		g.new("")
		g.putcells(cells)
		return True
	else:
		g.new("")
		g.putcells(initCells)
		return False

def AppendBox(maxBox, rect):

	if maxBox == []:
		return [rect[0], rect[1], rect[0] + rect[2] - 1, rect[1] + rect[3] - 1]
		
	if maxBox[0] > rect[0]:
		maxBox[0] = rect[0]
	
	if maxBox[1] > rect[1]:
		maxBox[1] = rect[1]
		
	if maxBox[2] < rect[0] + rect[2] - 1:
		maxBox[2] = rect[0] + rect[2] - 1
	
	if maxBox[3] < rect[1] + rect[3] - 1:
		maxBox[3] = rect[1] + rect[3] - 1
	
	return maxBox
	
def BoxValue(box):
	return (box[3] - box[1]) *  (box[2] - box[0])


def GunArea(cells, curGunPeriod):

	maxBox = []
	minpop = -100000
	
	for i in xrange(0, curGunPeriod, 4):
		
		g.new(str(i))
		g.putcells(g.evolve(cells, i))
		
		g.setbase(8)
		g.setstep(3)
		g.step()
		g.step()
		
		edgeGlider = EdgeGlider()

		while PerformDelete(edgeGlider, curGunPeriod):
			edgeGlider = DevolveGlider(edgeGlider, curGunPeriod)
		
		for j in xrange(0, 4):
		
			if g.getpop() > minpop:
				maxpop = g.getpop()
				maxpopgun = g.getcells(g.getrect())
				
			maxBox = AppendBox(maxBox, g.getrect())
			g.run(1)
		
	return [BoxValue(maxBox), maxpopgun, maxBox]
	
g.show("Reading guns into memory...")
g.update()
guns = GunsReader()
cells = g.getcells(g.getrect())

curGunPeriod = PeriodCalculator()

g.show("Calculating Period...")
g.update()

if curGunPeriod == -1:
	note("Failed to find gun period")
	g.exit("No gun found")

edgeGlider = EdgeGlider()

if edgeGlider == -1:
	g.note("Please orient the gun properly")
	g.exit("No glider found in bottom right corner")


g.show("searching box for your gun...")
g.update()

valueGun = GunArea(cells, curGunPeriod)


g.show("searching box for known gun...")
g.update()

dbValue =  GunArea(guns[curGunPeriod - 14], curGunPeriod)

if dbValue[0] > valueGun[0]:
	
	g.show("Success! Placing the gun array with your gun")
	g.update()

	g.new("")
	g.putcells(valueGun[1])
	rect = g.getrect()
	
	g.new("")
	g.putcells(cells, -rect[0], -rect[1] + 650 * (curGunPeriod - 14))
	cells = g.getcells(g.getrect())
	guns[curGunPeriod - 14] = cells
	
	GunPlacer(guns)
	g.setpos("0", str(650 * (curGunPeriod - 14)))
	g.setmag(-1)
	g.note("Congrats! You've found a better gun! \n  You gun value = {0}, The best known value = {1}".format(valueGun[0], dbValue[0]))
	g.exit("Please save the file, and post it as attachemnt on the forum")
else:
	g.new("")
	g.putcells(valueGun[1])
	g.note("This is not a better gun :( \n You gun value = {0}, The best value = {1}".format(valueGun[0], dbValue[0]))
	g.exit("Here is your gun")
	

I've also created git repository for this project, where you can find GunCollection.rle with all the current best guns, and both of the script (only the second script requires GunCollection.rle the evaluation can run as is).

EDIT @dvgrn I want to post this in the first message, but I've small bug in the second script. When I call g.new("") golly promts with "do you want to save". I want to create new document without prompting, is it even possible?

EDIT As requested by myself I post here perturbation of glider script (place glider it in all possible positions and states in some are):

Code: Select all

import golly as g 

gld = g.parse("3o$o$bo!", -1, -1)

def Iterate(x, y, h, w, gld, pat, pw, ph, dx, dy):

	d = 0
	
	for i in xrange(0, w):
		for j in xrange(0, h):
			for k in xrange(0, 4):
				g.putcells(pat, dx, dy + d)
				g.putcells(g.evolve(gld, k), dx + x + i, dy + y + j + d)
				d += ph * 3
		


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)
		
selRect = g.getselrect()

if selRect != []:
	patW = selRect[2]
	patH = selRect[3]
	pat = g.getcells(selRect)
	patDx =  selRect[0]
	patDy =  selRect[1] + 4 * patH
	
else:
	g.exit("Please select a pattern")

moving = True
selecting = False
val = g.getxy()
x = "a"
y = "a"

while True:
	event = g.getevent()
	
	if "click" in event:
		if "left" in event: 
				
			if moving:	
				
				g.show("select area to petrub the glider")
				moving =  False
				selecting = True
				g.update()
			
				
		elif "right" in event and moving:
			ClearRect(x - 1, y - 1, 3, 3)
			gld = g.transform(gld,0,0, 0, -1, 1, 0)
			ClearRect(x - 1, y - 1, 3, 3)
			g.putcells(gld, x, y)
			
		elif "right" in event and selecting and g.getselrect() != []:
				selrect = g.getselrect() 
				Iterate(selrect[0], selrect[1], selrect[2], selrect[3], gld, pat, patW, patH, patDx, patDy)
				g.exit()
				
	elif event == "" and moving and not selecting:
		if g.getxy() != "":
			val = g.getxy()
			
			if x != "a":
				ClearRect(x - 1, y - 1, 3, 3)
				g.putcells(under)
			
			
		if val == "":
			continue 
		
		x = int(val.split()[0])
		y = int(val.split()[1]) 
		
		under = g.getcells([x - 1, y - 1, 3, 3])
		g.putcells(gld, x, y)
		g.update()
	
	if selecting:
		g.doevent(event)
		
		if g.getselrect() != []:
			g.show("Right mouse click to create petrubation pattern")
			g.update()
		

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

Re: Glider Guns of large periods

Post by dvgrn » December 15th, 2014, 8:53 pm

simsim314 wrote:EDIT @dvgrn I want to post this in the first message, but I've small bug in the second script. When I call g.new("") golly promts with "do you want to save". I want to create new document without prompting, is it even possible?
Well, the warning is coming from a user setting that Golly gives no programmatic control over. You can make it go away by unchecking the appropriate check marks in File > Preferences > Layer, but that won't fix it for other people running Golly with the default settings.

What Golly is doing is trying not allow a script to destroy any work done manually -- this has actually come up once before on this very thread.

Your workflow requires the user to make a manual change to a pattern -- adding a gun to some arbitrary location in GunCollection.rle. So I think that, with your current system, the only ways to avoid that default message would be to

1) have the script add a new layer, and make changes to that; or
2) clear everything out of the current universe (something like g.clear() instead of g.new()) and then paste all the guns back in. That way Golly isn't worried about loss of work, because the Undo buffer doesn't get emptied.

#1 adds an extra layer, eventually making a mess. And #2 an awfully slow way to do something easy. How about this? If you're saying that the user's last action before running the script is a Paste operation, why not just skip the Paste and leave the gun in the clipboard? Golly can get hold of it with g.parse(g.getclipstr()), and then GunCollection.rle is unmodified and there won't be an annoying message.

The next stage would probably be to store GunCollection.rle somewhere standard like Golly's Data folder. Open it in a new layer, rebuild it with the new gun, save it again (with a backup file or two?), and maybe close the new layer again.

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

Re: Glider Guns of large periods

Post by simsim314 » December 15th, 2014, 9:20 pm

dvgrn wrote:The next stage would probably be to store GunCollection.rle somewhere standard like Golly's Data folder.
I'm lately starting to work with json. You take some pattern collection, analyze it slowly with golly, then the results stored in json. Next time you have it all already. It would be great if people started to share jsons, for scripts. Or to base scripts on common jsons. This is also the first step toward distributed searches.

Anyway I myself pretty lazy, so I prefer scripts that can run with "run from clipboard" - and pattern that don't need anything special to them. Asking people to download json and run script from inside a library, is really too much. Obviously it would be the best thing to do for the gun collection queries.

As for your other suggestions, I like to use g.new("") as it gives me clean and fast way to work with golly universe without thinking too much, or worry about other things that can be opened etc. So I guess there is no way to avoid this message.

Anyway this gun replacement script is more for me, people can just post guns, and use the GunValue.py script to see the accurate value of their gun - and obviously take the gun from collection and see the current best value.

If there would be such a need, I can add GunValue next to it's period in the GunsCollection.rle. Anyway I think there is enough tools to work with this collection.

I was testing this tool with recent guns improvements - and it worked nicely. So I say lets concentrate on the guns, and if people will need some more tools for it, or some other improvements - we'll think then. For now I think it's good enough.

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

Re: Glider Guns of large periods

Post by simsim314 » December 16th, 2014, 7:31 pm

dvgrn wrote:EDIT: An editor GUI that handles signal circuitry at the circuit level instead of the cell level has been on a lot of people's wish lists for a good while now. Really you want to be able to click and drag a Snark, and have it constrained to diagonal movement only
I've wrote a small golly script that recognize component (specifically some reflectors), restrict their movement by their orientation to continue supporting input gliders, and iterates the oscillating reflectors to according internal state relative to the movement.

It's just a start - I hope that people will start to use it, and request improvements.

Here it is.

Post Reply