Binary slow salvos

For discussion of specific patterns or specific families of patterns, both newly-discovered and well-known.
User avatar
Pavgran
Posts: 228
Joined: June 12th, 2019, 12:14 pm

Re: Binary slow salvos

Post by Pavgran » September 24th, 2020, 4:00 am

wzkchem5 wrote:
September 23rd, 2020, 11:46 pm
The pattern may eventually collide with the cleanup Corderships before the Corderships die
The pattern RCT actually constructs is just a glider salvo seed for the target pattern. That seed sits peacefully somewhere until all the cleanup is done, and then the final glider from the cleanup traveling towards the seed and the seed itself are the only things existing in the universe.

User avatar
wzkchem5
Posts: 127
Joined: April 17th, 2020, 2:19 am
Location: Valles Marineris, Mars

Re: Binary slow salvos

Post by wzkchem5 » September 24th, 2020, 8:27 am

Pavgran wrote:
September 24th, 2020, 4:00 am
wzkchem5 wrote:
September 23rd, 2020, 11:46 pm
The pattern may eventually collide with the cleanup Corderships before the Corderships die
The pattern RCT actually constructs is just a glider salvo seed for the target pattern. That seed sits peacefully somewhere until all the cleanup is done, and then the final glider from the cleanup traveling towards the seed and the seed itself are the only things existing in the universe.
Thank you, this makes sense!
The Red Phoenix, The Yellow Phoenix, The Pink Phoenix And The Multicolored Phoenix

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » September 24th, 2020, 7:17 pm

I'm noticing that there seems to be a pattern where activity increases during the weekend. Since most of my 3-GPSE ideas, including the most promising ones, require a search that should probably be automated, and I don't want to have to reinvent sideways glider detection, I'm going to wait until the weekend for working on the 3-GPSE solution, and if no one volunteers to code the search by the weekend's end, I'll start coding myself. In the meantime, I'll going to try to optimize the 4-GPSE solution further. Here is the current circuitry:

Code: Select all

x = 1792, y = 1798, rule = B3/S23
obo$b2o$bo62$64bobo$65b2o$65bo62$128bobo$129b2o$129bo62$192bobo$193b2o$193bo62$256bobo$257b2o$257bo62$320bobo$321b2o$321bo62$384bobo$385b2o$385bo62$448bobo$449b2o$449bo62$512bobo$513b2o$513bo62$576bobo$577b2o$577bo57$671bobo$672b2o$672bo3$640bobo$641b2o$641bo62$704bobo$705b2o$705bo62$768bobo$769b2o$769bo62$832bobo$833b2o$833bo65$894bo$893b2o$893bobo$875b2o$876b2o$875bo39$828bo$828b2o$827bobo18$958bo$957b2o$957bobo$811b2o$812b2o$811bo39$764bo$764b2o$763bobo18$1022bo$1021b2o$1021bobo$747b2o$748b2o$747bo39$700bo$700b2o$699bobo18$1086bo$1085b2o$1085bobo$683b2o$684b2o$683bo39$636bo$636b2o$635bobo18$1150bo$1115bo33b2o$1114b2o33bobo$619b2o493bobo$620b2o$619bo39$572bo$572b2o$571bobo18$1214bo$1213b2o$1213bobo$555b2o$556b2o$555bo39$508bo$508b2o$507bobo18$1278bo$1277b2o$1277bobo$491b2o$492b2o$491bo39$444bo$444b2o$443bobo18$1342bo$1341b2o$1341bobo$427b2o$428b2o$427bo39$380bo$380b2o$379bobo18$1406bo$1405b2o$1405bobo$363b2o$364b2o$363bo39$316bo$316b2o$315bobo18$1470bo$1469b2o$1469bobo$299b2o$300b2o$299bo39$252bo$252b2o$251bobo18$1534bo$1533b2o$1533bobo$235b2o$236b2o$235bo39$188bo$188b2o$187bobo18$1598bo$1597b2o$1597bobo$171b2o$172b2o$171bo39$124bo$124b2o$123bobo18$1662bo$1661b2o$1661bobo$107b2o$108b2o$107bo39$60bo$60b2o$59bobo18$1726bo$1725b2o$1725bobo$43b2o$44b2o$43bo59$1790bo$1789b2o$1789bobo!
If we keep the same set of interactions between glider streams A₀, B, C₀, and D, then in order for a collision between a C₁ glider and a D glider, the C₁ glider should be about eight columns to the left of the C₀ glider. I think that there's a way to do that, so I'll search for one.

Also, thank you to wzkchem5 and Pavgran for posting here on a weekday. This way, I don't have to keep editing my previous post.
I am tentatively considering myself back.

User avatar
wzkchem5
Posts: 127
Joined: April 17th, 2020, 2:19 am
Location: Valles Marineris, Mars

Re: Binary slow salvos

Post by wzkchem5 » September 24th, 2020, 10:16 pm

MathAndCode wrote:
September 24th, 2020, 7:17 pm
Also, thank you to wzkchem5 and Pavgran for posting here on a weekday. This way, I don't have to keep editing my previous post.
Good, I'll ask my stupid questions one at a time in order to do your favor :)
The Red Phoenix, The Yellow Phoenix, The Pink Phoenix And The Multicolored Phoenix

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

Re: Binary slow salvos

Post by dvgrn » September 24th, 2020, 10:18 pm

MathAndCode wrote:
September 24th, 2020, 7:17 pm
Also, thank you to wzkchem5 and Pavgran for posting here on a weekday. This way, I don't have to keep editing my previous post.
Just for the record, it's perfectly okay to start a new message every now and then, sometime before the twenty-fifth edit, even if it happens to follow a previous post. That rule is mostly intended to prevent overly chatty posters from posting four one-line messages five minutes apart, without saying much of anything interesting in any of them.

A good rule of thumb might be that if you're starting a new topic, and/or if a day or two has passed since your most recent post in a thread, and/or if your previous post is getting too long and crowded, then it's fine to go ahead and start a new post instead.

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » September 25th, 2020, 9:37 am

wzkchem5 wrote:
September 24th, 2020, 10:16 pm
MathAndCode wrote:
September 24th, 2020, 7:17 pm
Also, thank you to wzkchem5 and Pavgran for posting here on a weekday. This way, I don't have to keep editing my previous post.
Good, I'll ask my stupid questions one at a time in order to do your favor :)
I didn't consider your question to be stupid, but thank you…
dvgrn wrote:
September 24th, 2020, 10:18 pm
MathAndCode wrote:
September 24th, 2020, 7:17 pm
Also, thank you to wzkchem5 and Pavgran for posting here on a weekday. This way, I don't have to keep editing my previous post.
Just for the record, it's perfectly okay to start a new message every now and then, sometime before the twenty-fifth edit, even if it happens to follow a previous post. That rule is mostly intended to prevent overly chatty posters from posting four one-line messages five minutes apart, without saying much of anything interesting in any of them.

A good rule of thumb might be that if you're starting a new topic, and/or if a day or two has passed since your most recent post in a thread, and/or if your previous post is getting too long and crowded, then it's fine to go ahead and start a new post instead.
…and apparently that's not necessary, but I'd still like to thank wzkchem5 for being willing to help me, as well as thank dvgrn for clarifying the rule.

Anyway, here's an way to get a traffic light.

Code: Select all

x = 1792, y = 1798, rule = B3/S23
2bo$obo$b2o62$66bo$64bobo$65b2o62$130bo$128bobo$129b2o62$194bo$192bobo$193b2o62$258bo$256bobo$257b2o62$322bo$320bobo$321b2o62$386bo$384bobo$385b2o62$450bo$448bobo$449b2o62$514bo$512bobo$513b2o17$569bo$567bobo$568b2o43$578bo$576bobo$577b2o62$642bo$640bobo$641b2o62$706bo$704bobo$705b2o62$770bo$768bobo$769b2o62$834bo$832bobo$833b2o65$893b2o$893bobo$893bo$875b3o$877bo$876bo39$828b2o$827bobo$829bo18$957b2o$957bobo$957bo$811b3o$813bo$812bo39$764b2o$763bobo$765bo18$1021b2o$1021bobo$1021bo$747b3o$749bo$748bo39$700b2o$699bobo$701bo18$1085b2o$1085bobo$1085bo$683b3o$685bo$684bo39$636b2o$635bobo$637bo18$1149b2o$1114b2o33bobo$1114bobo32bo$619b3o492bo$621bo$620bo39$572b2o$571bobo$573bo18$1213b2o$1213bobo$1213bo$555b3o$557bo$556bo39$508b2o$507bobo$509bo18$1277b2o$1277bobo$1277bo$491b3o$493bo$492bo39$444b2o$443bobo$445bo18$1341b2o$1341bobo$1341bo$427b3o$429bo$428bo39$380b2o$379bobo$381bo18$1405b2o$1405bobo$1405bo$363b3o$365bo$364bo39$316b2o$315bobo$317bo18$1469b2o$1469bobo$1469bo$299b3o$301bo$300bo39$252b2o$251bobo$253bo18$1533b2o$1533bobo$1533bo$235b3o$237bo$236bo39$188b2o$187bobo$189bo18$1597b2o$1597bobo$1597bo$171b3o$173bo$172bo39$124b2o$123bobo$125bo18$1661b2o$1661bobo$1661bo$107b3o$109bo$108bo39$60b2o$59bobo$61bo18$1725b2o$1725bobo$1725bo$43b3o$45bo$44bo59$1789b2o$1789bobo$1789bo!

Code: Select all

x = 218, y = 153, rule = B3/S23
43b2o$43b2o2$6b2o$5bobo$6bo$17bo$17bo$17bo4$24b3o$35b2o33b2o$35b2o32bobo$69b2o$38bo$38bo$38bo2$40b3o2$37b2o$36bo2bo$37b2o40b2o$79b2o4$7b2o$6bo2bo$7bobo$8bo66b2o$75b2o2$38b2o$37bobo$38bo4$b2o47b3o$o2bo48b3o$b2o42b2o2b2o4bo$45b2o2bo2bo3bo$50bo4bo11b2o$53bo13b2o$51bobo$52bo17bo$70bo$70bo2$72b3o2$69b2o$68bo2bo$69b2o5$39b2o$38bo2bo$39bobo$40bo3$70b2o$69bobo$70bo4$33b2o44b2o$32bo2bo42bobo$33b2o30b2o12bo$64bobo$65bo3$53b2o$53b2o5$100b2o49bobo$91b2o7b2o50b2o$90bo2bo5bo2bo49bo$79b6o6bobo5bo2bo$78bo5bo7bo5bo2bo$78bo20bo2bo$70bo8bo4bo14b4o$69bobo10b3o15bo$70b2o31bo$101bo$101b2o4$105b2o$105b2o3$77b2o$77b2o3$107bo$107b2o$109bo2$85b2o7b3o$85b2o$92bo5bo12bo$92bo5bo$92bo5bo2b3o$100bo2bo$94b3o3bo3bo$99b2obobo$99b2ob2o12b4o$100b3o12b2o4bo$115b3o4bo$117bo5bo$115b2o$115b2o2b2o4bo$101b3o11bo9bo$116bo2bo3bo$117bo$118b2obo$120bo5$195bo$194b2o$194bobo13$215bobo$216b2o$216bo!
There's almost certainty at least one other way to get a target. Does anyone know which is the best?



Edit: This forms a bi-block.

Code: Select all

x = 218, y = 153, rule = B3/S23
43b2o$43b2o2$6b2o$5bobo$6bo$17bo$17bo$17bo4$24b3o$35b2o33b2o$35b2o32b
obo$69b2o$38bo$38bo$38bo2$40b3o2$37b2o$36bo2bo$37b2o40b2o$79b2o4$7b2o
$6bo2bo$7bobo$8bo66b2o$75b2o2$38b2o$37bobo$38bo4$b2o47b3o$o2bo48b3o$b
2o42b2o2b2o4bo$45b2o2bo2bo3bo$50bo4bo11b2o$53bo13b2o$51bobo$52bo17bo$
70bo$70bo2$72b3o2$69b2o$68bo2bo$69b2o5$39b2o$38bo2bo$39bobo$40bo3$70b
2o$69bobo$70bo4$33b2o44b2o$32bo2bo42bobo$33b2o30b2o12bo$64bobo$65bo3$
53b2o$53b2o5$100b2o49bobo$91b2o7b2o50b2o$90bo2bo5bo2bo49bo$79b6o6bobo
5bo2bo$78bo5bo7bo5bo2bo$78bo20bo2bo$70bo8bo4bo14b4o$69bobo10b3o15bo$70b
2o31bo$101bo$101b2o4$105b2o$105b2o3$77b2o$77b2o3$107bo$107b2o$109bo2$
85b2o7b3o$85b2o$92bo5bo12bo$92bo5bo$92bo5bo2b3o$100bo2bo$94b3o3bo3bo$
99b2obobo$99b2ob2o12b4o$100b3o12b2o4bo$115b3o4bo$117bo5bo$115b2o$115b
2o2b2o4bo$101b3o11bo9bo$116bo2bo3bo$117bo$118b2obo$120bo$191bo$190b2o
$190bobo17$215bobo$216b2o$216bo!

Code: Select all

x = 1792, y = 1798, rule = B3/S23
2bo$obo$b2o62$66bo$64bobo$65b2o62$130bo$128bobo$129b2o62$194bo$192bob
o$193b2o62$258bo$256bobo$257b2o62$322bo$320bobo$321b2o62$386bo$384bob
o$385b2o62$450bo$448bobo$449b2o62$514bo$512bobo$513b2o21$573bo$571bob
o$572b2o39$578bo$576bobo$577b2o62$642bo$640bobo$641b2o62$706bo$704bob
o$705b2o62$770bo$768bobo$769b2o62$834bo$832bobo$833b2o65$893b2o$893bo
bo$893bo$875b3o$877bo$876bo39$828b2o$827bobo$829bo18$957b2o$957bobo$957b
o$811b3o$813bo$812bo39$764b2o$763bobo$765bo18$1021b2o$1021bobo$1021bo
$747b3o$749bo$748bo39$700b2o$699bobo$701bo18$1085b2o$1085bobo$1085bo$
683b3o$685bo$684bo39$636b2o$635bobo$637bo18$1149b2o$1114b2o33bobo$1114b
obo32bo$619b3o492bo$621bo$620bo39$572b2o$571bobo$573bo18$1213b2o$1213b
obo$1213bo$555b3o$557bo$556bo39$508b2o$507bobo$509bo18$1277b2o$1277bo
bo$1277bo$491b3o$493bo$492bo39$444b2o$443bobo$445bo18$1341b2o$1341bob
o$1341bo$427b3o$429bo$428bo39$380b2o$379bobo$381bo18$1405b2o$1405bobo
$1405bo$363b3o$365bo$364bo39$316b2o$315bobo$317bo18$1469b2o$1469bobo$
1469bo$299b3o$301bo$300bo39$252b2o$251bobo$253bo18$1533b2o$1533bobo$1533b
o$235b3o$237bo$236bo39$188b2o$187bobo$189bo18$1597b2o$1597bobo$1597bo
$171b3o$173bo$172bo39$124b2o$123bobo$125bo18$1661b2o$1661bobo$1661bo$
107b3o$109bo$108bo39$60b2o$59bobo$61bo18$1725b2o$1725bobo$1725bo$43b3o
$45bo$44bo59$1789b2o$1789bobo$1789bo!
These seem to be the only two ways. The traffic light seems to be more promising because it's one of the steps in a crystal, but the bi-block is at least a theoretical option. If this pans out, then this will lead to universal construction in 16 gliders.
I am tentatively considering myself back.

User avatar
calcyman
Moderator
Posts: 2964
Joined: June 1st, 2009, 4:32 pm

Re: Binary slow salvos

Post by calcyman » September 25th, 2020, 12:39 pm

This is much more difficult than the 17-glider variant for at least two reasons:
  • The location of the initial target cannot be made arbitrarily far from the glider streams, so there's not as much room to manoeuvre.
  • There won't just be one glider from the northwest. I think that there will be a glider from the northwest every time we fire a single (as opposed to double) construction glider. This means that effectively these gliders from the northwest need to be factored in as part of the recipe.
We'd probably need to find some combination of gliders that results in the gliders from the northwest being consumed (e.g. by the crystal reaction) whilst also generating a target capable of being manipulated by the gliders from the southwest.
What do you do with ill crystallographers? Take them to the mono-clinic!

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » September 25th, 2020, 2:48 pm

calcyman wrote:
September 25th, 2020, 12:39 pm
This is much more difficult than the 17-glider variant for at least two reasons:
  • The location of the initial target cannot be made arbitrarily far from the glider streams, so there's not as much room to manoeuvre.
  • There won't just be one glider from the northwest. I think that there will be a glider from the northwest every time we fire a single (as opposed to double) construction glider. This means that effectively these gliders from the northwest need to be factored in as part of the recipe.
We'd probably need to find some combination of gliders that results in the gliders from the northwest being consumed (e.g. by the crystal reaction) whilst also generating a target capable of being manipulated by the gliders from the southwest.
The first point won't necessarily be a problem since we need a push reaction anyway.
About the second point, the signal that returns from GPSE C will be dependent on the signal that returns from GPSE the next time, which should make it easy to control.

Also, keep in mind that this is my way of continuing to make progress while waiting to see whether or not anyone volunteers to code an automated search by the end of the weekend.
I am tentatively considering myself back.

User avatar
calcyman
Moderator
Posts: 2964
Joined: June 1st, 2009, 4:32 pm

Re: Binary slow salvos

Post by calcyman » September 25th, 2020, 6:59 pm

MathAndCode wrote:
September 25th, 2020, 2:48 pm
The first point won't necessarily be a problem since we need a push reaction anyway.
Yes, but even still, there often needs to be a reasonable amount of manoeuvring room for the push reaction to work.

For example, if we look at the envelope for the push reaction for the 17-glider RCT, observe that it extends about 25 full-diagonals south-west of the 'two blinkers' elbow (left figure below). Moreover, to cleanly produce the 'two blinkers' elbow from the initial honeyfarm target of the 17-glider RCT requires a clearance of almost 50 full-diagonals (right figure below).

Code: Select all

x = 160, y = 80, rule = LifeHistory
135.B$134.3B$134.3B$133.5B2.B$130.2B.5B.4B$129.13BD$129.12BD.D$127.
14BD.D$125.17BD$124.19B$123.14B2D2B3.2B2D$122.14BD2BDB2.2BDB.D$121.
16B2D7B2DB6.2B$112.4B2.31B5.4B$109.2B.30BD6B5.4B$108.33BDBD6B3.7B$
107.34BDBD6B.9B$45.B60.36BD17B$43.5B58.53B$41.8B57.52B$40.11B56.51B$
40.12B3.2B49.51B$38.14B3.A2B49.44B.2B.B$31.3B2.19BA2B44.3B2.43B$30.
25BA4B42.48B$28.33B40.49B$26.25BD5B3AB40.30BA19B$26.25BD7B42.30BA19B$
26.25BD8B41.30BA18B$26.35B38.51B$27.26B3D5B37.35B3A15B$28.33B38.51B$
28.32B40.52B$27.32B42.52B$27.31B42.2B.36B6.7B$27.30B42.39B8.4B$27.29B
42.39B10.2B$27.29B42.38B$28.27B43.37B$28.27B42.37B$27.29B41.38B$26.
29B41.40B$26.29B40.41B$24.31B39.41B$23.31B40.39B$23.31B39.39B$24.29B
41.37B$24.27B44.36B$23.27B48.3B.28B$22.26B54.29B$21.27B53.30B$20.4B.
8B3.11B53.4B.26B$19.4B2.8B7.7B52.4B2.25B$18.4B2.4B.3B9.6B51.4B2.4B.
22B$17.4B2.4B15.B.B52.4B2.4B2.22B$16.4B2.4B70.4B2.4B3.22B$15.4B2.4B
70.4B2.4B4.20B$14.4B2.4B70.4B2.4B5.18B$13.4B2.4B70.4B2.4B7.18B$12.4B
2.4B70.4B2.4B7.18B$11.4B2.4B70.4B2.4B7.19B$10.4B2.4B70.4B2.4B9.14B.3B
$9.4B2.4B70.4B2.4B10.15B$8.4B2.4B70.4B2.4B11.14B$7.4B2.4B70.4B2.4B12.
14B$6.4B2.4B70.4B2.4B12.14B$5.4B2.4B70.4B2.4B13.14B$4.4B2.4B70.4B2.4B
16.7B.3B$3.4B2.4B70.4B2.4B17.2B.3B$2.4B2.4B70.4B2.4B$.4B2.4B70.4B2.4B
$4B2.4B70.4B2.4B$3B2.4B70.4B2.4B$2B2.4B70.4B2.4B$B2.4B70.4B2.4B$2.4B
70.4B2.4B$.4B70.4B2.4B$4B70.4B2.4B$3B70.4B2.4B$2B70.4B2.4B!
What do you do with ill crystallographers? Take them to the mono-clinic!

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » September 25th, 2020, 7:15 pm

calcyman wrote:
September 25th, 2020, 6:59 pm
MathAndCode wrote:
September 25th, 2020, 2:48 pm
The first point won't necessarily be a problem since we need a push reaction anyway.
Yes, but even still, there often needs to be a reasonable amount of manoeuvring room for the push reaction to work.

For example, if we look at the envelope for the push reaction for the 17-glider RCT, observe that it extends about 25 full-diagonals south-west of the 'two blinkers' elbow (left figure below). Moreover, to cleanly produce the 'two blinkers' elbow from the initial honeyfarm target of the 17-glider RCT requires a clearance of almost 50 full-diagonals (right figure below).
You have a good point. I'll stop trying to make that work and code a search in order to help realize a 3-GPSE solution.
I am tentatively considering myself back.

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Automated search difficulties

Post by MathAndCode » September 27th, 2020, 7:04 pm

MathAndCode wrote:
September 25th, 2020, 7:15 pm
calcyman wrote:
September 25th, 2020, 6:59 pm
MathAndCode wrote:
September 25th, 2020, 2:48 pm
The first point won't necessarily be a problem since we need a push reaction anyway.
Yes, but even still, there often needs to be a reasonable amount of manoeuvring room for the push reaction to work.

For example, if we look at the envelope for the push reaction for the 17-glider RCT, observe that it extends about 25 full-diagonals south-west of the 'two blinkers' elbow (left figure below). Moreover, to cleanly produce the 'two blinkers' elbow from the initial honeyfarm target of the 17-glider RCT requires a clearance of almost 50 full-diagonals (right figure below).
You have a good point. I'll stop trying to make that work and code a search in order to help realize a 3-GPSE solution.
I finished my program and ran it. I replaced the ranges in lines 109 and 110 with range(7, 8) and range(1) (but changed them back when adding the code), and the program was still running after a minute, which means that attempting to do a search with about 10,000 the size in this way would not be practical. Chances are that someone else has already coded a much more efficient way to do this (which is why I didn't want to be the one to code the search), but I'm including my (Python) code anyway.

Code: Select all

gpseRle = "bo$2o$obo62$65bo$64b2o$64bobo23$171bo$170bobo2$170bo2bo$172b2o$173bo2$187bo$182b2o3bo$182b2o3bo$170b2o13b2o$172bo9b2ob2o$171b2o10bo$170b3o$170b2o$169b3obo$170bo3bo$172bo2bo$172b3o$173b2o3$203b2o$203b2o3$192bo$191bobo$191b2o2$211b2o$211b2o3$183b2o$183b2o4$129bo$128b2o77b2o$128bobo75bo2b2o7b2o$205b6o7bobo$206b2obo9bo$208bo$197bo9bo$196bobo8b3o$196bo2bo5bo3b2o$197b2o6bo2b3ob2o$191bo13bo2bo3b2o$187bo2b3o13b2o2bo2bo$185bobo3b2o15b2o2bo$185bobo20b4o$184b2obobo$185bo3b2o44b2o$186bo4b2o42b2o2$187bo5bo$224bo$187bo4bo30bobo$187bo2bo19bo12b2o30b2o$188b3o18bobo42bo2bo$209b2o44b2o4$219bo$218bobo$218b2o3$249bo$248bobo$248bo2bo$249b2o5$219b2o$218bo2bo$219b2o2$215b3o2$219bo$219bo$219bo2$221b2o$221b2o$231b3o$287b2o$286bo2bo$287b2o$240bo$240bo$240bo$251bo$250bobo$250b2o2$213b2o$213b2o66bo$280bobo$280bo2bo$281b2o4$209b2o$209b2o40b2o$250bo2bo$251b2o2$247b3o2$251bo$251bo$251bo$219b2o$218bobo32b2o$218b2o33b2o$263b3o$319b2o$318bo2bo$319b2o$272bo$272bo$272bo$283bo$282bobo$282b2o2$245b2o$245b2o66bo$312bobo$312bo2bo$313b2o4$241b2o$241b2o40b2o$282bo2bo$283b2o2$279b3o2$283bo$283bo$283bo$251b2o$250bobo32b2o$250b2o33b2o$295b3o4$304bo$304bo$304bo5$277b2o$277b2o7$273b2o$273b2o9$283b2o$282bobo$282b2o".replace("b", "b,").replace("o", "o,").replace("$", "$,")[:-1].split(",")
for rleSectionIndex in range(len(gpseRle)):
    if len(gpseRle[rleSectionIndex]) < 2:
        gpseRle[rleSectionIndex] = "1" + gpseRle[rleSectionIndex]

gpseSetOfCells = set()
currentColumn = 0
currentRow = 0
for rleSection in gpseRle:
    if rleSection[-1] == "o":
        for _ in range(int(rleSection[:-1])):
            gpseSetOfCells.add((currentColumn, currentRow))
            currentColumn += 1
    elif rleSection[-1] == "b":
        for _ in range(int(rleSection[:-1])):
            currentColumn += 1
    else:         # rleSection[-1] == "$"
        for _ in range(int(rleSection[:-1])):
            currentRow += 1
        currentColumn = 0

def alive_next_generation(alreadyAlive, neighborPlusSelfCount):
    if alreadyAlive:
        return (neighborPlusSelfCount>=3 and neighborPlusSelfCount<=4)
    else:
        return neighborPlusSelfCount == 3

def board_update(updateFrom):
    return set(cellToCheck for cellToCheck in tuple(updateFrom.union(set((liveCell[0]-1, liveCell[1]) for liveCell in updateFrom)).union(set((liveCell[0]+1, liveCell[1]) for liveCell in updateFrom)).union(set((liveCell[0], liveCell[1]-1) for liveCell in updateFrom)).union(set((liveCell[0], liveCell[1]+1) for liveCell in updateFrom)).union(set((liveCell[0]-1, liveCell[1]-1) for liveCell in updateFrom)).union(set((liveCell[0]+1, liveCell[1]+1) for liveCell in updateFrom))) if alive_next_generation(cellToCheck in updateFrom, len(updateFrom.intersection(tuple((cellToCheck[0]+xDisplacement, cellToCheck[1]+yDisplacement) for xDisplacement in range(-1, 2) for yDisplacement in range(-1, 2))))))

def go_generations_ahead(initialBoard, numberOfGenerations):
    if numberOfGenerations == 0:
        return initialBoard
    else:
        return go_generations_ahead(board_update(initialBoard), numberOfGenerations-1)

def test_sending_glider(laneDisplacement, timeOffset):
    defaultBoard = go_generations_ahead(gpseSetOfCells, timeOffset)
    testBoard = defaultBoard.union(((0, 1-laneDisplacement), (1, 2-laneDisplacement), (1, 3-laneDisplacement), (2, 1-laneDisplacement), (2, 2-laneDisplacement)))
    sidewaysSpaceship = False
    defaultBoard = go_generations_ahead(go_generations_ahead(defaultBoard, 500), 500)
    testBoard = go_generations_ahead(go_generations_ahead(testBoard, 500), 500)
    lastSymmetricDifference = defaultBoard ^ testBoard
    lastLocalDifference = set(differentPoint for differentPoint in lastSymmetricDifference if differentPoint[0]>0 and differentPoint[0] < 400 and differentPoint[1]>0 and differentPoint[1] < 400)
    defaultBoard = go_generations_ahead(defaultBoard, 30)        # It detects whether or not the reaction has completed by checking whether or not all of the cells are the same as 30 generations ago. Checking whether or not they're the same as 2 generations ago would be sufficient for most runs, but I plan for this program to run about twenty thousand tests, so there's a decent chance that a pentadecathlon will pop up at least once. 
    testBoard = go_generations_ahead(testBoard, 30)
    generationsElapsed = timeOffset + 1030
    currentSymmetricDifference = defaultBoard ^ testBoard
    currentLocalDifference = set(differentPoint for differentPoint in currentSymmetricDifference if differentPoint[0]>0 and differentPoint[0]<400 and differentPoint[1]>0 and differentPoint[1]<400)
    while (currentLocalDifference) != lastLocalDifference:
        if any(abs(differentPoint[0]-differentPoint[1]-60)>150 for differentPoint in currentSymmetricDifference):
            sidewaysSpaceship = True
        else:
            lastSymmetricDifference = currentSymmetricDifference.copy()
            lastLocalDifference = currentLocalDifference.copy()
            defaultBoard = go_generations_ahead(defaultBoard, 30)
            testBoard = go_generations_ahead(testBoard, 30)
            generationsElapsed += 30
            currentSymmetricDifference = defaultBoard ^ testBoard
            currentLocalDifference = set(differentPoint for differentPoint in currentSymmetricDifference if differentPoint[0]>0 and differentPoint[0]<400 and differentPoint[1]>0 and differentPoint[1]<400)
    if sidewaysSpaceship:
        return "X"        # Escaping sideways gliders (or XWSSes) render the collision unusable.
    else:
        generationsMore = (-generationsElapsed)%256
        defaultBoard = go_generations_ahead(defaultBoard, generationsMore)
        testBoard = go_generations_ahead(testBoard, generationsMore)
        addedEscapingCells = set(addedCell for addedCell in testBoard-defaultBoard if addedCell[0]<0 or addedCell[1]<0)
        removedEscapingCells = set(removedCell for removedCell in defaultBoard-testBoard if removedCell[0]<0 or removedCell[1]<0)
        escapingSymmetricDifference = addedEscapingCells | removedEscapingCells        # Because of the nature of the sets, the symmetric difference could also be used.
        unaccountedRemovedCells = removedEscapingCells.copy()
        unaccountedEscapingDifference = escapingSymmetricDifference.copy()
        gliderDifferenceDict = {"created": set(), "destoryed": 0}
        for missingCellPosition in removedEscapingCells:        # detects missing gliders
            if missingCellPosition[0]-missingCellPosition[1]==1 and (missingCellPosition[0]+missingCellPosition[1])%128==1 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}<=defaultBoard:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= (missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2))
                unaccountedEscapingDifference ^= (missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2))        # It uses the symmetric difference instead of simply a difference in case a created glider partially overlaps a removed glider.
            elif missingCellPosition[1]-missingCellPosition[0]==2 and (missingCellPosition[0]+missingCellPosition[1])%128==2 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), (missingCellPosition[0]+2, missingCellPosition[1])}<=defaultBoard:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= ((missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+2, missingCellPosition[1]))
                unaccountedEscapingDifference ^= ((missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+2, missingCellPosition[1]))
            elif missingCellPosition[0]==missingCellPosition[0] and (missingCellPosition[0]+missingCellPosition[1])%128==4 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1])}<=defaultBoard:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= ((missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1]), missingCellPosition)
                unaccountedEscapingDifference ^= ((missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1]), missingCellPosition)
        if bool(unaccountedRemovedCells):        # returns true if and only if the set is not empty
            return "?"        # This line reports that the program was unable to identify the difference. It probably means that the bounds for checking for either escaping spaceships or when the reaction has settled should be changed.
        else:          # There would be a line unaccountedAddedCells=unaccountedRemovedCells^unaccountedEscapingDifference (taking the symmetric difference), but it's not necessary because this section will only execute if unaccountedRemovedCells is empty, so the program can use unaccountedEscapingDifference instead of unaccountedAddedCells.
            for addedCellPosition in unaccountedEscapingDifference.copy():        # The .copy() is necessary in order to prevent modifying a set while looping through it.
                if {addedCellPosition, (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]-1, addedCellPosition[1]+2), (addedCellPosition[0]+1, addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1]-1, 4*addedCellPosition[0]-4))
                    unaccountedEscapingDifference -= (addedCellPosition, (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]-1, addedCellPosition[1]+2), (addedCellPosition[0]+1, addedCellPosition[1]+2))
                elif {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+2, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-1))
                    unaccountedEscapingDifference -= (addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+2, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2))
                elif {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+1, addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-2))
                    unaccountedEscapingDifference -= (addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+1, addedCellPosition[1]+2))
                elif {(addedCellPosition[0]-1, addedCellPosition[1]), addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-3))
                    unaccountedEscapingDifference -= ((addedCellPosition[0]-1, addedCellPosition[1]), addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2))
        if bool(unaccountedEscapingDifference):        # returns true if and only if the set is not empty
            return "?"        # As before, this line reports that the program was unable to identify the difference and probably means that the bounds for checking for either escaping spaceships or when the reaction has settled should be changed.
        else:
            gliderDifferenceDict["backwards gliders"] = any(testCell[0]+testCell[1]>800 for testCell in testBoard)
            return gliderDifferenceDict
        
gliderResults = {}
for laneOffset in range(7, 45):
    for generationsToWait in range(256):
        gliderResults[(laneOffset, {generationsToWait, generationsToWait+256})] = {test_sending_glider(laneOffset, generationsToWait), test_sending_glider(laneOffset, generationsToWait+256)}
print(gliderResults)
I am tentatively considering myself back.

User avatar
calcyman
Moderator
Posts: 2964
Joined: June 1st, 2009, 4:32 pm

Re: Automated search difficulties

Post by calcyman » September 28th, 2020, 6:16 am

MathAndCode wrote:
September 27th, 2020, 7:04 pm
I finished my program and ran it. I replaced the ranges in lines 109 and 110 with range(7, 8) and range(1) (but changed them back when adding the code), and the program was still running after a minute, which means that attempting to do a search with about 10,000 the size in this way would not be practical. Chances are that someone else has already coded a much more efficient way to do this (which is why I didn't want to be the one to code the search), but I'm including my (Python) code anyway.
Oh wow -- you've implemented GoL yourself in Python without using any libraries? I can understand your reluctance.

It would be much faster and less painful to either use Golly or lifelib.
What do you do with ill crystallographers? Take them to the mono-clinic!

wwei23

Re: Binary slow salvos

Post by wwei23 » September 28th, 2020, 8:49 am

Uh, is there supposed to be an emoji in the range description? I'm confused.

User avatar
praosylen
Posts: 2449
Joined: September 13th, 2014, 5:36 pm
Location: Pembina University, Home of the Gliders
Contact:

Re: Binary slow salvos

Post by praosylen » September 28th, 2020, 9:16 am

wwei23 wrote:
September 28th, 2020, 8:49 am
Uh, is there supposed to be an emoji in the range description? I'm confused.
"8)" is replaced by that particular smiley by default when included in a post, if smilies aren't disabled.
former username: A for Awesome
praosylen#5847 (Discord)

The only decision I made was made
of flowers, to jump universes to one of springtime in
a land of former winter, where no invisible walls stood,
or could stand for more than a few hours at most...

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Automated search difficulties

Post by MathAndCode » September 28th, 2020, 1:18 pm

calcyman wrote:
September 28th, 2020, 6:16 am
MathAndCode wrote:
September 27th, 2020, 7:04 pm
I finished my program and ran it. I replaced the ranges in lines 109 and 110 with range(7, 8) and range(1) (but changed them back when adding the code), and the program was still running after a minute, which means that attempting to do a search with about 10,000 the size in this way would not be practical. Chances are that someone else has already coded a much more efficient way to do this (which is why I didn't want to be the one to code the search), but I'm including my (Python) code anyway.
Oh wow -- you've implemented GoL yourself in Python without using any libraries? I can understand your reluctance.
That wasn't actually the part that took the longest, partially because I was able to use code from another cellular automaton-simulating program. Instead, the part that took the longest—and the part that I was most concerned about—was writing the code to evaluate the effects of sending each glider, which would have taken even longer had I not thought of simply testing for cells sufficiently far from the main diagonal instead of writing code to detect sideways gliders and XWSSes (although the method that I used might be more prone to bugs).
calcyman wrote:
September 28th, 2020, 6:16 am
It would be much faster and less painful to either use Golly or lifelib.
Thank you. Do you know which would be better suited for this particular purpose? There will probably be a lot of repeated reactions, but I'm not sure whether or not HashLife will detect similarities across different runs. Also, can either of the programs detect escaping XWSSes?
While typing this response, I realized that the program would run the control case about 20,000 times, which is definitely unnecessary and should be addressed, and that an emitted XWSS in a diagonal-forwards direction might be absorbed the the ash of other GPSE without emitting any gliders and should therefore not be disqualified on account of the XWSS (although it might also emit sideways gliders).
A for awesome wrote:
September 28th, 2020, 9:16 am
wwei23 wrote:
September 28th, 2020, 8:49 am
Uh, is there supposed to be an emoji in the range description? I'm confused.
"8)" is replaced by that particular smiley by default when included in a post, if smilies aren't disabled.
Yes, so I disabled smilies in my post. However, I think that inserting a formatting tag, even if empty, between the two characters will also work:
range(7, 8)
Yes; it works.
I am tentatively considering myself back.

User avatar
calcyman
Moderator
Posts: 2964
Joined: June 1st, 2009, 4:32 pm

Re: Automated search difficulties

Post by calcyman » September 28th, 2020, 1:55 pm

MathAndCode wrote:
September 28th, 2020, 1:18 pm
Thank you. Do you know which would be better suited for this particular purpose? There will probably be a lot of repeated reactions, but I'm not sure whether or not HashLife will detect similarities across different runs. Also, can either of the programs detect escaping XWSSes?
While typing this response, I realized that the program would run the control case about 20,000 times, which is definitely unnecessary and should be addressed, and that an emitted XWSS in a diagonal-forwards direction might be absorbed the the ash of other GPSE without emitting any gliders and should therefore not be disqualified on account of the XWSS (although it might also emit sideways gliders).
Lifelib's hashlife implementation definitely does detect similarities across different runs, so you might want to use that.

There's functionality for finding (and replacing, if you like) subpatterns in a pattern, so you can efficiently search for a glider (in a particular phase+orientation combination). Specifically, you specify both the ON-cells and OFF-cells to search.
What do you do with ill crystallographers? Take them to the mono-clinic!

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Automated search difficulties

Post by MathAndCode » September 28th, 2020, 2:04 pm

calcyman wrote:
September 28th, 2020, 1:55 pm
MathAndCode wrote:
September 28th, 2020, 1:18 pm
Thank you. Do you know which would be better suited for this particular purpose? There will probably be a lot of repeated reactions, but I'm not sure whether or not HashLife will detect similarities across different runs. Also, can either of the programs detect escaping XWSSes?
While typing this response, I realized that the program would run the control case about 20,000 times, which is definitely unnecessary and should be addressed, and that an emitted XWSS in a diagonal-forwards direction might be absorbed the the ash of other GPSE without emitting any gliders and should therefore not be disqualified on account of the XWSS (although it might also emit sideways gliders).
Lifelib's hashlife implementation definitely does detect similarities across different runs, so you might want to use that.

There's functionality for finding (and replacing, if you like) subpatterns in a pattern, so you can efficiently search for a glider (in a particular phase+orientation combination). Specifically, you specify both the ON-cells and OFF-cells to search.
Yes; that will be very useful. Thank you.
Edit: I just thought of something. Will there be a way to tell when the pattern settles? I'm shooting gliders at the ash of an active puffer/rake, so that might be more difficult than for most situations. I suppose that I could use the same code as before, but there might be something more efficient.
I am tentatively considering myself back.

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » October 10th, 2020, 5:00 pm

Code: Select all

import lifelib

conwayLifeTree = lifelib.load_rules("b3s23").lifetree()
gpseLifelib = conwayLifeTree.pattern("bo$2o$obo62$65bo$64b2o$64bobo23$171bo$170bobo2$170bo2bo$172b2o$173bo2$187bo$182b2o3bo$182b2o3bo$170b2o13b2o$172bo9b2ob2o$171b2o10bo$170b3o$170b2o$169b3obo$170bo3bo$172bo2bo$172b3o$173b2o3$203b2o$203b2o3$192bo$191bobo$191b2o2$211b2o$211b2o3$183b2o$183b2o4$129bo$128b2o77b2o$128bobo75bo2b2o7b2o$205b6o7bobo$206b2obo9bo$208bo$197bo9bo$196bobo8b3o$196bo2bo5bo3b2o$197b2o6bo2b3ob2o$191bo13bo2bo3b2o$187bo2b3o13b2o2bo2bo$185bobo3b2o15b2o2bo$185bobo20b4o$184b2obobo$185bo3b2o44b2o$186bo4b2o42b2o2$187bo5bo$224bo$187bo4bo30bobo$187bo2bo19bo12b2o30b2o$188b3o18bobo42bo2bo$209b2o44b2o4$219bo$218bobo$218b2o3$249bo$248bobo$248bo2bo$249b2o5$219b2o$218bo2bo$219b2o2$215b3o2$219bo$219bo$219bo2$221b2o$221b2o$231b3o$287b2o$286bo2bo$287b2o$240bo$240bo$240bo$251bo$250bobo$250b2o2$213b2o$213b2o66bo$280bobo$280bo2bo$281b2o4$209b2o$209b2o40b2o$250bo2bo$251b2o2$247b3o2$251bo$251bo$251bo$219b2o$218bobo32b2o$218b2o33b2o$263b3o$319b2o$318bo2bo$319b2o$272bo$272bo$272bo$283bo$282bobo$282b2o2$245b2o$245b2o66bo$312bobo$312bo2bo$313b2o4$241b2o$241b2o40b2o$282bo2bo$283b2o2$279b3o2$283bo$283bo$283bo$251b2o$250bobo32b2o$250b2o33b2o$295b3o4$304bo$304bo$304bo5$277b2o$277b2o7$273b2o$273b2o9$283b2o$282bobo$282b2o!")

def test_sending_glider(laneDisplacement, timeOffset):
    testBoard = gpseLifelib[timeOffset].__or__(conwayLifeTree.pattern("obo$b2o$bo").shift(0, 1-laneDisplacement))
    sidewaysSpaceship = False
    generationsElapsed = timeOffset + 1000
    lastLocalDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords() if abs(differentPoint[0]+differentPoint[1]-400)<=400 and abs(differentPoint[0]-differentPoint[1])<=400)
    generationsElapsed += 30
    currentSymmetricDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords())
    currentLocalDifference = frozenset(tuple(differentPoint) for differentPoint in currentSymmetricDifference if abs(differentPoint[0]+differentPoint[1]-400)<=400 and abs(differentPoint[0]-differentPoint[1])<=400)
    while currentLocalDifference != lastLocalDifference:
        if any(abs(differentPoint[0]-differentPoint[1])>400 for differentPoint in currentSymmetricDifference):
            sidewaysSpaceship = True
            break
        else:
            lastLocalDifference = currentLocalDifference.copy()
            generationsElapsed += 30
            currentSymmetricDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords())
            currentLocalDifference = frozenset(tuple(differentPoint) for differentPoint in currentSymmetricDifference if abs(differentPoint[0]+differentPoint[1]-400)<=400 and abs(differentPoint[0]-differentPoint[1])<=400)
    if sidewaysSpaceship or any(abs(differentPoint[0]-differentPoint[1])>400 for differentPoint in currentSymmetricDifference):
        return "X"        # Escaping sideways gliders (or XWSSes) render the collision unusable.
    else:
        generationsElapsed += (-generationsElapsed)%256
        removedEscapingCells = frozenset(tuple(removedCell) for removedCell in (gpseLifelib[generationsElapsed]-testBoard[generationsElapsed-timeOffset]).coords() if removedCell[0]+removedCell[1]<0)
        escapingSymmetricDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords() if differentPoint[0]+differentPoint[1]<0)        # Because of the nature of the sets, the symmetric difference could also be used.
        unaccountedRemovedCells = set(removedEscapingCells.copy())
        unaccountedEscapingDifference = set(escapingSymmetricDifference.copy())
        gliderDifferenceDict = {"created": set(), "destroyed": 0}
        normalCells = frozenset(tuple(normalCell) for normalCell in gpseLifelib[generationsElapsed].coords())
        for missingCellPosition in removedEscapingCells:        # detects missing gliders
            if missingCellPosition[0]-missingCellPosition[1]==1 and (missingCellPosition[0]+missingCellPosition[1])%128==1 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}
                unaccountedEscapingDifference ^= {missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}        # It uses the symmetric difference instead of simply a difference in case a created glider partially overlaps a removed glider.
            elif missingCellPosition[1]-missingCellPosition[0]==1 and (missingCellPosition[0]+missingCellPosition[1])%128==1 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]+1, missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]+2, missingCellPosition[1]+1)}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+1, missingCellPosition[1]), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]+2, missingCellPosition[1]+1)}
                unaccountedEscapingDifference ^= {(missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+1, missingCellPosition[1]), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]+2, missingCellPosition[1]+1)}
            elif missingCellPosition[0]==missingCellPosition[1] and (missingCellPosition[0]+missingCellPosition[1])%128==2 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]), (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0]+1, missingCellPosition[1]+1)}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]), missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0]+1, missingCellPosition[1]+1)}
                unaccountedEscapingDifference ^= {(missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]), missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0]+1, missingCellPosition[1]+1)}
            elif missingCellPosition[1]-missingCellPosition[0]==2 and (missingCellPosition[0]+missingCellPosition[1])%128==2 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), (missingCellPosition[0]+2, missingCellPosition[1])}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+2, missingCellPosition[1])}
                unaccountedEscapingDifference ^= {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+2, missingCellPosition[1])}
            elif missingCellPosition[0]==missingCellPosition[1] and (missingCellPosition[0]+missingCellPosition[1])%128==4 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1])}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1]), missingCellPosition}
                unaccountedEscapingDifference ^= {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1]), missingCellPosition}
        if bool(unaccountedRemovedCells):        # returns true if and only if the set is not empty
            print("\n")
            return "?1"        # This line reports that the program was unable to identify the difference. It probably means that the bounds for checking for either escaping spaceships or when the reaction has settled should be changed.
        else:          # There would be a line unaccountedAddedCells=unaccountedRemovedCells^unaccountedEscapingDifference (taking the symmetric difference), but it's not necessary because this section will only execute if unaccountedRemovedCells is empty, so the program can use unaccountedEscapingDifference instead of unaccountedAddedCells.
            for addedCellPosition in unaccountedEscapingDifference.copy():        # The .copy() is necessary in order to prevent modifying a set while looping through it.
                if {addedCellPosition, (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]-1, addedCellPosition[1]+2), (addedCellPosition[0]+1, addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1]-1, 4*addedCellPosition[0]-4))
                    unaccountedEscapingDifference -= {addedCellPosition, (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]-1, addedCellPosition[1]+2), (addedCellPosition[0]+1, addedCellPosition[1]+2)}
                elif {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+2, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-1))
                    unaccountedEscapingDifference -= {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+2, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)}
                elif {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+1, addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-2))
                    unaccountedEscapingDifference -= {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+1, addedCellPosition[1]+2)}
                elif {(addedCellPosition[0]-1, addedCellPosition[1]), addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-3))
                    unaccountedEscapingDifference -= {(addedCellPosition[0]-1, addedCellPosition[1]), addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)}
        if bool(unaccountedEscapingDifference):        # returns true if and only if the set is not empty
            return "?2"        # As before, this line reports that the program was unable to identify the difference and probably means that the bounds for checking for either escaping spaceships or when the reaction has settled should be changed.
        else:
            gliderDifferenceDict["backwards gliders"] = any(testCell[0]+testCell[1]>800 for testCell in testBoard[generationsElapsed-timeOffset].coords())
            return gliderDifferenceDict
        
print({(laneOffset, frozenset((generationsToWait, generationsToWait+256))):frozenset((str(test_sending_glider(laneOffset, generationsToWait)), str(test_sending_glider(laneOffset, generationsToWait+256)))) for laneOffset in range(7, 8) for generationsToWait in range(256)})
This took slightly over half of a minute to run on my computer, so the complete search (range(7, 45) instead of range(7, 8)) should take about twenty minutes. I've already started the complete search, and once it's done, we'll hopefully have the necessary information to develop a 3-GPSE RCT-based universal constructor.
By the way, during debugging, I realized that I forgot to break out of a while loop when the program detected escaping sideways spaceships. If I had remembered to do that (and fixed the bugs that would have occurred had the program gotten to them), then the program wouldn't have been as slow as I thought that it was, but I'm sure that using lifelib is faster.



Edit: After about eighteen minutes and five rounds of garbage collection, Python has returned this:
Signal reflection search results.txt
(1.13 MiB) Downloaded 157 times
Now we need to analyze it in order to find out which pairs of collisions will be the most useful. All of the complete ideas for a 3-GPSE RCT-based universal constructor here have GPSEs A and C feeding into each other, so we should focus on pairs of signal pairs that have the same lane displacement and whose time offsets add up to a multiple of eight.



Another edit: Here are the results in a format that is probably easier to work with.
signalReflectionResults.pydata.zip
(40.2 KiB) Downloaded 164 times
Now that the search is done, a 2-GPSE solution seems more plausible to me, so I'll look for that first.



Yet another edit: I ran the following program to search for signal pairs that could have worked for my 2-GPSE idea. Here is the specific code:

Code: Select all

from pickle import load
fileObject = open("signalReflectionResults.pydata", "rb")
searchResults = load(fileObject)
fileObject.close()
print(searchResults)

for laneOffset in range(7, 45):
    for generationOffset in range(256):
        relevantResult = searchResults[(laneOffset, frozenset((generationOffset, generationOffset+256)))]
        if relevantResult[0]!="X" and relevantResult[1]!="X" and relevantResult[0]!="?1" and relevantResult[1]!="?1" and relevantResult[0]!="?2" and relevantResult[1]!="?2" and relevantResult[0]["created"] and relevantResult[0]["destroyed"] and relevantResult[1]["created"] and relevantResult[1]["destroyed"] and set((createdGliderTuple[0], createdGliderTuple[1]%2) for createdGliderTuple in relevantResult[0]["created"])!=set((createdGliderTuple[0], createdGliderTuple[1]%2) for createdGliderTuple in relevantResult[1]["created"]):
            print({(laneOffset, frozenset((generationOffset, generationOffset+256))): relevantResult})
It didn't print any possibilities, which surprised me. (There were nineteen cases where the program returned a question mark, indicating that it could not completely identify the differences, but they're probably either escaping XWSSes or involve the GPSE getting destroyed, turned into a BLSE, or made to produce gliders on the other side.) However, I know that it's possible to increase the lane displacement at least a little more without destroying the GPSE, so I replaced the end of my program with the following code and ran it.

Code: Select all

for laneOffset in range(45, 50):
    for generationOffset in range(256):
        relevantResult = (test_sending_glider(laneOffset, generationOffset), test_sending_glider(laneOffset, generationOffset+256))
        if relevantResult[0]!="X" and relevantResult[1]!="X" and relevantResult[0]!="?1" and relevantResult[1]!="?1" and relevantResult[0]!="?2" and relevantResult[1]!="?2" and relevantResult[0]["created"] and relevantResult[0]["destroyed"] and relevantResult[1]["created"] and relevantResult[1]["destroyed"] and set((createdGliderTuple[0], createdGliderTuple[1]%2) for createdGliderTuple in relevantResult[0]["created"])!=set((createdGliderTuple[0], createdGliderTuple[1]%2) for createdGliderTuple in relevantResult[1]["created"]):
            print({(laneOffset, frozenset((generationOffset, generationOffset+256))): relevantResult})
This printed the following:

Code: Select all

{(48, frozenset({359, 103})): ({'created': {(206, -389), (-14, -1467)}, 'destroyed': 1, 'backwards gliders': True}, {'created': {(-54, -384)}, 'destroyed': 1, 'backwards gliders': False})}
Unforutnately, I think that glider lanes 40 half-diagonals apart will be too far apart to allow universal construction (although if they are, please let me know). Unless I'm interpreting this incorrectly, or there's a bug in my code (and I doubt that either is the case), I suspect that this means that a 2-GPSE RCT-based universal constructor, at least following the only idea for one that I've had so far, is impossible.



Fourth edit: I decided to run the program for lane displacements in range(50, 55). The program printed {(52, frozenset({185, 441})): ({'created': {(34, -467)}, 'destroyed': 2, 'backwards gliders': False}, {'created': {(149, -57)}, 'destroyed': 2, 'backwards gliders': False})}, which also doesn't seem conducive to unversal construction, but I noticed that running the program produced a lot of blank lines (including one group of over 60 in a row) in my terminal. This had happened before, but only this time did the possibility occur to me that they might be more results that didn't appear due to some bug. I think that this is unlikely, but I'd like confirmation that lifelib could do this just to make sure that we're not throwing away any perfectly valid 2-GPSE RCT-based universal constructor possibilities.
Last edited by MathAndCode on October 22nd, 2020, 10:05 am, edited 1 time in total.
I am tentatively considering myself back.

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » October 18th, 2020, 8:34 pm

No one has replied to me, so I'm just going to assume that the only idea that I've had so far for a 2-GPSE solution is impossible and start looking for signal reflections that allow 3-GPSE RCT-based universal constructors.
In order for two perpendicularly traveling gliders to collide, they must be separated by at most 4.5 cells orthogonally perpendicular to their relative velocity. However, both of these collisions result in a loaf and blinker (formed from a traffic light predecessor interacting with a block), which probably won't be very useful. At 4.25 cells of separation, the two possible 90° collisions result in a block and a kickback reaction. At 4 cells of separation, the two possible 90° collisions result in a traffic light and a ∏-heptomino. Theoretically, any of these could be useful, but it would be difficult to harness them (especially the ∏-heptomino), so they should be discarded and only returned to as a last resort. At 3.75 cells of separation, one of the two possible 90° collisions results in a ∏-heptomino, and the other vanishes after four generations (i.e. results in nothing), so 3.75 cells of separation is the maximum for a two-glider collision that results in nothing. (Of course, not all 90° two-glider collisions with 3.75 or less cells of separation will result in nothing, but I'm not doing to try to code a program that can detect that automatically for now.) In order for the collision to create a traffic light and glider, the separation perpendicular to the relative velocity of the gliders must be 1 cell, so I shall look for cases where the A₁ glider is between 2.75 cells above and 4.75 cells below an A₀ glider. Let's hope that I get useful results this time.
I am tentatively considering myself back.

wwei23

Re: Binary slow salvos

Post by wwei23 » October 18th, 2020, 9:05 pm

MathAndCode wrote:
October 18th, 2020, 8:34 pm
Let's hope that I get useful results this time.
You can do it!

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » October 18th, 2020, 9:16 pm

wwei23 wrote:
October 18th, 2020, 9:05 pm
MathAndCode wrote:
October 18th, 2020, 8:34 pm
Let's hope that I get useful results this time.
You can do it!
I know that I can write the code. The problem is that I cannot magically make GPSEs have all of the signal-reflection abilities that I want them to have.
Also, thank you for your encouragement. It brightened this otherwise monotonous task.



Edit: I have ran this code.

Code: Select all

from pickle import load
fileObject = open("signalReflectionResults.pydata", "rb")
searchResults = load(fileObject)
fileObject.close()

for laneOffset in range(7, 45):
    for generationOffset in range(256):
        relevantResult = searchResults[(laneOffset, frozenset((generationOffset, generationOffset+256)))]
        if relevantResult[0]!="X" and relevantResult[1]!="X" and relevantResult[0]!="?1" and relevantResult[1]!="?1" and relevantResult[0]!="?2" and relevantResult[1]!="?2" and ((relevantResult[0]["created"] and relevantResult[1]["destroyed"] and any((4*createdGlider[0]-createdGlider[1]+128)%256>=109 and (4*createdGlider[0]-createdGlider[1]+128)%256<=139 for createdGlider in relevantResult[0]["created"])) or (relevantResult[1]["created"] and relevantResult[0]["destroyed"] and any((4*createdGlider[0]-createdGlider[1]+128)%256>=109 and (4*createdGlider[0]-createdGlider[1]+128)%256<=139 for createdGlider in relevantResult[1]["created"]))):
            print({(laneOffset, frozenset((generationOffset, generationOffset+256))): relevantResult})
It doesn't filter out the cases where GPSE A has a valid reflection but GPSE C doesn't, but I figured that I'd wait to see how many results I got before potentially adding that. Here are the results:

Code: Select all

{(7, frozenset({430, 174})): ({'created': {(-36, -154)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({431, 175})): ({'created': {(-36, -153)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({176, 432})): ({'created': {(-36, -152)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({434, 178})): ({'created': {(-36, -150)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({179, 435})): ({'created': {(-36, -149)}, 'destroyed': 0, 'backwards gliders': False}, {'created': {(-5, -118)}, 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({436, 180})): ({'created': {(-36, -148)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({439, 183})): ({'created': {(-36, -145)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({184, 440})): ({'created': {(-36, -144)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(7, frozenset({444, 188})): ({'created': {(-36, -140)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': True})}
{(19, frozenset({326, 70})): ({'created': {(-15, -301)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(19, frozenset({72, 328})): ({'created': {(-15, -299)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(19, frozenset({74, 330})): ({'created': {(-15, -297)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(26, frozenset({302, 46})): ({'created': {(144, -1207)}, 'destroyed': 0, 'backwards gliders': True}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
{(26, frozenset({48, 304})): ({'created': {(-29, -111)}, 'destroyed': 0, 'backwards gliders': False}, {'created': set(), 'destroyed': 1, 'backwards gliders': False})}
Hopefully, at least one will prove useful.



Another edit: I just realized that the results suggest that certain lane displacements might be useful. The predominant result, with a displacement of 7, is both the smallest lane displacement where the signal gliders don't crash into the GPSE's gliders before reaching the GPSE and the only lane displacement that I investigated all of the cases for manually (the latter partially being due to the former), which explains why I was overly optimistic about a 2-GPSE solution.



Yet another edit: It would be nice to have a demonstration of this once we're done, and I've been considering which pattern to create. It should obviously require more gliders than the current lower limit for a universal constructor (currently 17) but not a lot more, and also preferably mostly from one or two directions because that should make construction easier. The pattern should also ideally be notable in its own right but also useful. I'm leaning toward a fireship because it costs eighteen gliders, all but one of which come from behind (which also means that the fireship would likely travel away from the universal constructor, which is good because it means that it can be constructed before cleanup begins without us having to worry about anything crashing into it during cleanup), is notable in and of itself because it is only the second known spaceship of that speed and is a powerful sparker, and is useful for making c/10 puffers and rakes when combined with other fireships. If the glider cost of the universal constructor is pushed low enough, the demonstration can make a copperhead instead, but I doubt that that will happen unless someone finds a three-glider synthesis of a GPSE that doesn't emit escaping gliders.



Fourth edit: Something doesn't seem right. The program outputted nine possibilities with a displacement of seven lanes, but I searched manually through all possibilities with a displacement of seven lanes, and I only found eight possibilities (and not all of them should have met the conditions). This could mean that I missed a bunch of possibilities with my manual search, or it could mean that there's a mistake somewhere in my code. I'll attempt to look into it either today or tomorrow.



Fifth edit: I made the program return the relevant RLEs for the positive results with a lane displacement of seven, and they all appear to be legitimate. I guess that I missed some when doing a manual search.
I am tentatively considering myself back.

User avatar
Hdjensofjfnen
Posts: 1750
Joined: March 15th, 2016, 6:41 pm
Location: Pacific Time

Re: Potential universal construction in 16±2 gliders

Post by Hdjensofjfnen » October 21st, 2020, 11:43 pm

calcyman wrote:
September 20th, 2020, 3:14 pm
Here's a demonstration that the 17 gliders can come from infinity whilst being synchronised so that (at generation 50000 in the pattern below) the minimum population temporarily drops to 64:

Code: Select all

x = 40758, y = 40976, rule = B3/S23
2.A$A.A$.2A414$132.A$133.A$131.3A9219$40755.A.A$40755.2A$40756.A
17$9513.A$9514.2A$9513.2A$40725.A$40725.A.A$40725.2A6168$99.A.A$
100.2A$100.A17$25131.A$25129.2A$25130.2A$131.A$129.A.A$130.2A90$
25185.A.A$25185.2A$25186.A9467$135.2A$134.A.A$136.A$25135.2A$
25134.2A$25136.A17$105.A$105.2A$104.A.A15411$126.3A$128.A$127.A18$
40728.3A$40728.A$40729.A74$25182.3A$25182.A$25183.A$187.2A$186.A.A
$188.A25$25205.2A$25204.2A$25206.A!
That pattern has given me a much better understanding of how the new 17-glider RCT works. Thanks!

Code: Select all

x = 5, y = 9, rule = B3-jqr/S01c2-in3
3bo$4bo$o2bo$2o2$2o$o2bo$4bo$3bo!

Code: Select all

x = 7, y = 5, rule = B3/S2-i3-y4i
4b3o$6bo$o3b3o$2o$bo!

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » October 22nd, 2020, 2:12 pm

I have added code to my program that searches for signal reflections conducive to a 3-GPSE RCT-based universal constructor in order to make it narrow out A₁ gliders whose collision with a B glider does not produce nothing. (I didn't add any code to account for the possibility that some collisions could produce multiple A₁ gliders that would each collide with a B glider and that some but not all of those collisions would result in nothing, but I think that that is unlikely.)

Code: Select all

import lifelib
from pickle import load
fileObject = open("signalReflectionResults.pydata", "rb")
searchResults = load(fileObject)
fileObject.close()

conwayLifeTree = lifelib.load_rules("b3s23").lifetree()
def annihilatesBGlider(createdGliderTuple):
    glidersToCollide = conwayLifeTree.pattern("bo$2o$obo!")[(4*createdGliderTuple[0]-createdGliderTuple[1]+128)%256].__or__(conwayLifeTree.pattern("bo$b2o$obo!")[128].shift(-257-createdGliderTuple[0], 1))
    glidersToCollide.pdetect_or_advance()
    return glidersToCollide.empty()

for laneOffset in range(7, 45):
    for generationOffset in range(256):
        relevantResult = searchResults[(laneOffset, frozenset((generationOffset, generationOffset+256)))]
        if relevantResult[0]!="X" and relevantResult[1]!="X" and relevantResult[0]!="?1" and relevantResult[1]!="?1" and relevantResult[0]!="?2" and relevantResult[1]!="?2" and ((relevantResult[0]["created"] and relevantResult[1]["destroyed"] and any((4*createdGlider[0]-createdGlider[1]+128)%256>=109 and (4*createdGlider[0]-createdGlider[1]+128)%256<=139 and annihilatesBGlider(createdGlider) for createdGlider in relevantResult[0]["created"])) or (relevantResult[1]["created"] and relevantResult[0]["destroyed"] and any((4*createdGlider[0]-createdGlider[1]+128)%256>=109 and (4*createdGlider[0]-createdGlider[1]+128)%256<=139 and annihilatesBGlider(createdGlider) for createdGlider in relevantResult[1]["created"]))):
            print({(laneOffset, frozenset((generationOffset, generationOffset+256))): relevantResult})
Unfortunately, the program did not print anything, indicating that no such signal reflection mechanisms work. I'll increase the number of lanes in my data then look again, but we'll likely have to try a different method in order for a 3-GPSE solution.
I am tentatively considering myself back.

wwei23

Re: Binary slow salvos

Post by wwei23 » October 22nd, 2020, 2:48 pm

You can do it!

MathAndCode
Posts: 5166
Joined: August 31st, 2020, 5:58 pm

Re: Binary slow salvos

Post by MathAndCode » October 22nd, 2020, 3:04 pm

wwei23 wrote:
October 22nd, 2020, 2:48 pm
You can do it!
I'm running the code now. Here's the program.

Code: Select all

import lifelib
from pickle import dump

conwayLifeTree = lifelib.load_rules("b3s23").lifetree()
gpseLifelib = conwayLifeTree.pattern("bo$2o$obo62$65bo$64b2o$64bobo23$171bo$170bobo2$170bo2bo$172b2o$173bo2$187bo$182b2o3bo$182b2o3bo$170b2o13b2o$172bo9b2ob2o$171b2o10bo$170b3o$170b2o$169b3obo$170bo3bo$172bo2bo$172b3o$173b2o3$203b2o$203b2o3$192bo$191bobo$191b2o2$211b2o$211b2o3$183b2o$183b2o4$129bo$128b2o77b2o$128bobo75bo2b2o7b2o$205b6o7bobo$206b2obo9bo$208bo$197bo9bo$196bobo8b3o$196bo2bo5bo3b2o$197b2o6bo2b3ob2o$191bo13bo2bo3b2o$187bo2b3o13b2o2bo2bo$185bobo3b2o15b2o2bo$185bobo20b4o$184b2obobo$185bo3b2o44b2o$186bo4b2o42b2o2$187bo5bo$224bo$187bo4bo30bobo$187bo2bo19bo12b2o30b2o$188b3o18bobo42bo2bo$209b2o44b2o4$219bo$218bobo$218b2o3$249bo$248bobo$248bo2bo$249b2o5$219b2o$218bo2bo$219b2o2$215b3o2$219bo$219bo$219bo2$221b2o$221b2o$231b3o$287b2o$286bo2bo$287b2o$240bo$240bo$240bo$251bo$250bobo$250b2o2$213b2o$213b2o66bo$280bobo$280bo2bo$281b2o4$209b2o$209b2o40b2o$250bo2bo$251b2o2$247b3o2$251bo$251bo$251bo$219b2o$218bobo32b2o$218b2o33b2o$263b3o$319b2o$318bo2bo$319b2o$272bo$272bo$272bo$283bo$282bobo$282b2o2$245b2o$245b2o66bo$312bobo$312bo2bo$313b2o4$241b2o$241b2o40b2o$282bo2bo$283b2o2$279b3o2$283bo$283bo$283bo$251b2o$250bobo32b2o$250b2o33b2o$295b3o4$304bo$304bo$304bo5$277b2o$277b2o7$273b2o$273b2o9$283b2o$282bobo$282b2o!")

def test_sending_glider(laneDisplacement, timeOffset):
    testBoard = gpseLifelib[timeOffset].__or__(conwayLifeTree.pattern("obo$b2o$bo").shift(0, 1-laneDisplacement))
    sidewaysSpaceship = False
    generationsElapsed = timeOffset + 1000
    lastLocalDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords() if abs(differentPoint[0]+differentPoint[1]-400)<=400 and abs(differentPoint[0]-differentPoint[1])<=400)
    generationsElapsed += 30
    currentSymmetricDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords())
    currentLocalDifference = frozenset(tuple(differentPoint) for differentPoint in currentSymmetricDifference if abs(differentPoint[0]+differentPoint[1]-400)<=400 and abs(differentPoint[0]-differentPoint[1])<=400)
    while currentLocalDifference != lastLocalDifference:
        if any(abs(differentPoint[0]-differentPoint[1])>400 for differentPoint in currentSymmetricDifference):
            sidewaysSpaceship = True
            break
        else:
            lastLocalDifference = currentLocalDifference.copy()
            generationsElapsed += 30
            currentSymmetricDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords())
            currentLocalDifference = frozenset(tuple(differentPoint) for differentPoint in currentSymmetricDifference if abs(differentPoint[0]+differentPoint[1]-400)<=400 and abs(differentPoint[0]-differentPoint[1])<=400)
    if sidewaysSpaceship or any(abs(differentPoint[0]-differentPoint[1])>400 for differentPoint in currentSymmetricDifference):
        return "X"        # Escaping sideways gliders (or XWSSes) render the collision unusable.
    else:
        generationsElapsed += (-generationsElapsed)%256
        removedEscapingCells = frozenset(tuple(removedCell) for removedCell in (gpseLifelib[generationsElapsed]-testBoard[generationsElapsed-timeOffset]).coords() if removedCell[0]+removedCell[1]<0)
        escapingSymmetricDifference = frozenset(tuple(differentPoint) for differentPoint in gpseLifelib[generationsElapsed].__xor__(testBoard[generationsElapsed-timeOffset]).coords() if differentPoint[0]+differentPoint[1]<0)        # Because of the nature of the sets, the symmetric difference could also be used.
        unaccountedRemovedCells = set(removedEscapingCells.copy())
        unaccountedEscapingDifference = set(escapingSymmetricDifference.copy())
        gliderDifferenceDict = {"created": set(), "destroyed": 0}
        normalCells = frozenset(tuple(normalCell) for normalCell in gpseLifelib[generationsElapsed].coords())
        for missingCellPosition in removedEscapingCells:        # detects missing gliders
            if missingCellPosition[0]-missingCellPosition[1]==1 and (missingCellPosition[0]+missingCellPosition[1])%128==1 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}
                unaccountedEscapingDifference ^= {missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]-1, missingCellPosition[1]+2), (missingCellPosition[0]+1, missingCellPosition[1]+2)}        # It uses the symmetric difference instead of simply a difference in case a created glider partially overlaps a removed glider.
            elif missingCellPosition[1]-missingCellPosition[0]==1 and (missingCellPosition[0]+missingCellPosition[1])%128==1 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]+1, missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]+2, missingCellPosition[1]+1)}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+1, missingCellPosition[1]), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]+2, missingCellPosition[1]+1)}
                unaccountedEscapingDifference ^= {(missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+1, missingCellPosition[1]), (missingCellPosition[0], missingCellPosition[1]+1), (missingCellPosition[0]+2, missingCellPosition[1]+1)}
            elif missingCellPosition[0]==missingCellPosition[1] and (missingCellPosition[0]+missingCellPosition[1])%128==2 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]), (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0]+1, missingCellPosition[1]+1)}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]), missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0]+1, missingCellPosition[1]+1)}
                unaccountedEscapingDifference ^= {(missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]), missingCellPosition, (missingCellPosition[0]-1, missingCellPosition[1]+1), (missingCellPosition[0]+1, missingCellPosition[1]+1)}
            elif missingCellPosition[1]-missingCellPosition[0]==2 and (missingCellPosition[0]+missingCellPosition[1])%128==2 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), (missingCellPosition[0]+2, missingCellPosition[1])}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+2, missingCellPosition[1])}
                unaccountedEscapingDifference ^= {(missingCellPosition[0]+1, missingCellPosition[1]-2), (missingCellPosition[0], missingCellPosition[1]-1), (missingCellPosition[0]+1, missingCellPosition[1]-1), missingCellPosition, (missingCellPosition[0]+2, missingCellPosition[1])}
            elif missingCellPosition[0]==missingCellPosition[1] and (missingCellPosition[0]+missingCellPosition[1])%128==4 and missingCellPosition in unaccountedRemovedCells and {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1])}<=normalCells:
                gliderDifferenceDict["destroyed"] += 1
                unaccountedRemovedCells -= {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1]), missingCellPosition}
                unaccountedEscapingDifference ^= {(missingCellPosition[0]-1, missingCellPosition[1]-2), (missingCellPosition[0]-2, missingCellPosition[1]-1), (missingCellPosition[0]-1, missingCellPosition[1]-1), (missingCellPosition[0]-2, missingCellPosition[1]), missingCellPosition}
        if bool(unaccountedRemovedCells):        # returns true if and only if the set is not empty
            print("\n")
            return "?1"        # This line reports that the program was unable to identify the difference. It probably means that the bounds for checking for either escaping spaceships or when the reaction has settled should be changed.
        else:          # There would be a line unaccountedAddedCells=unaccountedRemovedCells^unaccountedEscapingDifference (taking the symmetric difference), but it's not necessary because this section will only execute if unaccountedRemovedCells is empty, so the program can use unaccountedEscapingDifference instead of unaccountedAddedCells.
            for addedCellPosition in unaccountedEscapingDifference.copy():        # The .copy() is necessary in order to prevent modifying a set while looping through it.
                if {addedCellPosition, (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]-1, addedCellPosition[1]+2), (addedCellPosition[0]+1, addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1]-1, 4*addedCellPosition[0]-4))
                    unaccountedEscapingDifference -= {addedCellPosition, (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]-1, addedCellPosition[1]+2), (addedCellPosition[0]+1, addedCellPosition[1]+2)}
                elif {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+2, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-1))
                    unaccountedEscapingDifference -= {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+2, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)}
                elif {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+1, addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-2))
                    unaccountedEscapingDifference -= {addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+1), (addedCellPosition[0]+1, addedCellPosition[1]+2)}
                elif {(addedCellPosition[0]-1, addedCellPosition[1]), addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)} <= unaccountedEscapingDifference:
                    gliderDifferenceDict["created"].add((addedCellPosition[0]-addedCellPosition[1], 4*addedCellPosition[0]-3))
                    unaccountedEscapingDifference -= {(addedCellPosition[0]-1, addedCellPosition[1]), addedCellPosition, (addedCellPosition[0]+1, addedCellPosition[1]), (addedCellPosition[0]-1, addedCellPosition[1]+1), (addedCellPosition[0], addedCellPosition[1]+2)}
            if bool(unaccountedEscapingDifference):        # returns true if and only if the set is not empty
                return "?2"        # As before, this line reports that the program was unable to identify the difference and probably means that the bounds for checking for either escaping spaceships or when the reaction has settled should be changed.
            else:
                gliderDifferenceDict["backwards gliders"] = any(testCell[0]+testCell[1]>800 for testCell in testBoard[generationsElapsed-timeOffset].coords())
                return gliderDifferenceDict

fileObject = open("signalReflectionResults.pydata", "wb")
dump({(laneOffset, frozenset((generationsToWait, generationsToWait+256))):(test_sending_glider(laneOffset, generationsToWait), test_sending_glider(laneOffset, generationsToWait+256)) for laneOffset in range(7, 65) for generationsToWait in range(256)}, fileObject)
fileObject.close()


Edit: The program completed, and it still returned no solutions. I guess that I'll have to try another method.
I am tentatively considering myself back.

Post Reply