Freeze-Dried Slow Salvos

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

Freeze-Dried Slow Salvos

Post by dvgrn » September 1st, 2016, 10:01 am

I've been going on about "freeze-dried slow salvos" for years now, but there are still very few actual examples. It's certainly possible to do a lot better than the all-blocks sample I posted three years ago. Here are the results of a first trial run at writing a freeze-dried slow salvo seed compiler. The first test of the script uses slow salvos for creating semi-Snarks and loaf2GtoGs.

loaf2GtoG: E+0 E+11 E-34 E+11 E-34 E+11 E-13 E+56 E-47 E+43 E-40 E+42 O-58 E+51 O-31 O+41 O-31 E+21 E-22 E+8 E+1 E+16 E-42 E+49 E-49 O+47 E-32 E+37 E-52 O+37 O-31 O+34 O-41 O+40 E-20 E-5 E+5 E-5

Code: Select all

x = 807, y = 786, rule = LifeHistory
24.2A$24.2A3$29.2A$29.2A12$.2A$A.A$.A3$59.A$58.A.A$59.2A19$31.A$30.A.
A$30.2A3$28.2A42.2A$28.A.A41.2A$29.A.A$30.A$77.2A$77.2A9$99.A$51.A46.
A.A$50.A.A46.2A$50.2A2$116.2A$48.2A66.2A$48.A.A$49.A.A$50.A70.2A$121.
2A11$71.A$70.A.A$70.2A3$68.2A$68.A.A$69.A.A$70.A12$97.2A62.A$96.A2.A
60.A.A$96.A2.A61.2A$97.2A$90.A$89.A.A$89.A.A$90.A2$129.A$128.A.A$129.
2A9$111.A$110.A.A$110.2A3$108.2A$108.A.A$109.A.A$110.A12$137.2A$136.A
2.A$136.A2.A$137.2A$130.A$129.A.A63.2A$129.A.A63.2A$130.A2$168.2A30.
2A$168.2A30.2A3$173.2A$173.2A6$151.A$150.A.A$150.2A3$148.2A$148.A.A$
149.A.A$150.A12$177.2A22.A$176.A2.A20.A.A$176.A2.A21.2A$177.2A$170.A$
169.A.A$169.A.A79.2A$170.A80.2A3$256.2A$256.2A9$197.2A$196.A2.A$196.A
2.A$197.2A$190.A$189.A.A$189.A.A$190.A13$211.A68.2A$210.A.A44.A22.2A$
210.2A44.A.A$257.2A$285.2A$208.2A75.2A$208.A.A$209.A.A$210.A12$231.A$
230.A.A$230.2A3$228.2A$228.A.A$229.A.A$230.A12$257.2A$256.A2.A$256.A
2.A$257.2A$250.A83.A$249.A.A81.A.A$249.A.A82.2A$250.A5$285.2A$285.2A
3$290.2A$290.2A3$271.A$270.A.A$270.2A3$268.2A$268.A.A$269.A.A$270.A
11$362.A$291.A29.A39.A.A$290.A.A27.A.A39.2A$290.2A29.2A3$288.2A$288.A
.A$289.A.A$290.A12$317.2A$316.A2.A$316.A2.A$317.2A$310.A$309.A.A$309.
A.A$310.A12$378.2A$337.2A39.2A$336.A2.A$336.A2.A$337.2A44.2A$330.A52.
2A$329.A.A$329.A.A$330.A4$389.2A$389.2A3$394.2A$394.2A4$351.A$350.A.A
$350.2A3$348.2A$348.A.A$349.A.A$350.A7$405.2A$405.2A3$410.2A$377.2A
31.2A$376.A2.A$376.A2.A$377.2A$370.A65.2A$369.A.A64.2A$369.A.A$370.A$
441.2A$441.2A11$397.2A$396.A2.A$396.A2.A$397.2A$390.A$389.A.A$389.A.A
$390.A13$417.2A$416.A2.A$416.A2.A$417.2A35.2A$410.A43.2A38.A$409.A.A
81.A.A$409.A.A82.2A$410.A48.2A$459.2A12$431.A$430.A.A$430.2A3$428.2A$
428.A.A$429.A.A$430.A8$485.A$484.A.A$485.2A2$451.A$450.A.A$450.2A2$
516.2A$448.2A66.2A$448.A.A$449.A.A$450.A70.2A$521.2A11$477.2A$476.A2.
A$476.A2.A$477.2A$470.A$469.A.A$469.A.A$470.A10$564.A$563.A.A$564.2A$
497.2A$496.A2.A$496.A2.A$497.2A$490.A$489.A.A$489.A.A$490.A11$519.2A$
519.2A$511.A$510.A.A$510.2A12.2A$524.2A2$508.2A$508.A.A$509.A.A$510.A
10$563.A$562.A.A$537.2A24.2A$536.A2.A$536.A2.A$537.2A$530.A$529.A.A$
529.A.A$530.A3$607.2A$607.2A3$612.2A$612.2A5$557.2A$556.A2.A$556.A2.A
$557.2A$550.A$549.A.A$549.A.A$550.A9$645.A$644.A.A$645.2A2$571.A$570.
A.A$570.2A3$568.2A$568.A.A$569.A.A$570.A39.A$609.A.A$610.2A10$591.A$
590.A.A$590.2A3$588.2A$588.A.A$589.A.A$590.A12$617.2A$616.A2.A$616.A
2.A$617.2A$610.A$609.A.A$609.A.A$610.A9$641.2A$641.2A3$631.A14.2A$
630.A.A13.2A$630.2A3$628.2A$628.A.A41.A$629.A.A39.A.A$630.A41.2A12$
651.A$650.A.A$650.2A$678.A$677.A.A$648.2A28.2A$648.A.A$649.A.A$650.A
10$719.2A$719.2A$677.2A$676.A2.A$676.A2.A44.2A$677.2A45.2A$670.A$669.
A.A$669.A.A$670.A8$725.2A$725.2A3$730.2A$691.A38.2A$690.A.A$690.2A$
775.A$774.A.A$688.2A85.2A$688.A.A$689.A.A$690.A12$717.2A$716.A2.A$
716.A2.A$717.2A$710.A$709.A.A$709.A.A$710.A5$785.2A$785.2A3$790.2A$
790.2A3$731.A$730.A.A$730.2A3$728.2A$728.A.A$729.A.A$730.A$805.2C$
805.2C10$751.A$750.A.A$750.2A3$748.2A$748.A.A$749.A.A$750.A12$767.3A$
767.A$768.A!
#C [[ X 350 Y 350 Z 2 STEP 20 STOP 7000 ]]
semi-Snark:E+0 E+10 E-34 E+22 E-32 E+35 E-32 E+32 E-35 E+43 E-51 E+48 O-36 O+32 E-48 E+50 E-23 E+21 E-30 E+30 E-27 O+27 E-20 E+33 E-32 O+16 O-25 E+38 E-30 E+19 O-32 E+25 E-31 E+29 E-17 E+34 E-23 E+23 E-25 E+35 E-46 E+16 E-16 E+19 E-22 E+30 E-37 E+25 E-17 E+22 E+0 E+0 E+0

Code: Select all

x = 1104, y = 1090, rule = LifeHistory
28.2A$28.2A3$33.2A$33.2A11$52.A$51.A.A$52.2A3$.2A$A.A$.A13$72.A$71.A.
A$72.2A9$37.2A$36.A2.A$36.A2.A$37.2A$30.A$29.A.A$29.A.A$30.A2$92.A$
91.A.A$92.2A9$57.2A$56.A2.A$56.A2.A$57.2A$50.A$49.A.A$49.A.A$50.A13$
77.2A$76.A2.A$76.A2.A$77.2A$70.A$69.A.A$69.A.A$70.A5$105.2A$105.2A3$
110.2A$110.2A3$91.A46.A$90.A.A44.A.A$90.2A46.2A3$88.2A$88.A.A$89.A.A$
90.A12$111.A$110.A.A$110.2A3$108.2A$108.A.A$109.A.A$110.A$171.2A$171.
2A3$176.2A$176.2A2$141.2A$141.2A3$131.A14.2A$130.A.A13.2A$130.2A3$
128.2A$128.A.A$129.A.A$130.A12$157.2A$156.A2.A$156.A2.A$157.2A$150.A
25.2A$149.A.A24.2A$149.A.A$150.A$181.2A$181.2A9$220.A$219.A.A$177.2A
41.2A$176.A2.A$176.A2.A$177.2A$170.A$169.A.A$169.A.A$170.A12$222.A$
191.A29.A.A$190.A.A29.2A$190.2A3$188.2A$188.A.A$189.A.A$190.A3$250.A$
249.A.A$250.2A7$217.2A$216.A2.A$216.A2.A$217.2A$210.A$209.A.A$209.A.A
$210.A12$262.A$237.2A22.A.A$236.A2.A22.2A$236.A2.A$237.2A$230.A$229.A
.A$229.A.A$230.A$309.2A$309.2A3$314.2A$314.2A7$257.2A$256.A2.A$256.A
2.A$257.2A$250.A$249.A.A$249.A.A$250.A13$271.A$270.A.A$270.2A44.A$
315.A.A$316.2A$268.2A$268.A.A$269.A.A$270.A5$344.2A$344.2A3$349.2A$
349.2A2$291.A$290.A.A$290.2A3$288.2A$288.A.A$289.A.A$290.A12$311.A$
310.A.A44.A22.A$310.2A44.A.A20.A.A$357.2A21.2A2$308.2A$308.A.A$309.A.
A$310.A12$331.A$330.A.A$330.2A3$328.2A$328.A.A$329.A.A$330.A12$357.2A
$356.A2.A$356.A2.A$357.2A$350.A$349.A.A$349.A.A$350.A3$387.2A$387.2A
3$392.2A$392.2A3$420.A$419.A.A$371.A48.2A$370.A.A$370.2A3$368.2A$368.
A.A$369.A.A$370.A12$391.A$390.A.A$390.2A3$388.2A$388.A.A$389.A.A$390.
A4$448.2A$448.2A3$421.2A30.2A$421.2A30.2A3$411.A14.2A$410.A.A13.2A$
410.2A3$408.2A$408.A.A$409.A.A$410.A12$437.2A$436.A2.A$436.A2.A$437.
2A$430.A$429.A.A$429.A.A$430.A6$464.2A$464.2A3$469.2A29.2A$469.2A29.
2A2$451.A$450.A.A52.2A$450.2A53.2A3$448.2A$448.A.A$449.A.A$450.A10$
502.2A$502.2A$471.A$470.A.A$470.2A35.2A$507.2A2$468.2A$468.A.A$469.A.
A$470.A79.A$549.A.A$550.2A10$497.2A$496.A2.A$496.A2.A$497.2A$490.A$
489.A.A$489.A.A$490.A13$511.A$510.A.A$510.2A3$508.2A$508.A.A$509.A.A
39.A$510.A39.A.A$551.2A9$579.2A$579.2A$531.A$530.A.A$530.2A52.2A$584.
2A2$528.2A$528.A.A$529.A.A$530.A6$587.A$586.A.A$587.2A4$551.A$550.A.A
$550.2A3$548.2A$548.A.A$549.A.A$550.A2$627.2A$627.2A3$632.2A$632.2A5$
577.2A$576.A2.A$576.A2.A$577.2A$570.A$569.A.A$569.A.A$570.A13$591.A$
590.A.A$590.2A$635.A$634.A.A$588.2A45.2A$588.A.A$589.A.A$590.A61.2A$
652.2A3$657.2A$657.2A7$611.A$610.A.A$610.2A3$608.2A$608.A.A$609.A.A$
610.A12$637.2A$636.A2.A$636.A2.A$637.2A$630.A$629.A.A$629.A.A$630.A$
692.2A$692.2A$667.2A$667.2A$697.2A$697.2A$672.2A$672.2A5$651.A$650.A.
A$650.2A3$648.2A$648.A.A$649.A.A$650.A12$677.2A$676.A2.A$676.A2.A$
677.2A18.2A$670.A26.2A$669.A.A$669.A.A$670.A31.2A$702.2A5$745.A$744.A
.A$745.2A5$697.2A$696.A2.A$696.A2.A$697.2A$690.A$689.A.A$689.A.A$690.
A13$711.A$710.A.A$710.2A3$708.2A$708.A.A$709.A.A38.2A21.2A$710.A39.2A
21.2A3$755.2A21.2A$755.2A21.2A8$731.A$730.A.A$730.2A3$728.2A$728.A.A$
729.A.A$730.A12$757.2A$756.A2.A$756.A2.A$757.2A$750.A$749.A.A$749.A.A
$750.A$812.2A$812.2A3$817.2A$817.2A4$781.A$780.A.A$781.2A$771.A$770.A
.A$770.2A3$768.2A$768.A.A$769.A.A$770.A12$797.2A$796.A2.A$796.A2.A$
797.2A$790.A$789.A.A$789.A.A62.2A$790.A63.2A2$829.A$828.A.A28.2A$829.
2A28.2A9$811.A$810.A.A$810.2A3$808.2A$808.A.A$809.A.A$810.A12$837.2A$
836.A2.A$836.A2.A$837.2A$830.A$829.A.A$829.A.A$830.A6$904.2A$904.2A$
863.A$862.A.A$863.2A44.2A$909.2A2$851.A$850.A.A$850.2A3$848.2A$848.A.
A$849.A.A$850.A12$871.A$870.A.A$870.2A3$868.2A66.A$868.A.A64.A.A$869.
A.A64.2A$870.A3$907.A$906.A.A$907.2A7$891.A$890.A.A$890.2A3$888.2A$
888.A.A$889.A.A$890.A12$917.2A$916.A2.A20.A$916.A2.A19.A.A$917.2A21.
2A$910.A$909.A.A$909.A.A$910.A10$980.2A$980.2A2$937.2A$936.A2.A45.2A$
936.A2.A45.2A$937.2A$930.A$929.A.A$929.A.A$930.A13$951.A$950.A.A$950.
2A3$948.2A$948.A.A23.2A$949.A.A22.2A$950.A2$979.2A29.2A$979.2A29.2A3$
1015.2A$1015.2A5$977.2A$976.A2.A$976.A2.A$977.2A$970.A$969.A.A$969.A.
A$970.A13$997.2A$996.A2.A19.2A$996.A2.A19.2A$997.2A$990.A65.2A$989.A.
A32.2A30.2A$989.A.A32.2A$990.A$1061.2A$1061.2A11$1017.2A$1016.A2.A$
1016.A2.A$1017.2A$1010.A$1009.A.A$1009.A.A$1010.A2$1071.2A$1071.2A3$
1076.2A$1076.2A6$1037.2A$1036.A2.A$1036.A2.A$1037.2A$1030.A$1029.A.A$
1029.A.A$1030.A13$1057.2A$1056.A2.A$1056.A2.A$1057.2A$1050.A$1049.A.A
$1049.A.A50.2C$1050.A51.2C13$1067.3A$1067.A$1068.A!
#C [[  X 555 Y 512  Z 2 STEP 20 STOP 9630 ]]
I had forgotten about this alternate format with relative lane numbers. It still seems pretty nice. It will make it possible to string together sub-recipes without any changes to most of the numbers. Just the first number has to change from "E+0" to whatever the correct relative lane number is.

Of course, with the current format it will always be possible to normalize a recipe so the first entry is "E+0". Maybe it would be worth adding another letter to the relative-lane format, so that that first E+0 data point could be dropped, to be replaced by a pointer to the type of target that the recipe should be aimed at: block-9qd, block+9qd, blinkerV{n}qd, blinkerH{n}qd, etc. The target list might get fairly large eventually.

(P2 targets will need to have two separate entries in the library for each possible location, because otherwise the recipe can't be normalized.)

-----------------------------------------------------

Then... at the end of each recipe in the library, if a new target has been left behind, we should include the target type and its location relative to the starting target. Maybe just pile all those details into the name at the front?

I think I might go back to the old quarter-diagonal lane measurement system, though. Then the first item in each recipe list can be an odd number that tells the compiler how to hit the target, and all following relative lane numbers will be even.

To string multiple recipes together without having to adjust any lane numbers, we just need to add a new letter that tells the compiler to move its reference lane without firing a glider. The lane shift at the end would again be an odd number, so as to point to a cell (the upper left corner of the next target) rather than a glider lane:

block@-8,7 targetin=block targetout=block@12,5: E+9 E+20 M-15

Then a compiler could read "E+9 E+20 M-15 E+9 E+20 M-15 E+9 E+20 M-15" to produce an oblique line of blocks, for example.

Might even be worthwhile to allow aliases to make the recipes easier to spot: "block@-8,7 block@-8,7 block@-8,7" would be one way to represent the above recipe... not very useful yet, but much more fun if we allow recursive definitions. Eventually we might end up with nice short high-level recipes, like "snark1 blockmove20,-31 snark2 blockmove11,30 semisnark1".

Comments, suggestions, other ideas? I might finally start trying to put together a slow-salvo compiler script along these general lines, if I can't convince someone else to do it for me... but that will be a separate thread!

-----------------------------------------------------

Back to this thread: I'm also interested in ideas for optimizing freeze-dried slow salvos. There are a lot of possible ways to use constellations that are more expensive in still-life count, but cheaper to construct (from one direction or another, with monochromatic or polychromatic slow salvos, slow pairs, or whatever -- different one-time turners and splitters for each case, presumably.)

It might also be cheaper, and take up less space, to set up constellations where a glider bounces back and forth as it works its way up a chain, shooting output gliders off to the side. The above recipes were designed with that idea in mind -- but each one could also be implemented as two separate freeze-dried constellations, since the two halves of the construction mostly don't interact with each other.

-- Way too many possibilities. The patterns above seem like a good placeholder to give the general idea, until a specific project comes along and it's clear what needs to be optimized.

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

Re: Freeze-Dried Slow Salvos

Post by simsim314 » September 2nd, 2016, 5:36 am

For starters here is a script that gives some solution using this relative lane notation:

Code: Select all

import golly as g 

gld_inv = g.parse("3o$o$bo!")

def IsGldInv(x, y):
	return IsPat(x, y, gld_inv)
	
def IsPat(x, y, pat):
	for i in xrange(0, len(pat), 2):
		if g.getcell(x + pat[i], y + pat[i + 1]) == 0:
			return False
			
	return True
	
def FindAllGldInv():
	result = [] 
	
	for gen in xrange(4):
		
		pat = g.getcells(g.getrect())
	
		for i in xrange(0, len(pat), 2):
			if IsGldInv(pat[i], pat[i + 1]):
				result.append(Glider(-1, -1, pat[i], pat[i + 1], gen))
		
		g.run(1)
		
	return result

class Glider:
	def __init__(self, dirx = 1, diry = 1, x = 0, y = 0, gen = 0):
		self.dirx = dirx
		self.diry = diry
		self.x = x
		self.y = y
		self.gen = gen

		#define lane and time by y and gen at X = 0 
		
		self.lane = y - diry * dirx * x 
		self.time = gen - dirx * 4 * x 
		
	def Copy(self, other):
		self.dirx = other.dirx
		self.diry = other.diry
		self.x = other.x
		self.y = other.y
		self.lane = other.lane
		self.time = other.time
		self.t = other.t
		
	def XY(self):
		return (x, y)
	
	def XYAt(self, t):
		return ((t - self.time) / 4 * self.dirx, self.lane + (t - self.time)/4 * self.diry * self.dirx)
	
	def __str__(self):
		return str((self.x, self.y, self.dirx, self.diry, self.lane, self.time, self.t))
	
	def Place(self):
		input_gld = g.parse("bo$2bo$3o!", -1, -1)
		input_gld = g.evolve(input_gld, self.gen %4)
		input_gld = g.transform(input_gld, 0, 0, self.dirx, 0, 0, self.diry)
		g.putcells(input_gld, self.x, self.y)
	
	def Evolve(self, d):
		self.x += self.dirx * d
		self.y += self.diry * d
		self.gen += 4 * d

		
class DVar:
	def __init__(self, dx, dy, x0, y0, x1, y1, gen):
		self.mx = x1 - x0
		self.nx = x0
		self.my = y1 - y0
		self.ny = y0
		
		self.gen = gen
		self.dirx = dx
		self.diry = dy 
		
	def Output(self, glider, d):
		
		mx = glider.dirx * self.dirx
		my = glider.diry * self.diry
		
		x = glider.x + glider.dirx * (self.mx * d + self.nx)
		y = glider.y + glider.diry * (self.my * d + self.ny)
		gen = glider.gen + self.gen 
		
		gld = Glider(mx, my, x, y, gen)
		gld.Evolve(d)
		
		return gld

class GliderOp:
	def __init__(self, pat, outputVars):
		self.pat = pat 
		self.outputVars = outputVars
	
	def AddVar(self, dvar):
		self.outputVars.append(dvar)
	
	def Var(self, idx):
		return self.outputVars[idx]
	
	def Place(self, glider, d):
		x = glider.x + d * glider.dirx
		y = glider.y + d * glider.diry
		
		pat = g.transform(self.pat, 0, 0, glider.dirx, 0, 0, glider.diry)
		
		pat = g.evolve(pat, glider.gen % 2)
		
		g.putcells(pat, x, y)
		
splitter = GliderOp(g.parse("2bo$bobo$2bobo$3b2o3$b2o$obo$bo!", 2, -1), [])
splitter.AddVar(DVar(1, 1, 6, 6, 6, 6, 21))
splitter.AddVar(DVar(-1, 1, 0, 0, 2, 0, 19))

Ref90 = []
Ref90.append(GliderOp(g.parse("10bo$9bobo$10bo2$2o$2o!",-6,1), [DVar(1, -1,-5,-2,-5,0,56)]))
Ref90.append(GliderOp(g.parse("5bo$4bobo$5bo2$2o$2o!"), [DVar(1, -1,11,-4,11,-2,33)]))
Ref90.append(GliderOp(g.parse("3$2b2o$bobo$2bo!"), [DVar(1, -1,1,-3,1,-1,32)]))
Ref90.append(GliderOp(g.parse("bo$obo$bobo$2b2o!", -1, 4), [DVar(1, -1,2,0,2,2,27)]))

ref90R = GliderOp(g.parse("bo$obo$2o!", 3, 2), [DVar(-1, 1, -1, -1, 1, -1, 24)])
blck = g.parse("2o$2o!",5, 0)

def FindTarget(tlane, ttime, glider):
	
	for ref in Ref90:
		
		gld = ref.Var(0).Output(glider, 0)
		dl = tlane - gld.lane
		dt = ttime - gld.time
		
		if dt % 2 == 0 and dl % 2 == 0:
			d1 = dl / 2
			
			return (d1, ref)

def PlaceRefR(tlane, ttime, gld):			
	ref90R.Place(gld, 0)
	gld = ref90R.Var(0).Output(gld, 0)
	d1, ref = FindTarget(tlane, ttime, gld)
	ref.Place(gld, d1)
	gld = ref.Var(0).Output(gld, d1)
		
def PlaceSplitter(tlane, ttime, gld):			
	splitter.Place(gld, 0)
	gld1 = splitter.Var(0).Output(gld, 0)
	gld = splitter.Var(1).Output(gld, 0)
	d1, ref = FindTarget(tlane, ttime, gld)
	ref.Place(gld, d1)
	g.show(str(d1))
	return gld1
	
#inStr = "E+0 E+10 E-34 E+22 E-32 E+35 E-32 E+32 E-35 E+43 E-51 E+48 O-36 O+32 E-48 E+50 E-23 E+21 E-30 E+30 E-27 O+27 E-20 E+33 E-32 O+16 O-25 E+38 E-30 E+19 O-32 E+25 E-31 E+29 E-17 E+34 E-23 E+23 E-25 E+35 E-46 E+16 E-16 E+19 E-22 E+30 E-37 E+25 E-17 E+22 E+0 E+0 E+0"
inStr = g.getstring("Please Enter Slow Salvo recipe", "E+0 E+10 E-34")

spStr = inStr.split(' ')
salvo = [] 
min = 0 
sum = 0 

for s in spStr:
	isEven = 0
	if 'O' in s:
		isEven = 1
		
	s = s.replace('E', '').replace('O','')
	val = int(s)
	sum += val
	salvo.append((isEven, sum))
	
	if sum < min: 
		min = sum
		
gld = Glider()
gld.Place()
D = 8
GenEv = 20
g.show(str(-min + D))
g.putcells(blck, min - D)

for i in xrange(len(salvo)):
	t, lane = salvo[i]
	
	if i < len(salvo) - 1:
		gld = PlaceSplitter(-min + D + lane, t, gld)
		gld.Evolve(GenEv)
	else: 
		PlaceRefR(-min + D + lane, t, gld)
As for optimization ideas:

1. One simple idea is to make the salvo tight i.e. step at a distance necessary for the slow salvo interaction to occur and for the reflectors to work, and not more than that.

2. More interesting idea of optimization is parallel slow salvo. Something along these lines:

Code: Select all

x = 121, y = 98, rule = LifeHistory
10$46.C3.C$47.C.C.C$45.3C2.C.C$51.2C3$49.2C$48.C.C$49.C8$28.C$27.C.C
4.C$28.2C3.C.C$32.C.C$32.2C6$76.C$75.C.C$76.C.C$77.2C3$75.2C$74.C.C$
17.C57.C$16.C.C$15.C.C$15.2C3$56.C$55.C.C4.C$56.2C3.C.C$60.C.C$60.2C
8$102.C$101.C.C$102.C.C$103.2C3$101.2C$100.C.C$101.C7$29.C$28.C.C47.C
$29.C47.C.C$78.C$38.2C$38.2C42.2C$82.2C!

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

Re: Freeze-Dried Slow Salvos

Post by dvgrn » September 4th, 2016, 9:39 pm

simsim314 wrote:1. One simple idea is to make the salvo tight i.e. step at a distance necessary for the slow salvo interaction to occur and for the reflectors to work, and not more than that.
That's easy enough. A brute-force addendum to your script will do that, and the results are quite impressive:

Code: Select all

x = 440, y = 421, rule = B3/S23
45bo3bo$2o44bobobo$2o42b3o2bobo$50b2o3$48b2o5bo$47bobo4bobo$48bo6bobo$
56b2o3$54b2o$53bobo$54bo8$71bo$70bobo$71bobo$72b2o3$70b2o5bo$21bo47bob
o4bobo$20bobo47bo6bobo$19bobo56b2o$19b2o$82bo$76b2o3bobo$75bobo4bobo$
76bo6b2o3$55bo25b2o5bo$54bobo23bobo4bobo$17b2o34bobo25bo6bobo$17bobo
33b2o34b2o$18bo2$71bo15b2o$70bobo13bobo6bo$69bobo15bo6bobo$69b2o24bobo
$96b2o2$100bo$94b2o3bobo$80bo12bobo4bobo$79bobo12bo6b2o$80bo$105bo$45b
2o37b2o13b2o3bobo$45bobo36b2o12bobo4bobo$46bo52bo6b2o3$104b2o5bo$103bo
bo4bobo$104bo6bobo$112b2o2$116bo$94bo15b2o3bobo$93bobo13bobo4bobo$51bo
40bobo15bo6b2o$50bobo39b2o$51bo$115b2o5bo$60b2o52bobo4bobo$60b2o47bo5b
o6bobo$108bobo12b2o$107bobo$107b2o$121b2o5bo$120bobo4bobo$121bo6bobo$
63bo65b2o$62bobo$63bo$127b2o$72b2o52bobo6bo$72b2o53bo6bobo$135bobo$
136b2o3$134b2o$133bobo$110b2o22bo$110bobo$111bo$70bo$69bobo$70bo77bo$
147bobo$79b2o67bobo$79b2o68b2o3$143bo3b2o5bo$86b2o54bobobobo4bobo$86bo
bo52bobo3bo6bobo$87bo53b2o12b2o3$153b2o$152bobo$153bo$163bo$162bobo$
106bo56bobo$105bobo56b2o$104bobo$104b2o62bo$162b2o3bobo$161bobo4bobo$
162bo6b2o3$167b2o$166bobo$142bo24bo$141bobo$142bo2$146b2o$146b2o5$119b
2o$119bobo$120bo3$191bo$190bobo$191bobo$192b2o3$190b2o5bo$189bobo4bobo
$134b2o54bo6bobo$134bobo61b2o$135bo2$196b2o5bo$195bobo4bobo$196bo6bobo
$177bo26b2o$176bobo$175bobo30bo$175b2o25b2o3bobo$201bobo4bobo$202bo6b
2o2$185bo27bo$184bobo20b2o3bobo$185bo20bobo4bobo$207bo6b2o$189b2o$189b
2o$212b2o5bo$211bobo4bobo$212bo6bobo$220b2o3$218b2o5bo$217bobo4bobo$
218bo6bobo$163b2o61b2o$163bobo$164bo$224b2o$223bobo$194bo29bo$193bobo$
192bobo40bo$192b2o40bobo$235bobo$179bo56b2o$178bobo22bo$177bobo22bobo
35bo$177b2o24bo30b2o3bobo$233bobo4bobo$207b2o25bo6b2o$207b2o2$239b2o$
238bobo6bo$239bo6bobo$247bobo$248b2o2$252bo$246b2o3bobo$245bobo4bobo$
246bo6b2o2$175bo29bo14b2o$174bobo27bobo13bobo28b2o5bo$175bo29bo15bo28b
obo4bobo$251bo6bobo$184b2o23b2o48b2o$184b2o23b2o$263bo$257b2o3bobo$
256bobo4bobo$257bo6b2o3$262b2o$261bobo$262bo$233bo38bo$232bobo36bobo$
231bobo38bobo$231b2o40b2o3$242bo28b2o$241bobo26bobo$242bo28bo2$251b2o$
208b2o41b2o$208bobo$209bo4$221bo67bo$220bobo65bobo$221bo67bobo$290b2o$
230b2o45bo$230b2o44bobo15bo$277bo10b2o3bobo$287bobo4bobo$281b2o5bo6b2o
$281b2o$242b2o$242bobo48b2o5bo$243bo48bobo4bobo$293bo6bobo$301b2o2$
305bo$299b2o3bobo$298bobo4bobo$299bo6b2o2$282bo$281bobo20b2o$282bo20bo
bo$304bo$286b2o$286b2o5$265b2o$265bobo$266bo3$325bo$324bobo$325bobo$
326b2o3$324b2o5bo$323bobo4bobo$324bo6bobo$332b2o2$336bo$330b2o3bobo$
329bobo4bobo$330bo6b2o$264bo$263bobo$264bo70b2o5bo$334bobo4bobo$273b2o
60bo6bobo$273b2o68b2o2$304bo$303bobo35b2o5bo$302bobo35bobo4bobo$302b2o
37bo6bobo$349b2o2$353bo$347b2o3bobo$346bobo4bobo$347bo6b2o$316bo14bo$
315bobo12bobo$314bobo14bo20b2o$314b2o35bobo$335b2o15bo$335b2o4$290bo
75bo$289bobo73bobo$290bo75bobo$367b2o$299b2o$299b2o70bo$365b2o3bobo$
364bobo4bobo$365bo6b2o$349bo$348bobo25bo$349bo20b2o3bobo$322bo46bobo4b
obo$321bobo29b2o15bo6b2o$322bo30b2o2$296bo34b2o42b2o5bo$295bobo33b2o
41bobo4bobo$296bo78bo6bobo$383b2o$305b2o$305b2o$381b2o5bo$380bobo4bobo
$363bo17bo6bobo$362bobo24b2o$361bobo12bo$361b2o12bobo15bo$376bo10b2o3b
obo$386bobo4bobo$380b2o5bo6b2o$342b2o36b2o$342bobo$343bo48b2o5bo$391bo
bo4bobo$392bo6bobo$400b2o2$404bo$398b2o3bobo$397bobo4bobo$383bo14bo6b
2o$382bobo$383bo$403b2o$387b2o13bobo$349b2o36b2o14bo$349bobo$350bo3$
366b2o$366bobo$367bo3$422bo$421bobo$422bobo$423b2o3$421b2o5bo$420bobo
4bobo$421bo6bobo$371bo57b2o$370bobo$371bo$427b2o$380b2o44bobo$380b2o
45bo5$395bo42bo$394bobo40bobo$395bo41b2o2$399b2o$399b2o9$395bo$394bobo
$395bo2$404b2o$404b2o4$404bo$403bobo$404bo2$413b2o$413b2o!
#C [[ AUTOFIT STEP 8 STOP 3250 ]]
Here's a revised draft script. Haven't done very well at making my additions readable yet, though... and I'm not sure, but it might be slightly faster if the trial patterns were kept in cell lists and tested with g.evolve(), instead of being dropped into the Golly universe and tested with g.run().

Code: Select all

import golly as g 

LONG_ENOUGH = 16384
gld_inv = g.parse("3o$o$bo!")

def IsGldInv(x, y):
   return IsPat(x, y, gld_inv)
   
def IsPat(x, y, pat):
   for i in xrange(0, len(pat), 2):
      if g.getcell(x + pat[i], y + pat[i + 1]) == 0:
         return False
         
   return True
   
def FindAllGldInv():
   result = [] 
   
   for gen in xrange(4):
      
      pat = g.getcells(g.getrect())
   
      for i in xrange(0, len(pat), 2):
         if IsGldInv(pat[i], pat[i + 1]):
            result.append(Glider(-1, -1, pat[i], pat[i + 1], gen))
      
      g.run(1)
      
   return result

class Glider:
   def __init__(self, dirx = 1, diry = 1, x = 0, y = 0, gen = 0):
      self.dirx = dirx
      self.diry = diry
      self.x = x
      self.y = y
      self.gen = gen

      #define lane and time by y and gen at X = 0 
      
      self.lane = y - diry * dirx * x 
      self.time = gen - dirx * 4 * x 
      
   def Copy(self, other):
      self.dirx = other.dirx
      self.diry = other.diry
      self.x = other.x
      self.y = other.y
      self.lane = other.lane
      self.time = other.time
      self.t = other.t
      
   def XY(self):
      return (x, y)
   
   def XYAt(self, t):
      return ((t - self.time) / 4 * self.dirx, self.lane + (t - self.time)/4 * self.diry * self.dirx)
   
   def __str__(self):
      return str((self.x, self.y, self.dirx, self.diry, self.lane, self.time, self.t))
   
   def Place(self):
      input_gld = g.parse("bo$2bo$3o!", -1, -1)
      input_gld = g.evolve(input_gld, self.gen %4)
      input_gld = g.transform(input_gld, 0, 0, self.dirx, 0, 0, self.diry)
      g.putcells(input_gld, self.x, self.y)
   
   def Evolve(self, d):
      self.x += self.dirx * d
      self.y += self.diry * d
      self.gen += 4 * d

      
class DVar:
   def __init__(self, dx, dy, x0, y0, x1, y1, gen):
      self.mx = x1 - x0
      self.nx = x0
      self.my = y1 - y0
      self.ny = y0
      
      self.gen = gen
      self.dirx = dx
      self.diry = dy 
      
   def Output(self, glider, d):
      
      mx = glider.dirx * self.dirx
      my = glider.diry * self.diry
      
      x = glider.x + glider.dirx * (self.mx * d + self.nx)
      y = glider.y + glider.diry * (self.my * d + self.ny)
      gen = glider.gen + self.gen 
      
      gld = Glider(mx, my, x, y, gen)
      gld.Evolve(d)
      
      return gld

class GliderOp:
   def __init__(self, pat, outputVars):
      self.pat = pat 
      self.outputVars = outputVars
   
   def AddVar(self, dvar):
      self.outputVars.append(dvar)
   
   def Var(self, idx):
      return self.outputVars[idx]
   
   def Place(self, glider, d):
      x = glider.x + d * glider.dirx
      y = glider.y + d * glider.diry
      
      pat = g.transform(self.pat, 0, 0, glider.dirx, 0, 0, glider.diry)
      
      pat = g.evolve(pat, glider.gen % 2)
      
      g.putcells(pat, x, y)

def FindTarget(tlane, ttime, glider):
   
   for ref in Ref90:
      
      gld = ref.Var(0).Output(glider, 0)
      dl = tlane - gld.lane
      dt = ttime - gld.time
      
      if dt % 2 == 0 and dl % 2 == 0:
         d1 = dl / 2
         
         return (d1, ref)

def PlaceRefR(tlane, ttime, gld):         
   ref90R.Place(gld, 0)
   gld = ref90R.Var(0).Output(gld, 0)
   d1, ref = FindTarget(tlane, ttime, gld)
   ref.Place(gld, d1)
   gld = ref.Var(0).Output(gld, d1)
      
def PlaceSplitter(tlane, ttime, gld):         
   splitter.Place(gld, 0)
   gld1 = splitter.Var(0).Output(gld, 0)
   gld = splitter.Var(1).Output(gld, 0)
   d1, ref = FindTarget(tlane, ttime, gld)
   ref.Place(gld, d1)
   return gld1

def BuildAndTestConstellation(salvo, D, delta, GenEvList):
   g.new("Test")
   BuildConstellation(salvo, D, GenEvList)
   g.run(LONG_ENOUGH+delta)
   h = g.hash(g.getrect())
   return h

def BuildConstellation(salvo, D, GenEvList):
   gld = Glider()
   gld.Place()
   g.putcells(blck, min - D)
         
   for i in xrange(len(salvo)):
      t, lane = salvo[i]
      
      if i < len(salvo) - 1:
         GenEv=GenEvList[i]
         gld = PlaceSplitter(-min + D + lane, t, gld)
         gld.Evolve(GenEv)
      else: 
         PlaceRefR(-min + D + lane, t, gld)
         
splitter = GliderOp(g.parse("2bo$bobo$2bobo$3b2o3$b2o$obo$bo!", 2, -1), [])
splitter.AddVar(DVar(1, 1, 6, 6, 6, 6, 21))
splitter.AddVar(DVar(-1, 1, 0, 0, 2, 0, 19))

Ref90 = []
Ref90.append(GliderOp(g.parse("10bo$9bobo$10bo2$2o$2o!",-6,1), [DVar(1, -1,-5,-2,-5,0,56)]))
Ref90.append(GliderOp(g.parse("5bo$4bobo$5bo2$2o$2o!"), [DVar(1, -1,11,-4,11,-2,33)]))
Ref90.append(GliderOp(g.parse("3$2b2o$bobo$2bo!"), [DVar(1, -1,1,-3,1,-1,32)]))
Ref90.append(GliderOp(g.parse("bo$obo$bobo$2b2o!", -1, 4), [DVar(1, -1,2,0,2,2,27)]))

ref90R = GliderOp(g.parse("bo$obo$2o!", 3, 2), [DVar(-1, 1, -1, -1, 1, -1, 24)])
blck = g.parse("2o$2o!",5, 0)
      
inStr = g.getstring("Please Enter Slow Salvo recipe", "E+0 E+10 E-34 E+22 E-32 E+35 E-32 E+32 E-35 E+43 E-51 E+48 O-36 O+32 E-48 E+50 E-23 E+21 E-30 E+30 E-27 O+27 E-20 E+33 E-32 O+16 O-25 E+38 E-30 E+19 O-32 E+25 E-31 E+29 E-17 E+34 E-23 E+23 E-25 E+35 E-46 E+16 E-16 E+19 E-22 E+30 E-37 E+25 E-17 E+22 E+0 E+0 E+0")

spStr = inStr.split(' ')
salvo = [] 
min = 0 
sum = 0 

g.setrule("Life")
g.new("Freeze-dried slow salvo")
for s in spStr:
   isEven = 0
   if 'O' in s:
      isEven = 1
      
   s = s.replace('E', '').replace('O','')
   val = int(s)
   sum += val
   salvo.append((isEven, sum))
   
   if sum < min: 
      min = sum
      
gld = Glider()
gld.Place()
D = 8
delta = 0
GenEvList = [20]*(len(salvo)-1)
bestknown=[salvo, D, delta, GenEvList]
knowngoodhash=BuildAndTestConstellation(*bestknown)

# optimize distance between splitters and turners
while True:
  D -= 2  #  D-=1 gives different hashes alternately, so it's a little harder to test reliably
  #TODO: try the next lower D value, look for hash matches in a wide range around LONG_ENOUGH.
  #      Or use some other method of collecting the hash,
  #         such as ignoring output objects outside of the initial box plus some margin
  delta -= 8
  newhash=BuildAndTestConstellation(salvo, D, delta, GenEvList)
  if newhash!=knowngoodhash: break
  bestknown[1], bestknown[2] = D, delta

salvo, D, delta, GenEvList = bestknown

# optimize distance between successive splitter+turner constellations 
for i in xrange(len(GenEvList)):
   salvo, D, delta, GenEvList = bestknown
   newlist = list(GenEvList)
   binary_max = newlist[i]
   base_offset = binary_max
   binary_min = -5 # hey, you never know
   delta_base = delta
   while True:
      newlist[i]=binary_min + int((binary_max-binary_min)/2)
#      g.note(str([binary_min, newlist[i], binary_max]))
      g.show(str(newlist).replace(" ",""))
      delta = delta_base - 8*(base_offset-newlist[i]) # magic number 8 = 1fd smaller distance for a glider -- there and back again
      newhash=BuildAndTestConstellation(salvo, D, delta, newlist)
      # g.show("Testing with i= " + str(i) + "dist=" + str(newlist[i]) + " known-good hash " + str(knowngoodhash) +" vs. new hash " + str(newhash))
      if newhash == knowngoodhash:
         binary_max = newlist[i]
         GenEvList[i], bestknown[2] = newlist[i], delta
      else:
         binary_min = newlist[i]+1
      if binary_min == binary_max: break
   delta=bestknown[2] # don't take the last

g.new("Tightest constellation")
BuildConstellation(bestknown[0],bestknown[1],bestknown[3])
Also, I've added a TODO comment to the effect that it might be possible sometimes to get the turners one lane closer to the splitters. But it needs a better hash check, because the turners all end up being different and so the timing of the output gets a little unpredictable.
simsim314 wrote:2. More interesting idea of optimization is parallel slow salvo. Something along these lines...
Yes, that was part of those loaf2GtoG and semi-Snark experiments. Each recipe has two almost-independent sets of slow gliders. In general, after a single initial target is split into several well-separated objects, slow-salvo construction can very often be massively parallel.

I think the next optimizations that I'm most interested in are

3. Build a library of near-optimal splitters and turners based on the type of slow salvo that will be used to construct them (different entries for P1 or P2, monochromatic or polychromatic, monophase or polyphase, etc.)

4. Also collect different splitters for the library, based on what direction the construction gliders will be coming from. For example, the true-knightship diamond Geminoid will probably have to construct its freeze-dried slow salvos either from the NE or the SW (relative to how this script produces its constellation). Construction from the SE and triggering from the NW might also be useful sometimes.

Post Reply