dvgrn wrote: December 2nd, 2024, 7:07 pm
Once the current code has accepted a pattern as a valid gun and has figured out that its period is P,
Unfortunately, the bug sometimes creates an invalid RLE for what it thinks is the gun (although the period calculation is always correct), such as in this case:
Vort wrote: July 1st, 2024, 12:30 pm
[gun_1650 as it appeared in Catagolue at the time:]
Code:
Select all
#C [[ GRID MAXGRIDSIZE 14 THEME Catagolue ]]
#CSYNTH gun_1650 costs 2915 cells.
#C period 1650 fullperiod 1650 bbox 53 by 55
#CLL state-numbering golly
x = 53, y = 55, rule = LifeHistory
2B2A4B2A17BA2BA3BA2BA15B$27BA2BA4BA2BA14B$28B5A5BA14B$31BA3BAB2A
14B$44BA2BABA3B$30BA5BA5B2AB3A2BA2B$28B3A12BABA3BA3B$44BAB2ABA3B$
28B2A7B3A7B2A4B$52BA$33BABA16BA$26BA2BABA3BA17B$27BA4BAB2A17B$27BA
4BA20B$29B2A22B$53B$53B$44B2A7B$44B2A7B$53B$20B2A31B$20B2A12BA18B$
33BABA17B$33BABA17B$34BA18B$11BA41B$10BABA40B$9BABA41B$9B2A42B$6B.
14BA31B$4B3.8BA4BABA30B$.B6.7BA4BABA30B$B6.8BA5BA31B$B5.47B$3B3.
47B$3B4.46B$3B3.47B$2B3.48B$2B4.47B$2B6.3B5.12BA24B$B14.12BABA23B$
4B11.12BABA23B$3B2A11.12BA24B$3B2A10.BA36B$4B11.ABA35B$5B11.2A32BA
2B$7B11.2B3A27BA2B$10B2.2B3.33BA2B$40B.12B$53B$16B2A35B$16B2A35B$.
52B$8.4B.25B4.7B2A2B$9.4B4.B2.12B10.7B2A2B!
Vort wrote: July 2nd, 2024, 3:30 am
In gun_1650 case, Catagolue detects bounding box of 53x55 and then crops gun in this state:
Code:
Select all
x = 52, y = 57, rule = B3/S23
31bo$30bobo$30bobo$6b2o5b2o2b2ob2o7b2ob2o2b2o$6bo2b2obo2bo2bob2o7bo5bo
2bo$7b2obob2ob2obo11b3o4bo2bo$3b2o3bobo2bobo2bob2o10bo2bobob2o7b2o$o2b
o2bo4bo3bob2o2bo11b2o2bo10bo$3o2b2obo3bobobo2bo16b2o7b2obo$3b2o2b5o6b
2o22b2o3bo$2bo2bo6b2o4bo23bo$3b2o8bo16b2o$29bo2bo9bo2bo$30b2o10bobo$9b
2o34bo2b2o$2o6bo2bo6b2o18bobo5bo2bo$bo7b2o7bo18b3o2bob2ob2o$bobo12bobo
17bob2o4bo$2b2o12b2o7b2o9b2o5bobob2o$20b2o2bobo17b2ob2o$21bo2bo$19bo2b
3o$19b3o8bo8b2o2bo$22bo5b2o7bo5bo3bobo$21b2o6b2o12bo2b2o$36bo6b3o4bo$
16b2o16b3ob4obobob2o2bo$16bobo14bo4bobo4bo2bob2o$8bo7bo17b5obob2ob2obo
$7bobo30bobo2bo2bob2o$7bobo26b3obobobo2b2ob2o$8bo22b2o3bo2bo3bo$12b2o
17bobo3b2o$12bobo18bo$14bo7b2o9b2o$14b2o6bo2bo$22bo2bo$22bo2$21b2o3bo$
17b2o3bob2o2b2o$17bo2bobo6bo$19b2ob7o$21bo$21bob4o$22b2o2bo2$33bobo$
33bo3bo$23b2o12bo5b2o$23b2o8bo4bo4b2o$37bo$33bo3bo$23bo9bobo$23b2o2$
22b2o!
This results in the loss of the bottom two cells and a subsequent explosion.
Perhaps it would be helpful to know exactly what idgun.py is doing and exactly why it fails to get the correct bounding box. To that end, I somewhat quickly read over the script and gave excessive annotations of what I think identify_gun() is doing at each step:
Code: Select all
# rle: the input rle of the gun to be tested.
# The input rle is always in 2-state b3s23.
# lt4: a 4-layer lifetree. This is necessary for
# representing the pattern in LifeHistory.
def identify_gun(rle, lt4):
# Create a new pattern, a, based on the input rle, and
# exit if the input pattern is empty.
a = lt4.pattern(rle)
if a.empty():
return []
# Advance pattern a by 524288 generations. This is to remove dying
# sparks that aren't actually part of the gun before analysis.
a = a[524288]
# Create a new empty LifeHistory pattern, x, and paste pattern a into x.
x = lt4.pattern('', 'LifeHistory')
x += a
# Advance x by 524288 generations. This gives a LifeHistory
# view of the gun with a *very* long stream of output gliders.
x = x[524288]
# Perform a population check to make sure the results make sense.
# This is not the source of the bug, so it's not important to us.
p = x.population
if (p < 1000000):
return None
if (p > 1500000):
return None
# Get the envelope (all cells that were ever alive) of x.
# This assignment is temporary. envelope will soon be
# reassigned to be the envelope of x[256] instead.
envelope = x.layers()[1]
# Get only the live cells of x[8] (note: x[8] is the pattern
# obtained from advancing x by 8 generations).
livecells = x[8].layers()[0]
# If the gun is valid, y should be just the front-most glider in the output stream
y = livecells - envelope
# Get the envelope of the pattern obtained by advancing x by 256 generations.
# Note that x has not changed, so envelope is now *not* the envelope of x.
envelope = x[256].layers()[1]
# Check if y is just a glider (if not, the "gun" is invalid).
if (y.population != 5):
return None
z = lt4.pattern("", "b3s23")
z += y
if (z.apgcode != 'xq4_153'):
return None
# Note that z is just a glider in ordinary b3s23, but its
# position in the plane matches the front-most glider of x[8]
# (note: x[8] is the pattern obtained from advancing x by 8
# generations). That is, z is the front-most glider of the
# input pattern after that pattern has been run for
# 524288*2 + 8 = 1048584 generations.
# Create a new LifeHistory pattern, w.
w = lt4.pattern("", "LifeHistory")
# First set w to be the glider z "reversed" by 2097152 generations
# (i.e., moved backwards by 2097152 / 4 = 524288 full diagonals).
w += z[-2097152]
# Now advance w (which is just a single glider in LifeHistory) by
# 2 * 2097152 = 4194304 generations.
w = w[4194304]
# Note that we have now advanced w by far more generations than we
# initially reversed z by when creating w. That is, the glider in
# w has gone much further beyond the position of the glider in z.
# Band is the envelope of w. It's basically just an extremely
# long strip of history cells covering the output glider stream
# but also extending backwards out of the back of the gun.
band = w.layers()[1]
# Create pbb, which is just the envelope of x[256] with all the cells
# of band removed. Essentially, this is the envelope of the gun,
# except all cells along the output glider stream (both forwards *and*
# backwards) are removed.
pbb = envelope - band
# Unfortunately, removing band from envelope means that pbb does not
# contain any history cells along the output glider stream, even if
# those history cells represent parts of the gun that aren't part of
# the output glider stream. Cells removed from the back of the gun
# (i.e., on the edges opposite the direction of the output glider
# stream) are accounted for later, but cells removed from the front
# are never accounted for, causing the bug.
# r1 and r2 are really just used to determine the direction of the
# output glider stream.
r1 = z.getrect()
r2 = z[1024].getrect()
# Update pbb by pasting a copy of pbb 256 full diagonals in the
# opposite direction of the output glider stream. This is used
# to correct for the fact that (envelope - band) may have deleted
# some cells at the edges of the gun opposite of the direction
# of the output glider stream that are essential to calculating
# the bounding box of the gun. Unfortunately, it does *not*
# account for cells at the edges of the gun in the same direction
# as the output glider stream.
pbb += pbb(r1[0] - r2[0], r1[1] - r2[1])
# Set r to be a 4-element array where the elements represent
# r[0]: the x-coordinate of the upper left corner of pbb
# r[1]: the y-coordinate of the upper left corner of pbb
# r[2]: the width of pbb
# r[3]: the height of pbb
r = pbb.getrect()
if (len(r) != 4):
return None
# Trim the envelope of x to only the part covered by the bounding box of pbb.
# This is where the bug occurs, because pbb does not include the history cells
# of the dying sparks along the edges of the gun in the same direction as the
# output glider stream. This is the final assignment of envelope, which now
# represents what the program thinks is the exact envelope of the gun.
envelope = envelope[r[0] : r[0] + r[2], r[1] : r[1] + r[3]]
# Update r to give the bounding box of the trimmed envelope. This is the final
# assignment of r, and the (possibly incorrect) width and height of the gun
# reported by the script will be r[2] and r[3] respectively.
r = envelope.getrect()
# This next part just determines the period and stream period (i.e., pseudo period) of
# the gun. It might or might not be relevant for whatever fix we attempt for the bug.
# The variable "period" represents the stream period, while "multiple" represents the
# true period of the gun.
geater = lt4.pattern("bo$2bo$3o4$5b2o$5bo$6b3o$8bo!", "b3s23")
eater = z.replace(geater[:3, :3], geater[100], orientations='rotate4reflect', n_phases=2)
if (eater.population != 7):
return None
x += eater
x = x[128]
multiple = x.oscar(eventual_oscillator=False, maxexp=20)['period']
print('True period: %d' % multiple)
if (multiple > 100000):
print('Period too large')
return []
gun = lt4.pattern("", "b3s23")
gun += livecells
if ((gun - gun[multiple]).population > 0):
return None
salvo = gun[multiple] - gun
if salvo.population != 5:
y = z.destream(salvo)[1:-1]
y.append(y[-1])
print(y)
if (len(set(y)) != 1) or (sum(y) != multiple):
print('Warning: intermittent glider gun')
return []
period = y[-1]
else:
period = multiple
print('Stream period: %d' % period)
if (period > 10000):
print('Period too large')
return []
# From this point on, I will assume that the bug doesn't exist, and
# envelope truly represents the exact envelope of the gun. If we're
# in the bugged scenario, weird things can happen. For example, see
# https://conwaylife.com/forums/viewtopic.php?p=188842#p188842
# https://conwaylife.com/forums/viewtopic.php?p=188881#p188881
# The pattern "gun" was initialized above as the live cells of x[8],
# which is essentially the original input pattern advanced by
# 524288*2 + 8 = 1048584 generations.
# This for loop simply advances gun so that it doesn't contain an
# output glider intersecting the edge of envelope's bounding box.
# Once this is true, it trims gun to only be the cells within the
# bounding box of envelope. So after this loop finishes, the
# pattern "gun" will be a 2-state representation of the gun with
# no cells of any output gliders beyond the gun's bounding box.
for i in range(period):
h = gun[1]
g = gun & envelope
if (g[1] == (h & envelope)):
gun = g
break
gun = h
else:
print('Failure 1!')
return None
# This for loop advances gun until the generation just before the
# first output glider exits the bounding box of envelope. That is,
# it advances gun until it is in the generation matching the gun's
# canonical form.
for i in range(period):
h = gun[1]
if (h - envelope).population > 0:
break
gun = h
else:
print('Failure 2!')
return None
# Create a new LifeHistory pattern, thing, containing the canonical
# generation of the 2-state gun we found above.
thing = lt4.pattern("", "LifeHistory")
thing += gun
# Advance thing by the true period of the gun. Since thing is a
# LifeHistory pattern, this populates the history cells of the gun.
thing = thing[multiple]
# Trim thing to the bounding box of the gun found earlier. This
# removes the output glider stream generated by advancing thing
# by the true period of the gun.
thing = thing[r[0] : r[0] + r[2], r[1] : r[1] + r[3]]
# Move thing so that the upper left corner is at coordinate (0,0).
# This is now the final LifeHistory pattern representing the gun.
thing = thing(-r[0], -r[1])
# Generate RLE and report the gun for possible inclusion in the database.
res = '\n\n#CSYNTH gun_%d costs %d cells.\n#C period %d fullperiod %d bbox %d by %d\n' % (period, r[2] * r[3], period, multiple, r[2], r[3])
print(res)
res += thing.rle_string()
to_update = [(('gun_%d' % period), r[2] * r[3], res)]
if (period == multiple):
to_update.append((('guntrue_%d' % period), r[2] * r[3], res.replace('gun_', 'guntrue_')))
return to_update
I'll try to illustrate this with the above p1320 gun as an example (slightly simplified for brevity).
Suppose we give the following as input:
Code: Select all
x = 49, y = 43, rule = B3/S23
34b2o7bo$30b2obobo5b3o$19b2o9b2obo6bo$10bobo2bo2bob3o10b2o5b2o$9bob2o
2b4o4bo6b2obob2o$9bo10b2obo6bo2b2obo$7b2ob9o2bob3o5bobo2b2ob2o$8bobo5b
o8bo13b2o$7bo2bo2b2o8b2obo$6b4o3b4o3bo3bo18bobo$9bo5bo4bo3bo18b2obo$
17bo2b2obo22bo$18b2obo2bo16b5ob2o$bo17bobob2o16bo3bobo$obo16bobobo18bo
4bo$bo13b2o3bo2bo8b3o7b2o3b2o$14b3o4b2o8bo3bo6bo2b2o$13bob2o13bo5bo6b
2obo$12bobo15bo5bo7bobobo$12bo2bo14bo5bo7bo2b2o$13b2o16bo3bo7b2o$7b2o
23b3o$6bobo$6bo23b2o$3b2obo24bo$4bobob2o18b3o$4bobob2o18bo$3b2obo7b2o$
3bo2b4o3bo2bo7b2o$4b2o3bo4b2o8bobo$6b2o18bo3b2o3bo2bo3b2o$6bo19b2o2b5o
4b5o$8bo21b2o3bo2bo3b2o$7b2o2$13b2o$9b2o4b4o14b2o4b2o$9b2o2b2ob3o13bo
8bo$13bo17bo2bo4bo2bo$32bo8bo$29bo3b2o4b2o$30bo$28b3o!
Note that an extra tub is included that actually extends the bounding box. The purpose of this is to illustrate one of the features of the function, and I hope it will be clear why I included the tub by the end of this example. The correct bounding box of the above pattern is 49x43, but identify_gun() will erroneously calculate it as 49x41 by shaving two rows off the bottom.
identify_gun() essentially starts by converting the input pattern to LifeHistory and running it for 2^20 generations. It then detects the location of the front-most glider in the output glider stream by saving the envelope of the whole pattern (all cells that were ever alive), running the pattern another 8 generations, deleting the saved envelope, and finally removing the small number of remaining dead history cells (i.e., state 2 cells). This results in a single glider from the output glider stream that is extremely far from where the gun was.
Next, it uses this detected glider to generate a band of history cells along the output glider stream path that extends backwards out the back of the gun (note: this will intersect that extra tub I added). It does this by "reversing" the glider by 2^21 generations, converting it to LifeHistory, then advancing it for 2^22 generations. This is illustrated by the following pattern showing the original gun with the band highlighted:
Code: Select all
x = 73, y = 74, rule = LifeHistory
D2$2.D2$4.D2$4.4D$5.4D$6.4D$7.4D44.2A7.A$8.4D39.2A.A.A5.3A$9.4D27.2A
9.2A.A6.A$10.4D17.A.A2.A2.A.3A10.2A5.2A$11.4D15.A.2A2.4A4.A6.2A.A.2A$
12.4D14.A10.2A.A6.A2.2A.A$13.4D11.2A.9A2.A.3A5.A.A2.2A.2A$14.4D11.A.A
5.A8.A13.2A$15.4D9.A2.A2.2A8.2A.A$16.4D7.4A3.4A3.A3.A18.A.A$17.4D9.A
5.A4.A3.A18.2A.A$18.4D16.A2.2A.A22.A$19.4D16.2A.A2.A16.5A.2A$20.2DCD
16.A.A.2A16.A3.A.A$21.CDCD15.A.A.A18.A4.A$22.C3D10.2A3.A2.A8.3A7.2A3.
2A$23.4D8.3A4.2A8.A3.A6.A2.2A$24.4D6.A.2A13.A5.A6.2A.A$25.4D4.A.A15.A
5.A7.A.A.A$26.4D3.A2.A14.A5.A7.A2.2A$27.4D3.2A16.A3.A7.2A$28.2C2D21.
3A$27.A.C3D$27.A2.4D17.2A$24.2A.A3.4D17.A$25.A.A.2A.4D13.3A$25.A.A.2A
2.4D12.A$24.2A.A6.D2CD$24.A2.4A3.A2DCD6.2A$25.2A3.A4.AC3D5.A.A$27.2A
8.4D6.A3.2A3.A2.A3.2A$27.A10.4D5.2A2.5A4.5A$29.A9.4D8.2A3.A2.A3.2A$
28.2A10.4D$41.4D$34.2A6.4D$30.2A4.4A3.4D7.2A4.2A$30.2A2.2A.3A4.4D5.A
8.A$34.A10.4D3.A2.A4.A2.A$46.4D3.A8.A$47.3DC3.2A4.2A$48.3DC$49.3CD$
50.4D$51.4D$52.4D$53.4D$54.4D$55.4D$56.4D$57.4D$58.4D$59.4D$60.4D$61.
4D$62.4D$63.4D$64.4D$65.4D2$68.D2$70.D2$72.D!
It now takes the envelope calculated earlier and removes the cells along the band (called pbb within the function). This gives the following pattern (blue cells changed to red for better visibility):
Code: Select all
#C pattern pbb at line 41 of idgun.py
x = 46, y = 41, rule = LifeHistory
31.2D7.D$27.2D.D.D5.3D$16.2D9.2D.D6.D$7.D.D2.D2.D.3D10.3D4.2D$6.D.2D
2.4D4.D6.8D.3D$6.D9.3D.D6.D.3D.4D$4.2D.12D.3D5.10D$5.D.D2.D2.D.D2.2D
2.2D5.9D$3.3D.2D.6D2.6D7.2D3.D$2.6D2.8D.6D4.3D8.D.D$3.2D.2D4.D2.11D.
4D9.2D.D$14.2D.15D11.D$15.2D.D2.3D.8D5.5D.2D$16.D.D.2D3.8D4.2D3.D.D$
16.D.D.D5.8D3.6D.D$11.3D3.D2.D6.8D3.4D2.2D$11.4D3.2D5.10D3.3D.2D$10.D
.3D9.14D2.2D.D$9.D.D.2D8.15D3.D.D.D$9.D2.D2.2D5.15D4.D2.2D$10.2D3.3D
3.4D2.9D4.2D$15.3D.5D5.6D$3.D10.9D4.5D$3.D8.D.8D5.2D$2D.2D.D4.10D7.D$
.D.D.3D4.9D4.3D$.D.D.4D4.8D4.D$2D.D2.4D4.7D12.2D$D2.8D4.4D.3D8.6D$.2D
2.3D.3D4.3D.2D.D5.10D$3.2D6.2D4.D5.D3.14D$3.D7.2D10.2D.16D$5.D8.D12.
14D$4.2D9.D13.10D$12.3D16.6D$7.D2.5D18.2D$6.10D14.3D2.3D$6.10D12.12D$
7.5D2.D10.D.14D$7.3D16.14D$27.2D.2D4.2D!
Notice that both the tub and the sparky area caused by the glider filters are not included in this pattern, so the bounding box is only 46x41 instead of the desired 49x43. The next step fixes the missing tub issue, but there is no step that fixes the issue caused by the glider filters.
To fix the missing tub issue, or rather, any issues on the edges opposite of the direction of the output glider stream, it simply places an additional copy of the above pattern 256 full diagonals in the opposite direction of the output glider stream:
Code: Select all
#C pattern pbb at line 45 of idgun.py
x = 302, y = 297, rule = LifeHistory
31.2D7.D$27.2D.D.D5.3D$16.2D9.2D.D6.D$7.D.D2.D2.D.3D10.3D4.2D$6.D.2D
2.4D4.D6.8D.3D$6.D9.3D.D6.D.3D.4D$4.2D.12D.3D5.10D$5.D.D2.D2.D.D2.2D
2.2D5.9D$3.3D.2D.6D2.6D7.2D3.D$2.6D2.8D.6D4.3D8.D.D$3.2D.2D4.D2.11D.
4D9.2D.D$14.2D.15D11.D$15.2D.D2.3D.8D5.5D.2D$16.D.D.2D3.8D4.2D3.D.D$
16.D.D.D5.8D3.6D.D$11.3D3.D2.D6.8D3.4D2.2D$11.4D3.2D5.10D3.3D.2D$10.D
.3D9.14D2.2D.D$9.D.D.2D8.15D3.D.D.D$9.D2.D2.2D5.15D4.D2.2D$10.2D3.3D
3.4D2.9D4.2D$15.3D.5D5.6D$3.D10.9D4.5D$3.D8.D.8D5.2D$2D.2D.D4.10D7.D$
.D.D.3D4.9D4.3D$.D.D.4D4.8D4.D$2D.D2.4D4.7D12.2D$D2.8D4.4D.3D8.6D$.2D
2.3D.3D4.3D.2D.D5.10D$3.2D6.2D4.D5.D3.14D$3.D7.2D10.2D.16D$5.D8.D12.
14D$4.2D9.D13.10D$12.3D16.6D$7.D2.5D18.2D$6.10D14.3D2.3D$6.10D12.12D$
7.5D2.D10.D.14D$7.3D16.14D$27.2D.2D4.2D216$287.2D7.D$283.2D.D.D5.3D$
272.2D9.2D.D6.D$263.D.D2.D2.D.3D10.3D4.2D$262.D.2D2.4D4.D6.8D.3D$262.
D9.3D.D6.D.3D.4D$260.2D.12D.3D5.10D$261.D.D2.D2.D.D2.2D2.2D5.9D$259.
3D.2D.6D2.6D7.2D3.D$258.6D2.8D.6D4.3D8.D.D$259.2D.2D4.D2.11D.4D9.2D.D
$270.2D.15D11.D$271.2D.D2.3D.8D5.5D.2D$272.D.D.2D3.8D4.2D3.D.D$272.D.
D.D5.8D3.6D.D$267.3D3.D2.D6.8D3.4D2.2D$267.4D3.2D5.10D3.3D.2D$266.D.
3D9.14D2.2D.D$265.D.D.2D8.15D3.D.D.D$265.D2.D2.2D5.15D4.D2.2D$266.2D
3.3D3.4D2.9D4.2D$271.3D.5D5.6D$259.D10.9D4.5D$259.D8.D.8D5.2D$256.2D.
2D.D4.10D7.D$257.D.D.3D4.9D4.3D$257.D.D.4D4.8D4.D$256.2D.D2.4D4.7D12.
2D$256.D2.8D4.4D.3D8.6D$257.2D2.3D.3D4.3D.2D.D5.10D$259.2D6.2D4.D5.D
3.14D$259.D7.2D10.2D.16D$261.D8.D12.14D$260.2D9.D13.10D$268.3D16.6D$
263.D2.5D18.2D$262.10D14.3D2.3D$262.10D12.12D$263.5D2.D10.D.14D$263.
3D16.14D$283.2D.2D4.2D!
It will use this pattern to trim the original envelope of the gun. I think it might be helpful here to see the original gun envelope with the pattern pbb overlayed on top. Here the red cells are those only in pbb, the white cells are those only in the original envelope, and the gray cells are in both:
Code: Select all
x = 323, y = 339, rule = LifeHistory
31.2D7.D$27.2D.D.D5.3D$16.2D9.2D.D6.D$7.D.D2.D2.D.3D10.3D4.2D$6.D.2D
2.4D4.D6.8D.3D$6.D9.3D.D6.D.3D.4D$4.2D.12D.3D5.10D$5.D.D2.D2.D.D2.2D
2.2D5.9D$3.3D.2D.6D2.6D7.2D3.D$2.6D2.8D.6D4.3D8.D.D$3.2D.2D4.D2.11D.
4D9.2D.D$14.2D.15D11.D$15.2D.D2.3D.8D5.5D.2D$16.D.D.2D3.8D4.2D3.D.D$
16.D.D.D5.8D3.6D.D$11.3D3.D2.D6.8D3.4D2.2D$11.4D3.2D5.10D3.3D.2D$10.D
.3D9.14D2.2D.D$9.D.D.2D8.15D3.D.D.D$9.D2.D2.2D5.15D4.D2.2D$10.2D3.3D
3.4D2.9D4.2D$15.3D.5D5.6D$3.D10.9D4.5D$3.D8.D.8D5.2D$2D.2D.D4.10D7.D$
.D.D.3D4.9D4.3D$.D.D.4D4.8D4.D$2D.D2.4D4.7D12.2D$D2.8D4.4D.3D8.6D$.2D
2.3D.3D4.3D.2D.D5.10D$3.2D6.2D4.D5.D3.14D$3.D7.2D10.2D.16D$5.D8.D12.
14D$4.2D9.D13.10D$12.3D16.6D$7.D2.5D18.2D$6.10D14.3D2.3D$6.10D12.12D$
7.5D2.D10.D.14D$7.3D16.14D$27.2D.2D4.2D216$287.2F7.F$283.2F.F.F5.3F$
272.2F9.2F.F6.F$263.F.F2.F2.F.3F10.3F4.2F$262.F.2F2.4F4.F6.8F.3F$262.
F9.3F.F6.F.3F.4F$260.2F.12F.3F5.10F$261.F.F2.F2.F.F2.2F2.2F5.9F$259.
3F.2F.6F2.6F7.2F3.F$258.6F2.8F.6F4.3F8.F.F$259.2F.2F4.F2.11F.4F9.2F.F
$270.2F.15F11.F$271.2F.F2.3F.8F5.5F.2F$254.C17.F.F.2F3.8F4.2F3.F.F$
253.C.C16.F.F.F5.8F3.6F.F$254.C12.3F3.F2.F6.8F3.4F2.2F$267.4F3.2F5.
10F3.3F.2F$266.F.3F9.14F2.2F.F$265.F.F.2F8.15F3.F.F.F$265.F2.F2.2F5.
15F4.F2.2F$266.2F3.3F3.4F2.9F4.2F$260.2C9.3F.5F5.6F$259.F.C8.9F4.5F$
259.F8.F.8F5.2F$256.2F.2F.F3.C10F7.F$257.F.F.3F.3C9F4.3F$257.F.F.4F4C
8F4.F$256.2F.F2.4F4C7F12.2F$256.F2.8F4C4F.3F8.6F$257.2F2.3F.3F4C3F.2F
.F5.10F$259.2F6.2F4CF5.F3.14F$259.F7.2F.4C5.2F.16F$261.F8.F4C8.14F$
260.2F9.F4C9.10F$268.3F2.4C10.6F$263.F2.5F3.4C11.2F$262.10F3.4C7.3F2.
3F$262.10F4.4C4.12F$263.5F2.F6.4CF.14F$263.3F12.4C14F$279.4C2F.2F4.2F
$280.4C$281.4C$282.4C$283.4C$284.4C$285.4C$286.4C$287.4C$288.4C$289.
4C$290.4C$291.4C$292.4C$293.4C$294.4C$295.4C$296.4C$297.4C$298.4C$
299.4C$300.4C$301.4C$302.4C$303.4C$304.4C$305.4C$306.4C$307.4C$308.4C
$309.4C$310.4C$311.4C$312.4C$313.4C$314.4C$315.4C2$318.C2$320.C2$322.
C!
identify_gun() basically crops the above pattern to the bounding box of pbb (i.e., the red and gray cells), and then removes the cells only in pbb (the red cells), giving the following pattern:
Code: Select all
x = 49, y = 41, rule = LifeHistory
34.2F7.F$30.2F.F.F5.3F$19.2F9.2F.F6.F$10.F.F2.F2.F.3F10.3F4.2F$9.F.2F
2.4F4.F6.8F.3F$9.F9.3F.F6.F.3F.4F$7.2F.12F.3F5.10F$8.F.F2.F2.F.F2.2F
2.2F5.9F$6.3F.2F.6F2.6F7.2F3.F$5.6F2.8F.6F4.3F8.F.F$6.2F.2F4.F2.11F.
4F9.2F.F$17.2F.15F11.F$18.2F.F2.3F.8F5.5F.2F$.C17.F.F.2F3.8F4.2F3.F.F
$C.C16.F.F.F5.8F3.6F.F$.C12.3F3.F2.F6.8F3.4F2.2F$14.4F3.2F5.10F3.3F.
2F$13.F.3F9.14F2.2F.F$12.F.F.2F8.15F3.F.F.F$12.F2.F2.2F5.15F4.F2.2F$
13.2F3.3F3.4F2.9F4.2F$7.2C9.3F.5F5.6F$6.F.C8.9F4.5F$6.F8.F.8F5.2F$3.
2F.2F.F3.C10F7.F$4.F.F.3F.3C9F4.3F$4.F.F.4F4C8F4.F$3.2F.F2.4F4C7F12.
2F$3.F2.8F4C4F.3F8.6F$4.2F2.3F.3F4C3F.2F.F5.10F$6.2F6.2F4CF5.F3.14F$
6.F7.2F.4C5.2F.16F$8.F8.F4C8.14F$7.2F9.F4C9.10F$15.3F2.4C10.6F$10.F2.
5F3.4C11.2F$9.10F3.4C7.3F2.3F$9.10F4.4C4.12F$10.5F2.F6.4CF.14F$10.3F
12.4C14F$26.4C2F.2F4.2F!
Notice that the tub has been added back, but the extra spark cells created by the glider filters have not, giving the erroneous bounding box of 49x41. From this point on, indentify_gun() treats this as the exact envelope of the gun (with gray and white cells actually being blue state-2 cells).
After this, the period/pseudo-period calculations will still be correct. The problems arise when it attempts to find the canonical phase of the gun (starting at line 100 of idgun.py). It will find a phase that it incorrectly thinks is the canonical phase, and can then crop the pattern in a way that it shouldn't like in the gun_1650 example quoted above. The final step is to take the (possibly incorrectly cropped) gun in 2-state Life, convert it to LifeHistory, run it for its full period, then crop again to get the final RLE. Unfortunately, the first incorrect crop could actually cause the pattern to explode, as was seen in the quoted gun_1650 example.