Small Four-Digit Prime Period Guns

For discussion of specific patterns or specific families of patterns, both newly-discovered and well-known.
Jormungant
Posts: 675
Joined: May 27th, 2016, 1:01 am

Re: Small Four-Digit Prime Period Guns

Post by Jormungant » June 17th, 2024, 8:49 pm

How about yet-another-family of prime guns?

Here is a p1759 glider gun:

Code: Select all

x = 139, y = 150, rule = LifeHistory
10$57.A$57.3A$49.A10.A$48.A.A8.2A$48.A.A8.4B14.A$47.2A.2A9.5B9.3A$47.
A2.B6.B.8B7.A$48.AB2AB3.12B6.2A$46.A.A.2AB.15B2.5B$46.2A2.24B$52.21B
2A$52.21B2A$53.19B.B$55.17B$54.17B$55.15B$56.13B$57.15B$57.2B2.12B$
61.12B$62.11B$60.4B.4B3DB$60.2A4.4BD2B$61.A4.2B3D2B$58.3A6.6B$58.A8.
7B$67.8B$68.8B$68.9B$67.6B.4B$67.7B.4B$68.6B2.4B$68.6B3.B2DB$68.6B4.
2D2B$67.8B4.4B$66.8B6.4B$66.9B6.4B$66.9B7.4B$65.10B8.4B$65.3B2A5B9.4B
$59.2A3.4B2A5B10.4B$60.A3.11B11.4B$60.A.A7BD4B12.4B$55.2A4.2A2.4B3DB
15.4B$56.A9.2B2D2BD4.2A10.4B$56.A.AB7.6B4.A12.4B25.A$42.2A13.2AB.3B3.
6B.BA.A13.4B23.A.A$41.B2AB14.14B.B2A15.4B22.A.A$42.2B15.16B18.4B20.2A
.3A$37.B3.2B17.14B20.4B7.2A11.B4.A$36.2AB.4B15.16B20.4B5.B2AB4.2B2.B
2AB3A$36.2A8B11.18B21.4B3.7B.6B2A.A$37.B.B2A6B2.2B2.20B9.B13.22B$40.
2A15BD15B10.B14.19B$40.17BDBD4B.7B27.19B$36.21B3D4B2.6B12.C.2C12.18B$
36.23BD4B3.6B11.2C.C11.19B$35.2A26B6.4B25.20B.2B$35.2A14B.4B12.B2A2B
9.5C11.22B2A$36.B.11B2.4B14.2A.B2A7.C4.C2.2C6.9BD3BA6B.B2A$38.10B2.4B
7.2C9.BA.A8.BCB.C2.C4.9BDBD2BABA5B2.B$39.14B8.2C4.C7.A8.B2C.C.C5.10B
2D2BA2BA5B$38.14B4.3B7.A.C6.2A5.C4B.C.2C3.16B2A5B$39.13B7.4C3.C.A12.C
BCB3.C5.2AB2.19B$39.13B6.C2.C.C.2C.AC11.C2BC2.2C4.A.AB2.20B$38.B2.7B
3DB5.C.A3.C.C2.B8.5B2C9.A4.3B.16B2A$42.7BD2B6.C.CA2C2.CB2A6.6B10.2A3.
21B2A$43.4B3D2B8.A3.C.A.2A4.8B15.10B2.7B.2B$42.10B7.A2.BA.A2.14B15.
10B2.6B$41.4B.7B5.C.2BC.A5.13B16.8B3.4B$40.4B2.8B4.2C.2BC5.15B15.4B.
2B3.2B$39.4B4.8B7.3B4.15B15.4B5.B2AB$38.4B5.9B7.4B.17B15.4B5.2A$37.4B
5.6B.32B16.4B$36.4B6.7B.5BD11B2A2B2C9B16.4B$35.4B8.6B.5B3D9B2A2BCBC9B
3.2A.A9.4B$34.4B9.12BDBD13BC6B3.B2A2.A.2A10.4B$33.4B9.15BD19B4.A2.A.A
14.4B3.3B$32.4B10.19B2.2B2.3B.6B5.3A.A15.4B$31.4B10.19B12.6B7.A17.4B
13.A$15.2A13.D3B7.B3.20B9.9B5.A6.2A11.4B10.3A$15.A.A2.2A7.D3B7.2AB.
19B2A.A7.2A4.4B4.2A4.B2AB11.4B8.A$12.A4.A3.A6.B3D8.2A19B.B2AB3A6.A5.
4B4.A5.2B13.4B7.2A$12.5A.3A6.4B10.B.3B2A12B4.B4.A2.3A7.4B3.A.AB3.2B
13.4B3.5B$16.A.A7.4B6.2A2.B.B.2B2A11B4.2A.3A3.A10.4B3.2AB.4B5.A8.4B2.
3B$12.3ABABA6.4B3.2A2.A.A6.2B2.10B5.A.A17.4B4.6B4.A.A8.9B7.2A$11.A2.A
B2A6.4B4.A.A.A2.A4.2B3.6B.B7.A.A18.4B2.2B2D4BA2.A.3A7.8B8.A$11.2A2.4B
4.5B5.BA.AB2A3.B2AB2.4B12.A20.4B2.DBD4B4A4.A7.10B3.B.A.2A$15.14B4.2AB
A7.2A3.2B2AB27.B5.7BD6B2.A.2A8.4BD2B2A2B.B3A2.A$16.2BA10B4.3BA.2A11.
2A27.2B6.8B2.B2A.2A.A9.2BDBD2B2A3BAB2.2A$16.BABA9B.4B.BABA2.A37.3B7.
6B5.A.A2.A9.3B2D7B4A$16.A2BA11B2A2B.BA2.2A36.4B6.6B4.A.A.A.A8.2AB.7B
3.2B.A$16.B2A10B.A2BA2B41.4B6.8B3.2A3.A8.A.A9B2.B3A$16.15B2A2B.BA2.2A
34.4B6.4B2.4B16.A2.7B4.A$14.2AB.11B.4B.BABA2.A33.4B6.4B4.4B14.2A.8B5.
5A$13.A.AB3.10B3.3BA.2A34.4B6.4B6.4B17.6B10.A$13.AB3.5B.7B2.2ABA36.4B
6.4B8.4B6.A8.7B8.A$12.2A2B2.2A4.6B3.BA.AB2A32.4B6.4B10.4B5.3A5.8B.B6.
2A$13.4B2.A3.7B2.A.A.A2.A31.4B6.4B12.4B7.A3.8B$14.2B3A5.B2A3B2.2A2.A.
A31.4B6.4B14.4B5.2A2.8B$15.BA2B5.B2A2B7.2A41.4B16.4B4.5B$16.B2AB3.6B
49.4B18.4B5.10B$17.BA2B2.6B48.4B20.4B2.3BD7B$18.ABAB.7B46.4B22.7BD7B$
19.2A2B.6B45.4B24.6B3D5B$20.9B45.4B26.13B$21.8B44.BD2B28.10B.B2A$22.
8B42.4B31.3B2AB3.BA.A$23.7B8.A32.4B32.3B2AB6.A$24.6B6.3A31.4B35.4B6.
2A$24.2B3D2B4.A33.4B36.3B$24.2BD4B4.2A31.4B34.AB.2B$24.B3D4B.4B4.A15.
2A8.4B34.A.AB2AB$24.11B4.3A14.B2A2B5.4B35.A.ABABAB$24.12B2.A18.4B2.6B
33.2A.A.A.A.A2.A$24.12B2.2A16.12B34.A2.A2.2A.4A$25.11B3.B15.12B37.2A
4.A$28.7B4.3B12.13B43.A.A$27.8B3.6B9.15B43.2A$26.9B2.10B6.9B2D4B$25.
23B3.11B2D4B$23.B.12BD3B2A15BD9B2A$22.2A13B2D2B2A15BDBD5B.A2BA2.2A$
22.2A14B2D18B3D4B2.ABAB3.A2.A$23.15BD21BD4B3.A4B.A.A.A$21.5B2.9BD26B
6.B2A.A2.A$21.2A6.5B5.13B.8B9.BAB.A$22.A7.2B.3B3.7B.B4.8B8.A4.A$19.3A
12.2A15.4B13.5A$19.A14.A15.4B$35.3A11.4B17.A$37.A10.4B17.A.A$47.4B19.
A$46.4B$45.4B$44.4B$43.4B$42.4B$41.4B$40.4B!
This strategy is more flexible than the h-to-g4 I used before, so it could still be useful for far larger primes.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 18th, 2024, 2:07 am

Jormungant wrote:
June 17th, 2024, 8:49 pm
This strategy is more flexible ...
No explosions, this is good.
However, with 1 variable (I hope I understood your idea correctly) this family produced only 18 guns:

Code: Select all

gun_1759:  26937 ->  16359
gun_1823:  19840 ->  16891
gun_1999:  23652 ->  18492
gun_2063:  25232 ->  19596
gun_2111:  26702 ->  20445
gun_2143:  27702 ->  21021
gun_2207:  29750 ->  22197
gun_2239:  30798 ->  22797
gun_2287:  32400 ->  23712
gun_2351:  34592 ->  24960
gun_2383:  35712 ->  25596
gun_2399:  36278 ->  25917
gun_2447:  38000 ->  26892
gun_2543:  33060 ->  28896
gun_2591:  33792 ->  29925
gun_2671:  34532 ->  31680
gun_2687:  34905 ->  32037
gun_2719:  35280 ->  32757

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace ConsoleApplication145
{
    class Pattern
    {
        public readonly int GridWidth;
        public readonly int GridHeight;
        int[,] cells;

        public Pattern(int width, int height)
        {
            GridWidth = width;
            GridHeight = height;
            cells = new int[GridWidth, GridHeight];
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.GridHeight; y++)
                for (int x = 0; x < stamp.GridWidth; x++)
                    cells[x + xo, y + yo] |= stamp.cells[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {GridWidth}, y = {GridHeight}, rule = B3/S23");
            for (int y = 0; y < GridHeight; y++)
            {
                for (int x = 0; x < GridWidth; x++)
                    sb.Append(cells[x, y] == 1 ? 'o' : 'b');
                sb.AppendLine(y == GridHeight - 1 ? "!" : "$");
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public void ReadRLE(string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";

            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                    continue;

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                cells[x, y] = c == 'o' ? 1 : 0;
                                x++;
                                WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += GridWidth;
            else if (x >= GridWidth)
                x -= GridWidth;
            if (y < 0)
                y += GridHeight;
            else if (y >= GridHeight)
                y -= GridWidth;
        }
    }

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        Program()
        {
            Pattern part1 = new Pattern(113, 133);
            Pattern part2 = new Pattern(32, 40);
            part1.ReadRLE(new string[] {
                "x = 113, y = 133, rule = B3/S23",
                "46bo$46b3o$38bo10bo$37bobo8b2o$37bobo26bo$36b2ob2o23b3o$36bo26bo$37bob",
                "2o22b2o$35bobob2o$35b2o$62b2o$62b2o11$49b2o$50bo$47b3o$47bo14$57b2o$",
                "48b2o7b2o$49bo$49bobo$44b2o4b2o$45bo20b2o$45bobo18bo41bo$31b2o13b2o16b",
                "obo40bobo$31b2o31b2o41bobo$106b2ob3o$94b2o16bo$25b2o67b2o10b2ob3o$25b",
                "2o79b2obo$29b2o$29b2o2$73bob2o$73b2obo$24b2o$24b2o32b2o11b5o33b2o$58b",
                "2o2b2o7bo4bo2b2o19bo8b2o$50b2o10bobo9bo2bo2bo18bobo$50b2o4bo7bo9b2obob",
                "o19bo2bo$55bobo6b2o5bo5bob2o19b2o$48b4o3bobo12bobo4bo5b2o$47bo2bobob2o",
                "b2o11bo2bo2b2o4bobo$46bobo3bobo16b2o9bo24b2o$47bob4o2bob2o22b2o24b2o$",
                "49bo3bobob2o$48bo3bobo$47bo3bobo$47b2o3bo$98b2o$98b2o2$60b2o2b2o$60b2o",
                "2bobo12b2obo$64bo10b2o2bob2o$74bo2bobo$75b3obo$78bo$4b2o71bo6b2o$4bobo",
                "2b2o18b2o21b2obo7b2o12b2o5b2o$bo4bo3bo18b2o21b2ob3o6bo13bo$b5ob3o25b2o",
                "21bo2b3o14bobo$5bobo17b2o8b2o15b2ob3o3bo17b2o11bo$b3obobo13b2o2bobo25b",
                "obo35bobo$o2bob2o14bobobo2bo24bobo32bo2bob3o$2o21bobob2o4b2o19bo33b4o",
                "4bo$22b2obo7b2o5b2o50bob2o$7bo17bob2o11b2o46b2ob2obo$6bobo16bobo2bo58b",
                "obo2bo$5bo2bo11b2o4bo2b2o56bobobobo$6b2o11bo2bo64b2o3bo$20b2o4bo2b2o$",
                "3b2o20bobo2bo$2bobo20bob2o$2bo19b2obo$b2o4b2o14bobob2o$8bo12bobobo2bo$",
                "5b3o6b2o5b2o2bobo$5bo8b2o9b2o$6b2o$7bo$7bobo$8b2o4$27bo$25b3o$24bo$24b",
                "2o$30bo15b2o$28b3o15b2o$27bo$27b2o6$30b2o25b2o$11b2o17b2o24bo2bo2b2o$",
                "11b2o43bobo4bo2bo$57bo5bobobo$60b2obo2bo$10b2o48bo2bo$11bo45bo4bo$8b3o",
                "12b2o32b5o$8bo14bo$24b3o32bo$26bo31bobo$59bo!"
            });
            part2.ReadRLE(new string[] {
                "x = 32, y = 40, rule = B3/S23",
                "22bo$20b3o$19bo$19b2o3$27b2o$28bo$28bob2o$20b2o4b3o2bo$20b2o3bo3b2o$",
                "25b4o$11b2o15bo$10bobo12b3o$10bo13bo$9b2o14b5o$29bo$3bo23bo$3b3o21b2o$",
                "6bo$5b2o7$15b2o$8b2o5bobo$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobobo$2obobo",
                "bobo2bo$o2bo2b2ob4o$2b2o4bo$8bobo$9b2o!"
            });

            var newGuns = new Dictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            const int mul = 2;
            const int loopDelay = 804;
            const int extraDelay = 119;

            for (int shift = 0; shift < 1000; shift++)
            {
                int period = mul * (loopDelay + shift * 8) + extraDelay;

                if (!IsPrime(period))
                    continue;
                if (period > 9999)
                    break;

                int p1x = 0;
                int p1y = 0;
                int p2x = 89 + shift;
                int p2y = 77 + shift;

                int minX = Math.Min(p1x, p2x);
                int minY = Math.Min(p1y, p2y);

                p1x -= minX;
                p2x -= minX;
                p1y -= minY;
                p2y -= minY;

                int width = 0;
                int height = 0;
                width = Math.Max(width, p1x + part1.GridWidth);
                width = Math.Max(width, p2x + part2.GridWidth);
                height = Math.Max(height, p1y + part1.GridHeight);
                height = Math.Max(height, p2y + part2.GridHeight);

                int area = width * height;

                if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                    continue;

                Pattern gun = new Pattern(width, height);
                gun.Stamp(part1, p1x, p1y);
                gun.Stamp(part2, p2x, p2y);
                newGuns[period] = gun;
                newGunsCosts[period] = area;
            }

            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                Console.WriteLine($"gun_{period}: {costS} -> {area,6}");
                gun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » June 18th, 2024, 3:38 am

Vort wrote:
June 18th, 2024, 2:07 am
Jormungant wrote:
June 17th, 2024, 8:49 pm
This strategy is more flexible ...
No explosions, this is good.
However, with 1 variable (I hope I understood your idea correctly) this family produced only 18 guns:
[...]
There is additional flexibility in that it is possible to replace the 2x pulse divider. For example, here is a p2579 glider gun in 168-by-145 (down from 169-by-185). Two out of three pulses are absorbed; third pulse is split into two gliders, one of which is sent to the beehive factory, and the other becomes the output glider of the gun.

Code: Select all

#C [[ MAXGRIDSIZE 9 KILLGLIDERS THEME LifeHistory ]]
x = 168, y = 145, rule = B3/S23
87b2o$87bobo$89bo4b2o$85b4ob2o2bo2bo$85bo2bobobobob2o$88bobobobo$89b2o
bobo$93bo2$79b2o$49bo30bo7b2o$48bobo29bobo5b2o$48bobo7b2o21b2o$46b3ob
2o6b2o49bo$45bo19b2o40b3o$46b3ob2o13b2o39bo$48bob2o54b2o3$91b2o21b2o$
61bo29bo23bo$60bobo29b3o20bob2o$59bo2bo31bo12b2o4b3o2bo$60b2o9b2o34b2o
3bo3b2o$71b2o39b4o37bo$98b2o15bo35b3o$87bo9bobo12b3o35bo$49b2o35bobo8b
o13bo31bo6b2o$49b2o35bob3o5b2o14b5o25bobo$85b2o4bo24bo26bo$84bo3b2o2bo
21bo$85b3ob3o22b2o32b2o$87bo60b2o5b2o$87bob3o63b2o$86b2obo2bo$91b2o$
138b2o$80b2o56b2o$63b2o15b2o$63bo23b2o64b2o$64b3o8b2o9bo2bo63bobo$66bo
9bo10b2o66bo$59b2obo12bo7b2o70b2o$59bob2o12b4o5bo$79bob3o$60b5o12b2ob
2o$55b2o2bo4bo11bobo$55bo2bo2bo14bobo$56bobob2o15bo$55b2obo5bo$58bo4bo
bo$58b2o2bo2bo$63b2o$113bo$111b3o$44bo65bo$4b2o38b3o63b2o$5bo41bo14bo
78bo$5bobo38b2o12b3o18b2o58b3o$6b2o2b2o47bo21bobo60bo14bo$10b2o47b2o
22bo59b2o12b3o7bo$74b2o7b2o71bo8bobo$74b2o80b2o8b2o$58b2o$39b2o17b2o4b
ob2o15bo$39b2o21b3ob2o14bobo23b2o45b2o$61bo20bobo23b2o26b2o17b2o$62b3o
b2o13b2ob3o49b2o$64b2o2bo18bo$67bobo11b2ob3o$51b2o11b3obobo10b2obo22b
2o$42b2o6bobo7b2obo2bo2bo37b2o$22b2o19bo6bo9b2ob2obo$2b2o18bobo15b3o7b
obo10bo2b2o71b2o$bobo20bo15bo12bo9bobo2bobo48b2o19bo$bo22b2o19b2o4bobo
10bobo2b2o48bobo15b3o$2o44bo6bo11bo55bo15bo$43b3o8bo66b2o19b2o$43bo60b
2o37bo$105bo34b3o$102b3o35bo$88b2o12bo$5bob2o79b2o$3b3ob2o$2bo155b2o$
3b3ob2o149bobo$5b2o2bo73b2o75bo$8b2o73b2o75b2o$87b2o52b2o9b2o8bo$87b2o
51bobo2b2o5b2o6b3o$46b2o91bo2bobobo12bo$46b2o91b2obobo14b2o4b2o$52b2o
27b2o59bob2o19bo$52b2o27b2o56b2obo20bobo$137bo2bobo20b2o$137b2o2bo4b2o
$50b2o93bo2bo11b2o$50b2o5b2o78b2o2bo4b2o11bo2bo$57b2o78bo2bobo16bobo$
139b2obo17bo$142bob2o$139b2obobo21b2o$139bo2bobobo14b2obo2bo$140bobo2b
2o13bobob3o$141b2o17bobo$158b3ob5o$157bo3bo4bo$157b2o2bobo$162b2o$128b
2o$128bo3b2o$124b2o4bo2bo$119b2o3b2o3b4o$113bob2obobo$113b2obobo10b2o$
100bo16b2o10bobo$100b3o27b2o$103bo$102b2o4$122b2o$121bo2bo$122b2o3$96b
2o35b2o$96b2o27bo7bobo$124bobo8bo$125bobob2o4b2o$123bobobobobo$107b2o
10b2o2b2obo4bo$106bo2bo8bobo5bob3o$107bobo9bo6bobo$108bo18bo4$95bob2o$
93b3ob2o13b2o$92bo19b2o$93b3ob2o6b2o$95b2o2bo5b2o$98b2o!
edit: gun_2579 processed in jobs/7123031375.
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.

Jormungant
Posts: 675
Joined: May 27th, 2016, 1:01 am

Re: Small Four-Digit Prime Period Guns

Post by Jormungant » June 18th, 2024, 8:38 am

Indeed, that's what I meant by more flexible, though there is also a way to not have to worry about period multipliers with multiple outputs:

P3463 prime gun:

Code: Select all

x = 143, y = 147, rule = LifeHistory
7$60.A$60.3A$52.A10.A$51.A.A8.2A$51.A.A8.4B14.A$50.2A.2A9.5B9.3A$50.A
2.B6.B.8B7.A$51.AB2AB3.12B6.2A$49.A.A.2AB.15B2.5B$49.2A2.24B$55.21B2A
$55.21B2A$56.19B.B$58.17B$57.17B$58.15B$59.13B$60.15B$60.2B2.12B$64.
12B$65.11B$63.4B.4B3DB$63.2A4.4BD2B$64.A4.2B3D2B$61.3A6.6B$61.A8.7B$
70.8B$71.8B$71.9B$70.6B.4B$70.7B.4B25.A$71.6B2.4B23.A.A$71.6B3.4B22.A
.A$71.6B3.5B20.2A.3A$70.8B3.5B7.2A11.B4.A$69.8B5.5B5.B2AB4.2B2.B2AB3A
$69.9B5.5B3.7B.6B2A.A$69.9B6.23B$68.10B7.20B$68.3B2A5B8.20B$62.2A3.4B
2A5B9.19B36.B$63.A3.11B9.19B35.2B$63.A.A7BD4B8.20B.2B31.3B$58.2A4.2A
2.4B3DB10.22B2A29.4B$59.A9.2B2D2BD4.2A4.9BD3BA6B.B2A28.4B$59.A.AB7.6B
4.A3.9BDBD2BABA5B2.B28.4B$45.2A13.2AB.3B3.6B.BA.A3.10B2D2BA2BA5B29.4B
$44.B2AB14.14B.B2A3.16B2A5B29.4B$45.2B15.16B4.2AB2.19B28.4B$40.B3.2B
17.14B4.A.AB2.20B26.4B$39.2AB.4B15.16B3.A4.3B.16B2A2.A21.4B$39.2A8B
11.18B2.2A3.21B2A2.3A18.4B$40.B.B2A6B2.2B2.20B8.10B2.7B.2B6.A16.4B$
43.2A15BD15B9.10B2.6B9.2A15.4B$43.17BDBD4B.7B12.8B3.4B10.5B11.4B$39.
21B3D4B2.6B12.4B.2B3.2B15.4B9.4B$39.23BD4B3.6B11.4B5.B2AB12.7B7.4B$
38.2A26B6.4B12.4B5.2A13.10B3.4B$38.2A14B.4B12.B2A2B13.4B18.12B.4B$39.
B.11B2.4B14.2A.B2A12.4B15.18B$41.10B2.4B7.2C9.BA.A12.4B14.17B$42.14B
8.2C4.C7.A8.C4.4B12.17B$41.14B4.3B7.A.C6.2A5.3C5.4B10.17B$42.13B7.4C
3.C.A12.CB8.4B8.19B$42.13B6.C2.C.C.2C.AC11.2CB8.4B7.18B$41.B2.7B3DB5.
C.A3.C.C2.B8.6B10.4B5.19B$45.7BD2B6.C.CA2C2.CB2A6.6B12.4B3.19B$46.4B
3D2B8.A3.C.A.2A4.8B13.4B.5B2A11B$30.2A13.10B7.A2.BA.A2.14B14.9B2A10B$
30.A13.4B.7B5.C.2BC.A5.13B14.20B$25.2A5.A10.4B2.8B4.2C.2BC5.15B14.3BD
16B$25.A5.2A9.4B4.8B7.3B4.15B14.BDBD16B$22.2A.A.3B11.4B5.9B7.4B.17B
12.3B2D13B.B$22.A2.A.2A2B2A7.4B5.6B.32B9.B.20B$24.2A.A.2B2AB5.4B6.7B.
5BD11B2A2B2C9B7.2A20B$27.A.4B5.4B8.6B.5B3D9B2A2BCBC9B6.2A22B$27.2A.4B
3.4B9.12BDBD13BC6B3.B2A6.20B.2A$20.2A8.10B9.15BD19B4.A2.A5.2B.18BA$
19.A.A8.9B10.19B2.2B2.3B.6B5.2A.A7.4B.9B5.3A$19.A8.B.8B10.19B12.6B7.A
6.4B3.8B7.A$16.2A.AB.B3.11B7.B3.20B9.9B6.2A4.4B5.8B$17.A.A.2AB.7BD4B
6.2AB.19B2A.A7.2A4.4B10.6B3.10B13.A$17.A.A.2A9BDBD2B6.2A19B.B2AB3A6.A
5.4B8.6B3.7B.4B10.3A$16.2A.A2.5B2A3B2D3B7.B.3B2A12B4.B4.A2.3A7.4B6.6B
3.4B.2B3.4B8.A$16.A2.4A3BA2BA5B.B2A4.B.B.2B2A11B4.2A.3A3.A10.4B4.6B3.
2C2B2.4B2.4B3.3B.2A$17.2A2.BAB.2B2A6B.BA.A8.2B2.10B5.A.A17.4B2.6B3.CB
CB5.2A3.4B2.6B$19.2A6.7B5.A7.2B3.6B.B7.A.A18.10B3.BC2B6.A5.9B$19.A7.
2B.4B5.2A5.B2AB2.4B12.A20.8B3.B2CB8.3A3.9B7.2A$21.A9.4B12.2A3.2B2AB
33.3D3B3.4B11.A4.8B8.A$20.2A10.4B18.2A33.3BD3B2.4B18.10B3.B.A.2A$33.
4B51.3BD4B.4B19.4BD2B2A2B.B3A2.A$34.5B48.10B23.2BDBD2B2A3BAB2.2A$35.
5B46.12B22.3B2D7B4A$36.5B44.8B2.4B19.2AB.7B3.2B.A$37.5B42.8B4.4B17.A.
A9B2.B3A$38.5B40.8B6.4B16.A2.7B4.A$39.5B38.8B8.4B14.2A.8B5.5A$40.5B
36.8B10.4B17.6B10.A$41.5B24.A9.4B3.B12.4B6.A10.4B9.A$42.4B24.3A6.4B
18.4B5.3A5.10B6.2A$43.4B26.A4.4B20.4B7.A3.8B.B$44.4B24.2A3.4B22.4B5.
2A2.8B$45.4B23.8B24.4B4.9B$46.4B18.2A4.5B26.4B5.10B$47.4B16.A.BAB.5B
6.2B20.4B2.3BD7B$48.4B15.A.2AB2.12B21.7BD7B$49.4B9.A.2A.A.B.B3.13B20.
6B3D5B$50.4B8.2A.A.A.2A2B2.13B21.13B$51.4B10.A2.A2.AB.14B3.2A17.10B.B
2A$52.4B9.A3.2ABA17B2.A19.3B2AB3.BA.A$53.4B9.3A2.A6B2A11B.A.2A16.3B2A
B6.A$54.4B11.A2.6B2A9B.3A2.A18.4B6.2A$55.4B7.3A3.17BAB2.2A19.3B$56.4B
5.A7.5B2A6B.2B4A18.AB.2B$57.4B4.2A5.6B2A3B4.4B.A17.A.AB2AB$58.9B4.12B
6.2A.A.A15.A.ABABAB$59.6B5.4B.8B7.A2.2A12.2A.A.A.A.A2.A$59.4BD3B2.4B
3.7B5.A.A16.A2.A2.2A.4A$57.7BD7B5.5B6.2A19.2A4.A$57.5B3D6B6.5B33.A.A$
57.13B7.2A2B35.2A$55.2AB.10B7.2BA3B$54.A.AB3.B2A4B8.A.A.A.A$54.A6.B2A
3B7.3ABA.2A.A$53.2A6.4B8.A5.A3.A$62.3B9.A.2A.A3.2A$63.2B.BA7.2A.A$62.
B2ABA.A$61.BABABA.A$59.A2.A.A.A.A.2A$59.4A.2A2.A2.A$63.A4.2A$61.A.A$
61.2A!
this describes a P ((836+8X)*Y + 119) gun family, because that off loop has a quadri-snark in there (Y=4), but one can alter to main loop to change the base the base 836 to something else, but the usual shift of the snark pair trombone gives that +8X family. since Y can be defined with chained quadri-snark, like the original reset guns, that can be used in a similar fashion, now the question is if that is more compact, I am not sure I found the best way here, it is comparable to previous stategy, but fitting that g-to-h-to-g in the middle of the loop felt constraining, now it is a g0-to-g that takes slightly less space.

addendum: the more general question is if there are more circuits that if overclocked with a specific delay, causes only the first signal to go through, and either A- the second signal is cleanly removed, B- leaves some still life that will supress the following "first" signal or C- deflect the second signal into a different path. The main contraint for prime guns is that the h-to-g0 needs odd differences in delays, sadly it is mostly even for the one in the collection, that being said, there is are 2 ways to engineer almost all odd delays deltas:

Code: Select all

x = 210, y = 92, rule = LifeHistory
8$59.2A$57.2B2AB$57.4B$56.4B$57.4B$57.5B$55.7B$45.2A7.8B$46.A7.9B$46.
A.AB3.12B75.2A$47.2AB2.13B3.B59.A5.A.2A.A2.A$49.20B57.B.3A3.2A.A.2A.A
$49.21B56.2B3.A7.B2.A.A$49.20B55.2A3B.2A6.2ABA.2A$50.18B57.A9B3.2A.A
13.2A$46.B.7B12.B57.A.A3B.8B.A13.A.A$45.2AB.6B12.B58.2A12B.2A13.AB$
45.2A8B12.B60.13B14.2B$46.B.7B12.B60.B2A10B12.5B$48.7B12.3B58.A2BA9B
11.7B$48.7B12.3B58.BABA10B9.8B3.BA$48.7B12.3B58.2BA11B10.8B.BA.A$48.
7B12.3B59.11B.B2A9.10BA$48.11B.11B56.4B4.5B.BA.A7.9B.B$48.10B3.12B52.
3B2AB5.3BD4.A6.9B$47.10B5.6BA5B47.2A.A.A2.A7.DBDB3.2A5.9B$47.10B5.5BA
BA3B48.A.2A.3A9.2D2B10.8B$39.2A6.10B7.3B2A4B52.A13.4B7.11B$40.A7.9B8.
B2.4B53.A.2A11.4B2.16B$40.A.AB4.9B.2B4.3B59.A.A12.21B$41.2AB.14B2A3.B
2AB74.20B$43.16B2A4.2A76.20B.B$43.14B.2B84.20B2A$44.13B86.19B.B2A$43.
14B.2B81.20B3.B$41.18B2A80.2BCB.13B$39.18B.B2A79.3BCBC14B$39.2BC15B2.
B81.2B3C13B$38.3BCBC4B.8B83.5BC13B8.2A$39.2B3C4B2.7B82.10B2.8B8.A2.2A
$38.5BC4B2.7B81.4B9.11B6.A.A$37.10B3.7B81.3B9.13B.B2.2A2.A$36.4B11.7B
78.4B10.14B2A3.2A$35.4B12.7B78.2A11.13B.BA.3A$34.4B13.6B80.A10.13B.3B
AB2.2A$18.A.A12.4B15.5B77.3A11.18BAB.A$17.A.2A11.4B14.6B78.A13.15B.3B
A.A$17.A13.4B15.6B92.16B2.2A.2A$13.A.2A.3A9.4B16.4B95.15B$13.2A.A.A2.
A7.4B3.2A12.2B2AB96.14B$17.3B2AB5.4B4.A15.2A96.6B2.B3.4B$19.4B4.5B.BA
.A112.2AB2AB2.3B3.4B$21.11B.B2A113.A3.A3.B2AB3.4B$20.2BA11B116.3A5.2A
5.4B$20.BABA10B114.A.A15.4B$20.A2BA9B115.2A12.2A3.4B$20.B2A10B130.A4.
4B$20.13B130.A.A3.4B$18.2AB.10B.2A129.2A4.4B$17.A.AB3.8B.A137.4B$17.A
4.5B3.2A.A138.4B$16.2A4.2A6.2ABA.2A136.4B$23.A7.B2.A.A137.4B$20.3A3.
2A.A.2A.A140.4B$20.A5.A.2A.A2.A141.4B$32.2A143.4B$178.4B$179.3B$180.
2B$181.B!
(note that the 180 degree reflector can add +4X delays, since it can be flipped)

some examples with that novel g-to-h:

Code: Select all

x = 296, y = 164, rule = LifeHistory
$26.2A$14.A5.A.2A.A2.A$14.3A3.2A.A.2A.A$17.A7.B2.A.A$10.2A4.2A6.2ABA.
2A$11.A4.5B3.2A.A$11.A.AB3.8B.A$12.2AB.10B.2A$14.13B$14.B2A10B$14.A2B
A9B$14.BABA10B$14.2BA11B$15.11B.B2A$13.4B4.5B.BA.A$11.3B2AB5.4B4.A$7.
2A.A.A2.A7.4B3.2A$7.A.2A.3A9.4B$11.A13.4B$11.A.2A11.4B$12.A.A12.4B$
28.4B$29.4B$30.4B$31.4B$32.4B184.2A$33.4B20.2A149.A5.A.2A.A2.A$34.4B
17.2B2AB148.3A3.2A.A.2A.A$35.4B16.4B152.A7.B2.A.A$36.4B15.6B143.2A4.
2A6.2ABA.2A$37.4B14.6B144.A4.5B3.2A.A$38.4B15.5B143.A.AB3.8B.A$39.4B
13.6B144.2AB.10B.2A$40.4B12.7B145.13B$41.4B11.7B145.B2A10B$42.10B3.7B
146.A2BA9B$43.B4.C4B2.7B146.BABA10B$44.B.3C4B2.7B146.2BA11B$43.2B.C.C
4B.8B147.11B.B2A$44.2BC15B2.B142.4B4.5B.BA.A$44.18B.B2A139.3B2AB5.4B
4.A$46.18B2A135.2A.A.A2.A7.4B3.2A$48.14B.2B136.A.2A.3A9.4B$49.13B143.
A13.4B$48.14B.2B140.A.2A11.4B$48.16B2A4.2A134.A.A12.4B$46.2AB.14B2A3.
B2AB149.4B$45.A.AB4.9B.2B4.3B151.4B20.2A$45.A7.9B8.B2.4B147.4B17.2B2A
B$44.2A6.10B7.3B2A4B147.4B16.4B$52.10B5.5BABA3B148.4B15.6B$52.10B5.6B
A5B148.4B14.6B$53.10B3.12B150.4B15.5B$53.11B.11B153.4B13.6B$53.22B
155.4B12.7B$53.22B156.4B11.7B$53.22B157.10B3.7B$53.22B158.B4.C4B2.7B$
51.B.20B161.B.3C4B2.7B$50.2A21B160.2B.C.C4B.8B$50.2AB.19B161.2BC15B2.
B$51.B.20B161.18B.B2A$55.16B165.18B2A$54.17B167.14B.2B$54.17B168.13B$
54.18B166.14B.2B$52.2AB2.13B168.16B2A4.2A$51.A.AB3.12B166.2AB.14B2A3.
B2AB$51.A7.9B8.C.C156.A.AB4.9B.2B4.3B$50.2A7.8B10.2C156.A7.9B8.B2.4B$
60.7B5.A4.C156.2A6.10B7.3B2A4B$62.5B175.10B5.5BABA3B$62.4B176.10B5.6B
A5B$61.4B79.2B97.10B3.12B$62.4B78.BCB96.11B.11B$62.2B2AB77.2B2C95.22B
$64.2A79.2C96.22B16.2A.A$243.22B12.2A.A2.2A$243.22B12.A3.A$241.B.20B
16.2A.2A.A$240.2A21B8.2A2.4A.A.A.2A$240.2AB.19B8.A2.A.A2.3B$241.B.20B
9.A.A.3B.B$245.18B10.A.A6B3.2A$244.20B10.AB.2B2AB3.A$244.20B13.2B2A6.
A$244.20B12.5B2.5A$242.2AB2.13B3.B12.7BA$241.A.AB3.12B11.B3.7B4.2A$
241.A7.9B7.BCBC4B2.7B4.A$240.2A7.8B9.B2C5B.6B2.BA.A$250.7B5.A4.C14B.B
2A$252.5B11.16B6.A$252.4B13.15B4.3A$104.C14.A46.C14.A69.4B14.15B3.A$
103.2BC11.3A45.2BC11.3A70.4B10.2B.17B.2A$103.3CB9.A48.3CB9.A73.2B2AB
8.2A22B$104.4B8.2A48.4B8.2A74.2A9.2AB.18B$100.2A3.4B4.5B3.2A39.2A3.4B
4.5B3.2A81.B.20B$101.A4.4B2.4B5.A41.A4.4B2.4B5.A85.18B.B$101.A.AB.5B.
5B.BA.A41.A.AB.5B.5B.BA.A86.20B$102.2AB.11B.B2A43.2AB.11B.B2A87.21B$
104.15B47.15B90.20B$104.15B47.15B91.5B2C12B$99.2A5.13B42.2A5.13B91.5B
2C12B$100.A5.13B43.A5.13B92.19B$95.A4.A.AB.16B5.2A29.A4.A.AB.16B5.2A
84.13B$95.3A3.2AB.17B4.A30.3A3.2AB.17B4.A86.12B$98.A4.10B2A7B.BA.A33.
A4.10B2A7B.BA.A86.12B$97.2AB2.11B2A7B.B2A33.2AB2.11B2A7B.B2A88.11B$
97.27B35.27B91.10B$99.25B37.25B92.9B$97.27B35.27B92.9B$97.25B37.25B
96.7B$96.2A20B2.4B34.2A20B2.4B95.6B$96.2A11B.5B.B5.2A34.2A11B.5B.B5.
2A96.5B$97.B.9B2.5B7.A36.B.9B2.5B7.A97.5B$100.9B.4B9.3A36.9B.4B9.3A
92.2AB.2B$100.5B2A2B.5B10.A36.5B2A2B.5B10.A91.A.AB$102.3B2AB4.B.2A48.
3B2AB4.B.2A101.A$103.6B5.A50.6B5.A101.2A$103.6B6.3A47.6B6.3A$102.7B9.
A45.7B9.A$102.6B7.3A46.6B7.3A$103.6B4.3A49.6B4.3A$103.6B3.A52.6B3.A$
102.7B2.A.A50.7B2.A.A$112.A61.A2$103.3D59.3D$105.D4.2A55.D4.2A$104.3D
3.2A54.3D3.2A4$105.2C60.2C$105.2C60.2C!
Last edited by Jormungant on June 18th, 2024, 12:55 pm, edited 1 time in total.

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » June 18th, 2024, 11:30 am

Another way is to insert another pulse divider in the track before the x2, instead of replacing the x2. Two examples:
gun_8719 in 172-by-147 (down from 189-by-161), by combining the stable x5 pulse divider and the same 2H-to-G pulse divider sending alternate output gliders in opposite directions on the same lane:

Code: Select all

#C [[ MAXGRIDSIZE 9 KILLGLIDERS THEME LifeHistory ]]
x = 172, y = 147, rule = B3/S23
81bo$79b3o$78bo10bo$78b2o8bobo$61bo26bobo$61b3o23b2ob2o$64bo26bo$63b2o
22b2obo$87b2obobo$91b2o$64b2o$64b2o11$77b2o$77bo$78b3o$80bo14$69b2o$
69b2o7b2o$78bo$76bobo$76b2o4b2o$60b2o20bo$19bo41bo18bobo$18bobo40bobo
16b2o13b2o$18bobo41b2o31b2o$16b3ob2o$15bo16b2o$16b3ob2o10b2o67b2o$18bo
b2o79b2o$97b2o$97b2o2$51b2obo$51bob2o$102b2o$17b2o33b5o11b2o32b2o$17b
2o8bo19b2o2bo4bo7b2o2b2o$26bobo18bo2bo2bo9bobo10b2o$25bo2bo19bobob2o9b
o7bo4b2o$26b2o19b2obo5bo5b2o6bobo$43b2o5bo4bobo12bobo3b4o$43bobo4b2o2b
o2bo11b2ob2obobo2bo$19b2o24bo9b2o16bobo3bobo$19b2o24b2o22b2obo2b4obo$
69b2obobo3bo$73bobo3bo$74bobo3bo$75bo3b2o$28b2o33bobo$28b2o33b2o2bo$
66b3o3$51b2o$45b2o3bo2bo$45bobobob2o$47bobo$42b2o2b2obo$42b2o5b2o12b2o
7bob2o21b2o$49bo13bo6b3ob2o21b2o$47bobo14b3o2bo21b2o$9bo25bo11b2o17bo
3b3ob2o15b2o$9b3o22bobo35bobo$12bo19b3obo2bo32bobo$11b2o18bo4b4o33bo
19b2o$32b2obo50b2o5b2o$33bob2ob2o46b2o$3b2o28bo2bobo$3bo30bobobobo4b2o
$2obo31bo3b2o3bobo$o2b3o4b2o34bo$b2o3bo3b2o$3b4o$3bo15b2o$4b3o12bobo$
7bo13bo$2b5o14b2o$2bo$4bo23bo88b2o2bo$3b2o21b3o88bo3b3o$25bo92bo5bo$
25b2o92bo3b2o$107b2obob2o6bo$106bo2b2obo2bob3o$91bo13bobo4bob2obo$91b
3o12bob5o$94bo13bo4bob2o$93b2o12bo3bobob2o$15b2o89bo3bobo$14bobo5b2o
82b2o3bo$14bo7b2o$13b2o$83b2o$27bo55b2o$23b2obobo89b2o38bo$22bobobobo
89b2o36b3o$19bo2bobobobob2o101b2o20bo$19b4ob2o2bo2bo100bo2bo19b2o$23bo
4b2o103b2obobo$21bobo54b2o56bob3o$21b2o55b2o56bo4bo25b2o$72b2o47b2o12b
2o3b2o25bo$67b2o2bo2bo47bo35bo5bo3b3o$64bo2bo4bobo18b2o24b3o35bobo4b4o
3bo$63bobobo5bo19b2o11b2o11bo23b2o12b2o10bobo$64bo2bob2o35bo35bo2bo20b
2ob2o$67bo2bo36b3o33b2o21b2o$68bo4bo35bo59b2o$69b5o96bo$169bo$71bo78b
2o17b2o$70bobo78bo$71bo76b3o$148bo11b2o5b2o$159bo2bo4bobo$155b2o3bobo
6bo$151b2obobo4bo7b2o$152bobo9b2o$151bo2b2o8bo$152b2o11b3o$154b2o11bo$
103bo50bo$104bo50bo$102b3o49b2o!
And here's a p30671 glider gun (a five-digit prime number) with bounding box 143-by-122, using the (7+6n)G-to-H pulse divider instead of the x5. Other periods can be obtained by adjusting trombone slides and/or the pulse-division coefficient; however, I do not see an obvious way to adjust this arrangement to a four-digit period:

Code: Select all

#C [[ MAXGRIDSIZE 9 KILLGLIDERS THEME LifeHistory ]]
x = 143, y = 122, rule = B3/S23
74bo$72b3o$71bo10bo$71b2o8bobo$54bo26bobo$54b3o23b2ob2o$57bo26bo$56b2o
22b2obo$80b2obobo$84b2o$57b2o$57b2o11$70b2o$70bo$71b3o$73bo14$62b2o$
62b2o7b2o$71bo$69bobo$69b2o4b2o$53b2o20bo$12bo41bo18bobo$11bobo40bobo
16b2o13b2o$11bobo41b2o31b2o$9b3ob2o$8bo4bo11b2o$9b5o11b2o67b2o$11bobo
80b2o$90b2o$90b2o2$44b2obo$44bob2o$95b2o$10b2o33b5o11b2o32b2o$10b2o8bo
19b2o2bo4bo7b2o2b2o$19bobo18bo2bo2bo9bobo10b2o$18bo2bo19bobob2o9bo7bo
4b2o$19b2o19b2obo5bo5b2o6bobo$36b2o5bo4bobo12bobo3b4o$36bobo4b2o2bo2bo
11b2ob2obobo2bo$12b2o24bo9b2o16bobo3bobo$12b2o24b2o22b2obo2b4obo$62b2o
bobo3bo$66bobo3bo$67bobo3bo$68bo3b2o$21b2o$21b2o$109bo$59b2o47bobo$59b
2o47bobo$24bobo17b2o61b2ob2o$9bo14b2o12b2o3bo2bo$9b3o13bo12bobobob2o
61b2ob4o$12bo27bobo64b2obo2bo$11b2o22b2o2b2obo70bobo$35b2o5b2o12b2o7bo
b2o21b2o2b2o16b2ob3o$42bo13bo6b3ob2o21b2o2b2o22bo$3b2o35bobo14b3o2bo
21b2o26b2ob3o$3bo24bo11b2o17bo3b3ob2o15b2o26b2obo$2obo23bobo35bobo$o2b
3o4b2o13b3obo2bo32bobo51b2o$b2o3bo3b2o12bo4b4o33bo19b2o31bo$3b4o18b2ob
o50b2o5b2o29bobo$3bo15b2o5bob2ob2o33bo12b2o13b2o21b2o4b2o$4b3o12bobo4b
o2bobo34b3o25bo27bobo$7bo13bo5bobobobo35bo22bobo27bo$2b5o14b2o5bo3b2o
34b2o22b2o27b2o$2bo$4bo23bo108b2o$3b2o21b3o81b2o25bo$25bo83bo2bo22bobo
$26bo31b2o50b2o23b2o$22bo3bo31b2o$21bo$20bo5bo111b2o$19bo3bo3bo71b2o
36bobo$19bo2bobo2bo71b2o36bo$19bo3bo3bo108b2o$15b2o3bo5bo26b2o$14bobo
4bo3bo27b2o84b2o$14bo7b3o22b2o91bo$13b2o27b2o2bo2bo66b2o19b3o$39bo2bo
4bobo18b2o32b2o13bo19bo$27bo10bobobo5bo19b2o11b2o20bo10b3o21b2o$23b2ob
obo10bo2bob2o35bo21bobo8bo24bo$22bobobobo13bo2bo36b3o19b2o22b2o5b2o2bo
b2o$19bo2bobobobob2o11bo4bo35bo42bo2bo4bobobob2o$19b4ob2o2bo2bo12b5o
74b2o3bobo6bobo$23bo4b2o92bobo4bo7bobo$21bobo22bo75bo9b2o4bo$21b2o22bo
bo72bob2o8bo$46bo72bobo11b3o$119bo2b2o11bo$71bo48bobo$72bo46b2o2bo$70b
3o49b2o!
edit: gun_3463 (134-by-123 from post187894), gun_8719 (172-by-147) submitted and processed in jobs/7128443902.
Last edited by confocaloid on June 19th, 2024, 10:30 pm, edited 1 time in total.
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 18th, 2024, 1:31 pm

Jormungant wrote:
June 18th, 2024, 8:38 am
this describes a P ((836+8X)*Y + 119) gun family
It have similar problem to exploding guns before:
Some combinations of variables produce incorrectly working guns.

This time gun always start working correcty after some stabilization time, but if I upload it "as is", Catagolue will reject it.
Instead of trying to find a way to always produce perfect gun, I made changes to my code to "normalize" gun before writing it to file.

Normalization works horribly slow right now (~10 sec for gun validation/normalization), either I made some mistake or code just needs to be optimized.
With small changes, this code will also allow to filter gun family with occasional explosions, to prevent Catagolue from clogging.

Here is the log from recent batch:

Code: Select all

gun_1091:        ->  19044
gun_1123:        ->  20164
gun_1163:        ->  21609
gun_1187:        ->  22500
gun_1259:        ->  25281
gun_1283:        ->  26244
gun_1291:        ->  26569
gun_1307:        ->  27225
gun_1427:        ->  32400
gun_1451:        ->  33489
gun_1459:        ->  33856
gun_1483:        ->  34969
gun_1499:        ->  35721
gun_1523:        ->  36864
gun_1531:        ->  37249
gun_1579:        ->  39601
gun_1627:        ->  42025
gun_2579:  24360 ->  16214
gun_2699:  32697 ->  16884
gun_2843:  24138 ->  17688
gun_2939:  24624 ->  18224
gun_2963:  24633 ->  18495
gun_3011:  24955 ->  19043
gun_3083:  25434 ->  19880
gun_3203:  26404 ->  21315
gun_3251:  26730 ->  21903
gun_3299:  27388 ->  22499
gun_3323:  27552 ->  22800
gun_3347:  27720 ->  23103
gun_3371:  28220 ->  23408
gun_3467:  29237 ->  24648
gun_3491:  29410 ->  24963
gun_3539:  29754 ->  25599
gun_3659:  31325 ->  27224
gun_1759:  16359 ->  15946
gun_1823:  16891 ->  16482
gun_1999:  18492 ->  17956
gun_2063:  19596 ->  19044
gun_2111:  20445 ->  19881
gun_2143:  21021 ->  20449
gun_2207:  22197 ->  21609
gun_2239:  22797 ->  22201
gun_2287:  23712 ->  23104
gun_2351:  24960 ->  24336
gun_2383:  25596 ->  24964
gun_2399:  25917 ->  25281
gun_2447:  26892 ->  26244
gun_2543:  28896 ->  28224
gun_2591:  29925 ->  29241
gun_2671:  31680 ->  30976
gun_2687:  32037 ->  31329
gun_2719:  32757 ->  32041
gun_5039:  23667 ->  16214
gun_5087:  24287 ->  16348
gun_5231:  24272 ->  16750
gun_5279:  24900 ->  16884
gun_5471:  25857 ->  17420
gun_5519:  25872 ->  17554
gun_5711:  27360 ->  18090
gun_5807:  28199 ->  18495
gun_5903:  28884 ->  19043
gun_6047:  30260 ->  19880
gun_6143:  31140 ->  20448
gun_6287:  32040 ->  21315
gun_6719:  36099 ->  24024
gun_6863:  37044 ->  24963
gun_6911:  37824 ->  25280
gun_6959:  38009 ->  25599
gun_7103:  31584 ->  26568
gun_7151:  32300 ->  26895
gun_7247:  32661 ->  27555
gun_7487:  32661 ->  29240
gun_3463:  16482 ->  16214
gun_3527:  30621 ->  16482
gun_3559:  31150 ->  16616
gun_3623:  32220 ->  16884
gun_3719:  22484 ->  17286
gun_3847:  23079 ->  17822
gun_3911:  23068 ->  18225
gun_3943:  23373 ->  18496
gun_4007:  23360 ->  19044
gun_4231:  24585 ->  21025
gun_4327:  25384 ->  21904
gun_4391:  26040 ->  22500
gun_4423:  26364 ->  22801
gun_4519:  27360 ->  23716
gun_6679:  35530 ->  16214
gun_6871:  37240 ->  16616
gun_7127:  32661 ->  17152
gun_7639:  26878 ->  18224
gun_7703:  26492 ->  18495
gun_8087:  27816 ->  20163
gun_8599:  30268 ->  22499
gun_8663:  30240 ->  22800
gun_9239:  33540 ->  25599
gun_9431:  34672 ->  26568
gun_9623:  35820 ->  27555
And here is the program:

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace ConsoleApplication145
{
    class Pattern : IEquatable<Pattern>
    {
        public readonly int Width;
        public readonly int Height;
        byte[,] cells;

        public Pattern(int width, int height)
        {
            Width = width;
            Height = height;
            cells = new byte[Width, Height];
        }

        public Pattern(int width, int height, Pattern source, int offsetX, int offsetY)
        {
            Width = width;
            Height = height;
            cells = new byte[Width, Height];
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    cells[x, y] = source.cells[x + offsetX, y + offsetY];
        }

        public Pattern Advance()
        {
            var result = new Pattern(Width, Height);
            for (int y = 0; y < Height; y++)
            {
                int ym1 = y - 1;
                int yp1 = y + 1;
                if (ym1 < 0)
                    ym1 = Height - 1;
                else if (ym1 >= Height)
                    ym1 = 0;
                if (yp1 < 0)
                    yp1 = Height - 1;
                else if (yp1 >= Height)
                    yp1 = 0;
                for (int x = 0; x < Width; x++)
                {
                    int xm1 = x - 1;
                    int xp1 = x + 1;
                    if (xm1 < 0)
                        xm1 = Width - 1;
                    else if (xm1 >= Width)
                        xm1 = 0;
                    if (xp1 < 0)
                        xp1 = Width - 1;
                    else if (xp1 >= Width)
                        xp1 = 0;
                    int neighbours =
                        cells[xm1, ym1] +
                        cells[x, ym1] +
                        cells[xp1, ym1] +
                        cells[xm1, y] +
                        cells[xp1, y] +
                        cells[xm1, yp1] +
                        cells[x, yp1] +
                        cells[xp1, yp1];

                    if (cells[x, y] == 1)
                        result.cells[x, y] = (neighbours == 2 || neighbours == 3) ? (byte)1 : (byte)0;
                    else
                        result.cells[x, y] = neighbours == 3 ? (byte)1 : (byte)0;
                }
            }
            return result;
        }

        public void Clear(int startX, int startY, int countX, int countY)
        {
            for (int y = 0; y < countY; y++)
                for (int x = 0; x < countX; x++)
                    cells[x + startX, y + startY] = 0;
        }

        public bool Search(Pattern pattern, int startX, int startY, int countX, int countY)
        {
            for (int y1 = 0; y1 < countY; y1++)
            {
                for (int x1 = 0; x1 < countX; x1++)
                {
                    bool found = true;
                    for (int y2 = 0; y2 < pattern.Height; y2++)
                    {
                        for (int x2 = 0; x2 < pattern.Width; x2++)
                        {
                            if (cells[startX + x1 + x2, startY + y1 + y2] != pattern.cells[x2, y2])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (!found)
                            break;
                    }
                    if (found)
                        return true;
                }
            }
            return false;
        }

        public Pattern NormalizeGun(int period)
        {
            Pattern gliderTop1 = new Pattern(3, 3);
            Pattern gliderTop2 = new Pattern(3, 3);
            Pattern gliderBottom1 = new Pattern(3, 3); 
            Pattern gliderBottom2 = new Pattern(3, 3);
            Pattern gliderLeft1 = new Pattern(3, 3);
            Pattern gliderLeft2 = new Pattern(3, 3);
            Pattern gliderRight1 = new Pattern(3, 3);
            Pattern gliderRight2 = new Pattern(3, 3);
            gliderTop1.ReadRLE(new string[] { "3o$2bo$bo!" });
            gliderTop2.ReadRLE(new string[] { "3o$o$bo!" });
            gliderBottom1.ReadRLE(new string[] { "bo$2bo$3o!" });
            gliderBottom2.ReadRLE(new string[] { "bo$o$3o!" });
            gliderLeft1.ReadRLE(new string[] { "2o$obo$o!" });
            gliderLeft2.ReadRLE(new string[] { "o$obo$2o!" });
            gliderRight1.ReadRLE(new string[] { "2bo$obo$b2o!" });
            gliderRight2.ReadRLE(new string[] { "b2o$obo$2bo!" });

            Pattern expanded = new Pattern(Width + 6, Height + 6);
            expanded.Stamp(this, 3, 3);

            int gliderTick = int.MaxValue;
            var latestGenerations = new List<Pattern>();
            for (int tick = 0; tick < 5 * period; tick++)
            {
                bool gliderFound =
                    expanded.Search(gliderTop1, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderTop2, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderBottom1, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderBottom2, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderLeft1, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderLeft2, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight1, Width + 3, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight2, Width + 3, 0, 1, Height + 4);
                if (gliderFound)
                {
                    expanded.Clear(0, 0, expanded.Width, 3);
                    expanded.Clear(0, Height + 3, expanded.Width, 3);
                    expanded.Clear(0, 0, 3, expanded.Height);
                    expanded.Clear(Width + 3, 0, 3, expanded.Height);
                    if (tick - gliderTick == period)
                        return new Pattern(Width, Height, latestGenerations[0], 3, 3);
                    else
                        gliderTick = tick;
                }
                latestGenerations.Add(expanded);
                if (latestGenerations.Count > 12)
                    latestGenerations.RemoveAt(0);
                expanded = expanded.Advance();
            }
            return null;
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.Height; y++)
                for (int x = 0; x < stamp.Width; x++)
                    cells[x + xo, y + yo] |= stamp.cells[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {Width}, y = {Height}, rule = B3/S23");
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                    sb.Append(cells[x, y] == 1 ? 'o' : 'b');
                sb.AppendLine(y == Height - 1 ? "!" : "$");
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public void ReadRLE(string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";

            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                    continue;

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                cells[x, y] = c == 'o' ? (byte)1 : (byte)0;
                                x++;
                                WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        public override int GetHashCode()
        {
            int shift = 0;
            int hash = Width << 16 | Height;
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                {
                    hash = hash ^ cells[x, y] << shift;
                    shift = (shift + 1) & 31;
                }
            return hash;
        }

        public bool Equals(Pattern other)
        {
            if (Width != other.Width || Height != other.Height)
                return false;
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    if (cells[x, y] != other.cells[x, y])
                        return false;
            return true;
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += Width;
            else if (x >= Width)
                x -= Width;
            if (y < 0)
                y += Height;
            else if (y >= Height)
                y -= Width;
        }
    }

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        Program()
        {
            Pattern part1 = new Pattern(84, 123);
            Pattern part2 = new Pattern(32, 40);
            Pattern part31 = new Pattern(19, 23);
            Pattern part32 = new Pattern(21, 23);
            Pattern part33 = new Pattern(18, 25);
            Pattern part41 = new Pattern(23, 19);
            Pattern part42 = new Pattern(23, 21);
            Pattern part43 = new Pattern(25, 18);
            Pattern part44 = new Pattern(25, 22);
            part1.ReadRLE(new string[] {
                "x = 84, y = 123, rule = B3/S23",
                "22bo$22b3o$14bo10bo$13bobo8b2o$13bobo26bo$12b2ob2o23b3o$12bo26bo$13bob",
                "2o22b2o$11bobob2o$11b2o$38b2o$38b2o11$25b2o$26bo$23b3o$23bo5$69bo$68bo",
                "bo$68bobo$67b2ob3o$55b2o16bo$55b2o10b2ob3o$67b2obo3$33b2o$24b2o7b2o$",
                "25bo$25bobo$20b2o4b2o42b2o$21bo20b2o17bo8b2o$21bobo18bo17bobo$7b2o13b",
                "2o16bobo17bo2bo$7b2o31b2o19b2o$44b2o$43bobo$b2o40bo24b2o2bo$b2o39b2o",
                "24b2o2b3o$5b2o68bo$5b2o67b2o3$59b2o$2o57b2o$2o32b2o$34b2o2b2o$26b2o10b",
                "obo$26b2o4bo7bo8bo$31bobo6b2o5b3o$24b4o3bobo12bo$23bo2bobob2ob2o11b2o$",
                "22bobo3bobo$23bob4o2bob2o$25bo3bobob2o35b2o$24bo3bobo39b2o$23bo3bobo$",
                "23b2o3bo4$36b2o2b2o16b2o$36b2o2bobo15b2o$40bo10b2o27b2o$50bo2bo26bo$",
                "51b2obo26b3o$54bo28bo$54b2o$5b2o21b2obo7b2o$5b2o21b2ob3o6bo$11b2o21bo",
                "2b3o$11b2o15b2ob3o3bo27b2o$29bobo32bobo6b2o$29bobo32bo8bo$9b2o19bo32b",
                "2o9b3o$9b2o5b2o58bo$16b2o5$36bo$36b3o$39bo$38b2o2$34b2o$30b2obo2bo$30b",
                "2obob2o$33bo$33bob2o$34bo2bo19b2o$35b2obo19bo$32b3o2bo6b2o12bob2o$32bo",
                "2bo8b2o10b3o2bo$33b2o20bo3b2o$44b2o9b4o$44b2o12bo$55b2obobo$56bo2b2o$",
                "54bobo$54b2o2$43b2o$44bo$42bobobobo$40b3obob2obo$39bo5bo3bo$40bob2obo",
                "3b2o$41b2obo!"
            });
            part2.ReadRLE(new string[] {
                "x = 32, y = 40, rule = B3/S23",
                "22bo$20b3o$19bo$19b2o3$27b2o$28bo$28bob2o$20b2o4b3o2bo$20b2o3bo3b2o$",
                "25b4o$11b2o15bo$10bobo12b3o$10bo13bo$9b2o14b5o$29bo$3bo23bo$3b3o21b2o$",
                "6bo$5b2o7$15b2o$8b2o5bobo$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobobo$2obobo",
                "bobo2bo$o2bo2b2ob4o$2b2o4bo$8bobo$9b2o!"
            });
            part31.ReadRLE(new string[] {
                "x = 19, y = 23, rule = B3/S23",
                "15bo$13b3o$12bo$12b2o7$2b2o$bobo5b2o$bo7b2o$2o2$14bo$10b2obobo$9bobobo",
                "bo$6bo2bobobobob2o$6b4ob2o2bo2bo$10bo4b2o$8bobo$8b2o!"
            });
            part32.ReadRLE(new string[] {
                "x = 21, y = 23, rule = B3/S23",
                "19bo$17b3o$16bo$16b2o5$2b2ob2o$o2bob2o$2o$13b2o$5bo2bo4b2o$5b4o$2bo$2b",
                "5o11bo$6bo7b2obobo$4bo8bobobobo$4b2o4bo2bobobob2o$10b4ob2o2bo$14bo4bo$",
                "10b2o2bob3o$10b2o3b2o!"
            });
            part33.ReadRLE(new string[] {
                "x = 18, y = 25, rule = B3/S23",
                "15bo$13b3o$12bo$12b2o7$2b2o$bobo8bo$bo9bobo$2o9bobo$12bo4$9b2ob2o$5b2o",
                "2b2obo3b2o$5bo6bobo2bo$6b7ob2o$13bo$8b4obo$8bo2b2o!"
            });
            part41.ReadRLE(new string[] {
                "x = 23, y = 19, rule = B3/S23",
                "9bo$9b3o$12bo$11b2o3$3b2o$3bo$2obo$o2b3o4b2o$b2o3bo3b2o$3b4o$3bo15b2o$",
                "4b3o12bobo$7bo13bo$2b5o14b2o$2bo$4bo$3b2o!"
            });
            part42.ReadRLE(new string[] {
                "x = 23, y = 21, rule = B3/S23",
                "12b2o$12bo$7b2o5bo$7bo5b2o$4b2obo$4bo2bob2o2b2o$6b2obo3b2o$9bo$9b2o2$",
                "2ob2o$2obo$3bo$3b3o4b2o$b2o3bo3b2o$o2b4o$2obo15b2o$bo2b3o12bobo$bo5bo",
                "13bo$2b5o14b2o$4bo!"
            });
            part43.ReadRLE(new string[] {
                "x = 25, y = 18, rule = B3/S23",
                "11bo$11b3o$14bo$13b2o2$4b2o$3bobo$3bo$2obo$bobob2o$bobob2o3b2o$2obo6b",
                "2o$o2b4o14b2o$b2o3bo14bobo$3b2o18bo$3bo19b2o$5bo$4b2o!"
            });
            part44.ReadRLE(new string[] {
                "x = 25, y = 22, rule = B3/S23",
                "14b2o$14bo$9b2o5bo$9bo5b2o$6b2obo$6bo2bob2o2b2o$8b2obo3b2o$11bo$11b2o$",
                "4b2o$3bobo$3bo$2obo$bobob2o$bobob2o$2obo7b2o$o2b4o3bo2bo7b2o$b2o3bo4b",
                "2o8bobo$3b2o18bo$3bo19b2o$5bo$4b2o!"
            });
            var newGuns = new Dictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            const int loopDelay = 820;
            const int extraDelay = 119;

            for (int mul3 = 1; mul3 < 4; mul3++)
            {
                for (int mul4 = 1; mul4 < 5; mul4++)
                {
                    int mul = mul3 * mul4;
                    for (int shift = 0; shift < 1000; shift++)
                    {
                        int period = mul * (loopDelay + shift * 8) + extraDelay;

                        if (!IsPrime(period))
                            continue;
                        if (period > 9999)
                            break;

                        int p1x = 0;
                        int p1y = 0;
                        int p2x = 67 + shift;
                        int p2y = 79 + shift;
                        int p3x;
                        int p3y;
                        if (mul3 == 1)
                        {
                            p3x = 15;
                            p3y = 111;
                        }
                        else if (mul3 == 2)
                        {
                            p3x = 11;
                            p3y = 111;
                        }
                        else if (mul3 == 3)
                        {
                            p3x = 15;
                            p3y = 111;
                        }
                        else
                            throw new Exception();
                        int p4x;
                        int p4y;
                        if (mul4 == 1)
                        {
                            p4x = -20;
                            p4y = 72;
                        }
                        else if (mul4 == 2)
                        {
                            p4x = -20;
                            p4y = 68;
                        }
                        else if (mul4 == 3)
                        {
                            p4x = -22;
                            p4y = 72;
                        }
                        else if (mul4 == 4)
                        {
                            p4x = -22;
                            p4y = 68;
                        }
                        else
                            throw new Exception();

                        int minX = Math.Min(p1x, Math.Min(p2x, Math.Min(p3x, p4x)));
                        int minY = Math.Min(p1y, Math.Min(p2y, Math.Min(p3y, p4y)));

                        p1x -= minX;
                        p2x -= minX;
                        p3x -= minX;
                        p4x -= minX;
                        p1y -= minY;
                        p2y -= minY;
                        p3y -= minY;
                        p4y -= minY;

                        Pattern part3 = mul3 == 1 ? part31 :
                            (mul3 == 2 ? part32 : part33);
                        Pattern part4 = mul4 == 1 ? part41 :
                            (mul4 == 2 ? part42 : (mul4 == 3 ? part43 : part44));

                        int width = 0;
                        int height = 0;
                        width = Math.Max(width, p1x + part1.Width);
                        width = Math.Max(width, p2x + part2.Width);
                        width = Math.Max(width, p3x + part3.Width);
                        width = Math.Max(width, p4x + part4.Width);
                        height = Math.Max(height, p1y + part1.Height);
                        height = Math.Max(height, p2y + part2.Height);
                        height = Math.Max(height, p3y + part3.Height);
                        height = Math.Max(height, p4y + part4.Height);

                        int area = width * height;

                        if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                            continue;

                        Pattern gun = new Pattern(width, height);
                        gun.Stamp(part1, p1x, p1y);
                        gun.Stamp(part2, p2x, p2y);
                        gun.Stamp(part3, p3x, p3y);
                        gun.Stamp(part4, p4x, p4y);
                        newGuns[period] = gun;
                        newGunsCosts[period] = area;
                    }
                }
            }
            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                Pattern normalizedGun = gun.NormalizeGun(period);
                if (normalizedGun == null)
                    throw new Exception();
                Console.WriteLine($"gun_{period}: {costS} -> {area,6}");
                normalizedGun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}
upd. Added small code optimization.
upd2. Forgot about x9 (3*3) multiplier.

Jormungant
Posts: 675
Joined: May 27th, 2016, 1:01 am

Re: Small Four-Digit Prime Period Guns

Post by Jormungant » June 18th, 2024, 6:15 pm

Vort wrote:
June 18th, 2024, 1:31 pm
Jormungant wrote:
June 18th, 2024, 8:38 am
this describes a P ((836+8X)*Y + 119) gun family
It have similar problem to exploding guns before:
Some combinations of variables produce incorrectly working guns.
Yes... either the hive stopper or the g0-to-g that leaves a hive behind can interact incorrectly with gliders on the loop, the "off loop" part can be modified to be slower get produce the same period (it has no influence on the period, just on whether is blows up or not, or a different non-prime period if it deletes the wrong glider in the pair separated by 119 ticks.

for example, the P3463 prime gun I posted earlier would explode if I did not add attach a g-to-g component to a snark, that just slows it down by 34 ticks, (no influence on the period):

Code: Select all

x = 372, y = 173, rule = LifeHistory
19$267.A$267.3A$259.A10.A$46.A211.A.A8.2A$46.3A209.A.A8.4B14.A$38.A
10.A207.2A.2A9.5B9.3A$37.A.A8.2A207.A2.B6.B.8B7.A$37.A.A8.4B14.A191.A
B2AB3.12B6.2A$36.2A.2A9.5B9.3A189.A.A.2AB.15B2.5B$36.A2.B6.B.8B7.A
192.2A2.24B$37.AB2AB3.12B6.2A197.21B2A$35.A.A.2AB.15B2.5B197.21B2A$
35.2A2.24B200.19B.B$41.21B2A201.17B$41.21B2A200.17B$42.19B.B202.15B$
44.17B205.13B$43.17B207.15B$44.15B208.2B2.12B$45.13B213.12B$46.15B
211.11B$46.2B2.12B208.4B.4B3DB$50.12B208.2A4.4BD2B$51.11B209.A4.2B3D
2B$49.4B.4B3DB206.3A6.6B$49.2A4.4BD2B206.A8.7B$50.A4.2B3D2B215.8B$47.
3A6.6B216.8B$47.A8.7B215.9B$56.8B213.6B.4B$57.8B212.7B.4B25.A$57.9B
212.6B2.4B23.A.A$56.6B.4B211.6B3.4B22.A.A$56.7B.4B25.A184.6B3.5B20.2A
.3A$57.6B2.4B23.A.A182.8B3.5B7.2A11.B4.A$57.6B3.4B22.A.A181.8B5.5B5.B
2AB4.2B2.B2AB3A$57.6B3.5B20.2A.3A179.9B5.5B3.7B.6B2A.A$56.8B3.5B7.2A
11.B4.A178.9B6.23B$55.8B5.5B5.B2AB4.2B2.B2AB3A178.10B7.20B$55.9B5.5B
3.7B.6B2A.A180.3B2A5B8.20B$55.9B6.23B176.2A3.4B2A5B9.19B36.B$54.10B7.
20B179.A3.11B9.19B35.2B$54.3B2A5B8.20B178.A.A7BD4B8.20B.2B31.3B$48.2A
3.4B2A5B9.19B36.B136.2A4.2A2.4B3DB10.22B2A29.4B$49.A3.11B9.19B35.2B
137.A9.2B2D2BD4.2A4.9BD3BA6B.B2A28.4B$49.A.A7BD4B8.20B.2B31.3B137.A.A
B7.6B4.A3.9BDBD2BABA5B2.B28.4B$44.2A4.2A2.4B3DB10.22B2A29.4B123.2A13.
2AB.3B3.6B.BA.A3.10B2D2BA2BA5B29.4B$45.A9.2B2D2BD4.2A4.9BD3BA6B.B2A
28.4B123.B2AB14.14B.B2A3.16B2A5B29.4B$45.A.AB7.6B4.A3.9BDBD2BABA5B2.B
28.4B125.2B15.16B4.2AB2.19B28.4B$31.2A13.2AB.3B3.6B.BA.A3.10B2D2BA2BA
5B29.4B121.B3.2B17.14B4.A.AB2.20B26.4B$30.B2AB14.14B.B2A3.16B2A5B29.
4B121.2AB.4B15.16B3.A4.3B.16B2A2.A21.4B$31.2B15.16B4.2AB2.19B28.4B
122.2A8B11.18B2.2A3.21B2A2.3A18.4B$26.B3.2B17.14B4.A.AB2.20B26.4B124.
B.B2A6B2.2B2.20B8.10B2.7B.2B6.A16.4B$25.2AB.4B15.16B3.A4.3B.16B2A2.A
21.4B128.2A15BD15B9.10B2.6B9.2A15.4B$25.2A8B11.18B2.2A3.21B2A2.3A18.
4B129.17BDBD4B.7B12.8B3.4B10.5B11.4B$26.B.B2A6B2.2B2.20B8.10B2.7B.2B
6.A16.4B126.21B3D4B2.6B12.4B.2B3.2B15.4B9.4B$29.2A15BD15B9.10B2.6B9.
2A15.4B127.23BD4B3.6B11.4B5.B2AB12.7B7.4B$29.17BDBD4B.7B12.8B3.4B10.
5B11.4B127.2A26B6.4B12.4B5.2A13.10B3.4B$25.21B3D4B2.6B12.4B.2B3.2B15.
4B9.4B128.2A14B.4B12.B2A2B13.4B18.12B.4B$25.23BD4B3.6B11.4B5.B2AB12.
7B7.4B130.B.11B2.4B14.2A.B2A12.4B15.18B$24.2A26B6.4B12.4B5.2A13.10B3.
4B133.10B2.4B7.2C9.BA.A12.4B14.17B$24.2A14B.4B12.B2A2B13.4B18.12B.4B
135.14B8.2C4.C7.A8.C4.4B12.17B$25.B.11B2.4B14.2A.B2A12.4B15.18B135.
14B4.3B7.A.C6.2A5.3C5.4B10.17B$27.10B2.4B7.2C9.BA.A12.4B14.17B137.13B
7.4C3.C.A12.CB8.4B8.19B$28.14B8.2C4.C7.A8.C4.4B12.17B138.13B6.C2.C.C.
2C.AC11.2CB8.4B7.18B$27.14B4.3B7.A.C6.2A5.3C5.4B10.17B138.B2.7B3DB5.C
.A3.C.C2.B8.6B10.4B5.19B$28.13B7.4C3.C.A12.CB8.4B8.19B141.7BD2B6.C.CA
2C2.CB2A6.6B12.4B3.19B$28.13B6.C2.C.C.2C.AC11.2CB8.4B7.18B143.4B3D2B
8.A3.C.A.2A4.8B13.4B.5B2A11B$27.B2.7B3DB5.C.A3.C.C2.B8.6B10.4B5.19B
127.2A13.10B7.A2.BA.A2.14B14.9B2A10B$31.7BD2B6.C.CA2C2.CB2A6.6B12.4B
3.19B128.A13.4B.7B5.C.2BC.A5.13B14.20B$32.4B3D2B8.A3.C.A.2A4.8B13.4B.
5B2A11B125.2A5.A10.4B2.8B4.2C.2BC5.15B14.3BD16B$16.2A13.10B7.A2.BA.A
2.14B14.9B2A10B126.A5.2A9.4B4.8B7.3B4.15B14.BDBD16B$16.A13.4B.7B5.C.
2BC.A5.13B14.20B123.2A.A.3B11.4B5.9B7.4B.17B12.3B2D13B.B$11.2A5.A10.
4B2.8B4.2C.2BC5.15B14.3BD16B122.A2.A.2A2B2A7.4B5.6B.32B9.B.20B$11.A5.
2A9.4B4.8B7.3B4.15B14.BDBD16B124.2A.A.2B2AB5.4B6.7B.5BD11B2A2B2C9B7.
2A20B$8.2A.A.3B11.4B5.9B7.4B.17B12.3B2D13B.B128.A.4B5.4B8.6B.5B3D9B2A
2BCBC9B6.2A22B$8.A2.A.2A2B2A7.4B5.6B.32B9.B.20B129.2A.4B3.4B9.12BDBD
13BC6B3.B2A6.20B.2A$10.2A.A.2B2AB5.4B6.7B.5BD11B2A2B2C9B7.2A20B123.2A
8.10B9.15BD19B4.A2.A5.2B.18BA$13.A.4B5.4B8.6B.5B3D9B2A2BCBC9B6.2A22B
120.A.A8.9B10.19B2.2B2.3B.6B5.2A.A7.4B.9B5.3A$13.2A.4B3.4B9.12BDBD13B
C6B3.B2A6.20B.2A120.A8.B.8B10.19B12.6B7.A6.4B3.8B7.A$6.2A8.10B9.15BD
19B4.A2.A5.2B.18BA118.2A.AB.B3.11B7.B3.20B9.9B6.2A4.4B5.8B$5.A.A8.9B
10.19B2.2B2.3B.6B5.2A.A7.4B.9B5.3A116.A.A.2AB.7BD4B6.2AB.19B2A.A7.2A
4.4B10.6B3.10B13.A$5.A8.B.8B10.19B12.6B7.A6.4B3.8B7.A116.A.A.2A9BDBD
2B6.2A19B.B2AB3A6.A5.4B8.6B3.7B.4B10.3A$2.2A.AB.B3.11B7.B3.20B9.9B6.
2A4.4B5.8B122.2A.A2.5B2A3B2D3B7.B.3B2A12B4.B4.A2.3A7.4B6.6B3.4B.2B3.
4B8.A$3.A.A.2AB.7BD4B6.2AB.19B2A.A7.2A4.4B10.6B3.10B13.A107.A2.4A3BA
2BA5B.B2A4.B.B.2B2A11B4.2A.3A3.A10.4B4.6B3.2C2B2.4B2.4B3.3B.2A$3.A.A.
2A9BDBD2B6.2A19B.B2AB3A6.A5.4B8.6B3.7B.4B10.3A108.2A2.BAB.2B2A6B.BA.A
8.2B2.10B5.A.A17.4B2.6B3.CBCB5.2A3.4B2.6B$2.2A.A2.5B2A3B2D3B7.B.3B2A
12B4.B4.A2.3A7.4B6.6B3.4B.2B3.4B8.A113.2A6.7B5.A7.2B3.6B.B7.A.A18.10B
3.BC2B6.A5.9B$2.A2.4A3BA2BA5B.B2A4.B.B.2B2A11B4.2A.3A3.A10.4B4.6B3.2C
2B2.4B2.4B3.3B.2A112.A7.2B.4B5.2A5.B2AB2.4B12.A20.8B3.B2CB8.3A3.9B7.
2A$3.2A2.BAB.2B2A6B.BA.A8.2B2.10B5.A.A17.4B2.6B3.CBCB5.2A3.4B2.6B114.
A9.4B12.2A3.2B2AB33.3D3B3.4B11.A4.8B8.A$5.2A6.7B5.A7.2B3.6B.B7.A.A18.
10B3.BC2B6.A5.9B115.2A10.4B18.2A33.3BD3B2.4B18.10B3.B.A.2A$5.A7.2B.4B
5.2A5.B2AB2.4B12.A20.8B3.B2CB8.3A3.9B7.2A118.4B51.3BD4B.4B19.4BD2B2A
2B.B3A2.A$7.A9.4B12.2A3.2B2AB33.3D3B3.4B11.A4.8B8.A119.5B48.10B23.2BD
BD2B2A3BAB2.2A$6.2A10.4B18.2A33.3BD3B2.4B18.10B3.B.A.2A117.5B46.12B
22.3B2D7B4A$19.4B51.3BD4B.4B19.4BD2B2A2B.B3A2.A118.5B44.8B2.4B19.2AB.
7B3.2B.A$20.5B48.10B23.2BDBD2B2A3BAB2.2A120.5B42.8B4.4B17.A.A9B2.B3A$
21.5B46.12B22.3B2D7B4A123.5B40.8B6.4B16.A2.7B4.A$22.5B51.B2.4B19.2AB.
7B3.2B.A124.5B38.8B8.4B14.2A.8B5.5A$23.5B54.4B17.A.A9B2.B3A126.5B36.
8B10.4B17.6B10.A$24.5B54.4B16.A2.7B4.A130.5B24.A9.4B3.B12.4B6.A10.4B
9.A$25.5B54.4B14.2A.8B5.5A126.4B24.3A6.4B18.4B5.3A5.10B6.2A$26.5B54.
4B17.6B10.A127.4B26.A4.4B20.4B7.A3.8B.B$27.5B54.4B6.A10.4B9.A130.4B
24.2A3.4B22.4B5.2A2.8B$28.4B55.4B5.3A5.10B6.2A130.4B23.8B24.4B4.9B$
29.4B55.4B7.A3.8B.B140.4B18.2A4.5B26.4B5.10B$30.4B55.4B5.2A2.8B144.4B
16.A.BAB.5B6.2B20.4B2.3BD7B$31.4B55.4B4.9B148.4B15.A.2AB2.12B21.7BD7B
$32.4B55.4B5.10B146.4B9.A.2A.A.B.B3.13B20.6B3D5B$33.4B55.4B2.3BD7B
148.4B8.2A.A.A.2A2B2.13B21.13B$34.4B55.7BD7B150.4B10.A2.A2.AB.14B3.2A
17.10B.B2A$35.4B55.6B3D5B151.4B9.A3.2ABA17B2.A19.3B2AB3.BA.A$36.4B55.
13B152.4B9.3A2.A6B2A11B.A.2A16.3B2AB6.A$37.4B55.10B.B2A151.4B11.A2.6B
2A9B.3A2.A18.4B6.2A$38.4B5.A50.3B2AB3.BA.A151.4B7.3A3.17BAB2.2A19.3B$
39.4B4.2A5.B43.3B2AB6.A152.4B5.A7.5B2A6B.2B4A18.AB.2B$40.9B4.2B45.4B
6.2A152.4B4.2A5.6B2A3B4.4B.A17.A.AB2AB$41.6B5.3B45.3B162.9B4.12B6.2A.
A.A15.A.ABABAB$41.4BD3B2.4B42.AB.2B164.6B5.4B.8B7.A2.2A12.2A.A.A.A.A
2.A$39.7BD7B42.A.AB2AB163.4BD3B2.4B3.7B5.A.A16.A2.A2.2A.4A$39.5B3D6B
43.A.ABABAB160.7BD7B5.5B6.2A19.2A4.A$39.13B41.2A.A.A.A.A2.A158.5B3D6B
6.5B33.A.A$37.2AB.10B42.A2.A2.2A.4A158.13B7.2A2B35.2A$36.A.AB3.B2A4B
45.2A4.A160.2AB.10B7.2BA3B$36.A6.B2A3B52.A.A157.A.AB3.B2A4B8.A.A.A.A$
35.2A6.4B55.2A157.A6.B2A3B7.3ABA.2A.A$44.3B213.2A6.4B8.A5.A3.A$45.2B.
BA219.3B9.A.2A.A3.2A$44.B2ABA.A219.2B.BA7.2A.A$43.BABABA.A218.B2ABA.A
$41.A2.A.A.A.A.2A214.BABABA.A$41.4A.2A2.A2.A212.A2.A.A.A.A.2A$45.A4.
2A214.4A.2A2.A2.A$43.A.A224.A4.2A$43.2A223.A.A$268.2A!
basically, one can push away diagonally that "off loop" bit, there exist a range of offsets for gun where it work as intended, but that depends on the component you used to define Y, and the location of the glider are intercepted (before the trombone bit is in sync, after it is not.)

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 19th, 2024, 2:21 am

Having non-exploding guns is important for lowering maximum area line.
However families with occasional explosions are valuable as well, because of optimization potential.
They will leave spikes on maximum area line, but will allow for deeper "cut".

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 19th, 2024, 11:14 am

After my first failure with gun_3593 family, I decided to test different approach.

Before I tried to predict behaviour of all guns in family.
Now I just iterate over all possible variable values in some range, simulate every generated gun and classify guns based on simulation results.

Code below contains some speed and readability improvements, but it is not enough: with this code, checking of 1616 guns took 2 hours.
Rewriting this code in C++ can speed up execution by approximately 50 times, making this approach usable enough.

Code: Select all

Generating 1616 guns............................................................
................................................................................
.........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...............
..............................xxxxxxxxxxxxx.....................................
...................................................xxxxxxxxxxxxx................
........................................................................xxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx................................
.............xxxxxxxxxxxxx......................................................
..................................xxxxxxxxxxxxx.................................
.......................................................xxxxxxxxxxxxx............
............................................................................xxxx
xxxxxxxxx.......................................................................
.................xxxxxxxxxxxxx..................................................
......................................xxxxxxxxxxxxx.............................
...........................................................xxxxxxxxxxxxx........
................................................................................
xxxxxxxxxxxxx...................................................................
.....................xxxxxxxxxxxxx..............................................
..........................................xxxxxxxxxxxxx.........................
...............................................................xxxxxxxxxxxxx....
....................................... Done
gun_1117:        ->  20300
gun_1213:        ->  23864
gun_1229:        ->  24486
gun_1237:        ->  24800
gun_1277:        ->  26400
gun_1301:        ->  27384
gun_1373:        ->  30444
gun_1381:        ->  30794
gun_1429:        ->  32936
gun_1453:        ->  34034
gun_1549:        ->  38606
gun_1597:        ->  41000
gun_1613:        ->  41814
gun_1693:        ->  46004
gun_2447:  26244 ->  20300
gun_2503:  32697 ->  22344
gun_2543:  28224 ->  23864
gun_2551:  33234 ->  24174
gun_2591:  29241 ->  25754
gun_5099:  21896 ->  20294
gun_5107:  22200 ->  20580
gun_5147:  23750 ->  22040
gun_5171:  24704 ->  22940
gun_5179:  25026 ->  23244
gun_5227:  25920 ->  25110
gun_7759:  26850 ->  20586
gun_7823:  27360 ->  22946
gun_7879:  27720 ->  25116
gun_7919:  27693 ->  26726
gun_7927:  27874 ->  27054

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication145
{
    class Pattern : IEquatable<Pattern>
    {
        public readonly int Width;
        public readonly int Height;
        static byte[] lookup;
        byte[] cells;

        static Pattern()
        {
            lookup = new byte[16];
            lookup[3] = 1;
            lookup[10] = 1;
            lookup[11] = 1;
        }

        public Pattern(int width, int height)
        {
            Width = width;
            Height = height;
            cells = new byte[Width * Height];
        }

        public Pattern(int width, int height, Pattern source, int offsetX, int offsetY)
            : this(width, height)
        {
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    this[x, y] = source[x + offsetX, y + offsetY];
        }

        public byte this[int x, int y]
        {
            get
            {
                return cells[x + y * Width];
            }
            set
            {
                cells[x + y * Width] = value;
            }
        }

        public Pattern Advance()
        {
            var result = new Pattern(Width, Height);
            for (int y = 0; y < Height; y++)
            {
                int ym1 = y == 0 ? Height - 1 : y - 1;
                int yp1 = y == Height - 1 ? 0 : y + 1;
                for (int x = 0; x < Width; x++)
                {
                    int xm1 = x == 0 ? Width - 1 : x - 1;
                    int xp1 = x == Width - 1 ? 0 : x + 1;
                    int neighbours =
                        this[xm1, ym1] +
                        this[x, ym1] +
                        this[xp1, ym1] +
                        this[xm1, y] +
                        this[xp1, y] +
                        this[xm1, yp1] +
                        this[x, yp1] +
                        this[xp1, yp1];
                    result[x, y] = lookup[neighbours & 7 | this[x, y] << 3];
                }
            }
            return result;
        }

        public void Clear(int startX, int startY, int countX, int countY)
        {
            for (int y = 0; y < countY; y++)
                for (int x = 0; x < countX; x++)
                    this[x + startX, y + startY] = 0;
        }

        public bool Search(Pattern pattern, int startX, int startY, int countX, int countY)
        {
            for (int y1 = 0; y1 < countY; y1++)
            {
                for (int x1 = 0; x1 < countX; x1++)
                {
                    bool found = true;
                    for (int y2 = 0; y2 < pattern.Height; y2++)
                    {
                        for (int x2 = 0; x2 < pattern.Width; x2++)
                        {
                            if (this[startX + x1 + x2, startY + y1 + y2] != pattern[x2, y2])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (!found)
                            break;
                    }
                    if (found)
                        return true;
                }
            }
            return false;
        }

        public Pattern Normalize(ref int period)
        {
            Pattern gliderTop1 = ReadRLE("x = 3, y = 3", "3o$2bo$bo!");
            Pattern gliderTop2 = ReadRLE("x = 3, y = 3", "3o$o$bo!");
            Pattern gliderBottom1 = ReadRLE("x = 3, y = 3", "bo$2bo$3o!");
            Pattern gliderBottom2 = ReadRLE("x = 3, y = 3", "bo$o$3o!");
            Pattern gliderLeft1 = ReadRLE("x = 3, y = 3", "2o$obo$o!");
            Pattern gliderLeft2 = ReadRLE("x = 3, y = 3", "o$obo$2o!");
            Pattern gliderRight1 = ReadRLE("x = 3, y = 3", "2bo$obo$b2o!");
            Pattern gliderRight2 = ReadRLE("x = 3, y = 3", "b2o$obo$2bo!");

            Pattern expanded = new Pattern(Width + 6, Height + 6);
            expanded.Stamp(this, 3, 3);

            int lastPeriod = int.MinValue;
            int gliderTick = int.MaxValue;
            var latestGenerations = new List<Pattern>();
            for (int tick = 0; tick < 40000; tick++)
            {
                bool gliderFound =
                    expanded.Search(gliderTop1, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderTop2, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderBottom1, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderBottom2, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderLeft1, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderLeft2, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight1, Width + 3, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight2, Width + 3, 0, 1, Height + 4);
                if (gliderFound)
                {
                    expanded.Clear(0, 0, expanded.Width, 3);
                    expanded.Clear(0, Height + 3, expanded.Width, 3);
                    expanded.Clear(0, 0, 3, expanded.Height);
                    expanded.Clear(Width + 3, 0, 3, expanded.Height);
                    period = tick - gliderTick;
                    if (period == lastPeriod)
                        return new Pattern(Width, Height, latestGenerations[0], 3, 3);
                    else
                    {
                        gliderTick = tick;
                        lastPeriod = period;
                    }
                }
                latestGenerations.Add(expanded);
                if (latestGenerations.Count > 12)
                    latestGenerations.RemoveAt(0);
                expanded = expanded.Advance();
            }
            return null;
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.Height; y++)
                for (int x = 0; x < stamp.Width; x++)
                    this[x + xo, y + yo] |= stamp[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {Width}, y = {Height}, rule = B3/S23");
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                    sb.Append(this[x, y] == 1 ? 'o' : 'b');
                sb.AppendLine(y == Height - 1 ? "!" : "$");
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public static Pattern ReadRLE(params string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";
            Pattern pattern = null;
            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                {
                    var match = Regex.Match(line, "^x = ([0-9]+), y = ([0-9]+)");
                    if (!match.Success)
                        throw new Exception();
                    int width = int.Parse(match.Groups[1].Value);
                    int height = int.Parse(match.Groups[2].Value);
                    pattern = new Pattern(width, height);
                    continue;
                }

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                pattern[x, y] = c == 'o' ? (byte)1 : (byte)0;
                                x++;
                                pattern.WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
            return pattern;
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        public override int GetHashCode()
        {
            int shift = 0;
            int hash = Width << 16 | Height;
            for (int i = 0; i < cells.Length; i++)
            {
                hash = hash ^ cells[i] << shift;
                shift = (shift + 1) & 31;
            }
            return hash;
        }

        public bool Equals(Pattern other)
        {
            if (Width != other.Width || Height != other.Height)
                return false;
            for (int i = 0; i < cells.Length; i++)
                if (cells[i] != other.cells[i])
                    return false;
            return true;
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += Width;
            else if (x >= Width)
                x -= Width;
            if (y < 0)
                y += Height;
            else if (y >= Height)
                y -= Width;
        }
    }

    class Component
    {
        public int X1;
        public int Y1;
        public int X2;
        public int Y2;
        public Pattern Pattern;

        public int X
        {
            get { return X1 + X2; }
        }

        public int Y
        {
            get { return Y1 + Y2; }
        }

        public Component(int x, int y, Pattern pattern)
        {
            X1 = x;
            Y1 = y;
            Pattern = pattern;
        }
    };

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        static Pattern Combine(params Component[] components)
        {
            int minX = int.MaxValue;
            int minY = int.MaxValue;

            foreach (var component in components)
            {
                minX = Math.Min(minX, component.X);
                minY = Math.Min(minY, component.Y);
            }

            int width = 0;
            int height = 0;
            foreach (var component in components)
            {
                width = Math.Max(width,
                    component.X + component.Pattern.Width - minX);
                height = Math.Max(height,
                    component.Y + component.Pattern.Height - minY);
            }

            Pattern pattern = new Pattern(width, height);
            foreach (var component in components)
            {
                pattern.Stamp(component.Pattern,
                    component.X - minX, component.Y - minY);
            }
            return pattern;
        }

        Program()
        {
            Component part1 = new Component(0, 0, Pattern.ReadRLE(
                "x = 89, y = 108, rule = B3/S23",
                "30b2o$30bobo$32bo4b2o$28b4ob2o2bo2bo$28bo2bobobobob2o$31bobobobo$32b2o",
                "bobo$36bo2$22b2o$23bo7b2o$23bobo5b2o$24b2o7$34b2o$34bo$35b3o$37bo4$40b",
                "o$38b3o$37bo$24bo12b2o$22b3o47b2o$21bo50b2o$4bo17bob3o$2b5o14b2obo2bo$",
                "bo5bo13bo3b2o$bo2b3o12bobo18b2o$2obo15b2o19b2o31b2o$o2b4o62b2obobo$b2o",
                "3bo3b2o58bobo$3b3o4b2o58bo2bo$3bo45bo3b2o16bobo$2obo44bobo3bo17bo$2ob",
                "2o42bobo3bo$43b2obobo3bo$43b2obo2b4obo5b2o$11b2o34bobo3bobo5bo$12bo30b",
                "2ob2o2bo2bobo2b3o26b2o$9b3o32bobo2b2o3bo3bo28b2o$9bo22b2o10bobo$32b2o",
                "11bo2$67b2o$66bobo$66bo$65b2o7b2o$74b2o2$82b2obo$82b2ob3o$88bo$82b2ob",
                "3o$81bo2b2o$80bobo$79bobob2obo$62b2o16bo2bob2o$63bo8b3o8bo$63bobo8bo7b",
                "2o$64b2o7b3o3bobo2b2o$79b2o2bo2bo$84b2o10$65b2o15b2o$65b2o15bobo$84bo$",
                "84b2o6$77bo$75b3o$74bo$74b2o9$69b2o$69bo2bo$70b2obo$73bo$68bo4bob2o$",
                "66b3o3b2ob2o$65bo$65b2o!"
            ));
            Component part2 = new Component(2, 2, Pattern.ReadRLE(
                "x = 19, y = 23, rule = B3/S23",
                "8b2o$8bobo$10bo4b2o$6b4ob2o2bo2bo$6bo2bobobobob2o$9bobobobo$10b2obobo$",
                "14bo2$2o$bo7b2o$bobo5b2o$2b2o7$12b2o$12bo$13b3o$15bo!"
            ));
            Component[] parts3 = new Component[] {
                new Component(44, 102, Pattern.ReadRLE(
                    "x = 19, y = 23, rule = B3/S23",
                    "3bo$3b3o$6bo$5b2o7$15b2o$8b2o5bobo$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobo",
                    "bo$2obobobobo2bo$o2bo2b2ob4o$2b2o4bo$8bobo$9b2o!"
                )),
                new Component(46, 102, Pattern.ReadRLE(
                    "x = 21, y = 23, rule = B3/S23",
                    "bo$b3o$4bo$3b2o5$14b2ob2o$14b2obo2bo$19b2o$6b2o$6b2o4bo2bo$12b4o$18bo$",
                    "2bo11b5o$bobob2o7bo$bobobobo8bo$2obobobo2bo4b2o$bo2b2ob4o$bo4bo$2b3obo",
                    "2b2o$4b2o3b2o!"
                )),
                new Component(45, 102, Pattern.ReadRLE(
                    "x = 18, y = 25, rule = B3/S23",
                    "2bo$2b3o$5bo$4b2o7$14b2o$7b2o5bobo$7b2o7bo$16b2o5$4b2ob2o$2o3bob2o2b2o",
                    "$o2bobo6bo$2b2ob7o$4bo$4bob4o$5b2o2bo!"
                )),
                new Component(45, 102, Pattern.ReadRLE(
                    "x = 22, y = 25, rule = B3/S23",
                    "2bo$2b3o$5bo$4b2o5$15b2ob2o$15b2obo2bo$20b2o$7b2o$7b2o4bo2bo$13b4o$19b",
                    "o$15b5o$15bo$17bo$4b2ob2o7b2o$2o3bob2o2b2o$o2bobo6bo$2b2ob7o$4bo$4bob",
                    "4o$5b2o2bo!"
                ))
            };
            Component[] parts4 = new Component[] {
                new Component(-29, 41, Pattern.ReadRLE(
                    "x = 23, y = 19, rule = B3/S23",
                    "3b2o$4bo$2bo$2b5o14b2o$7bo13bo$4b3o12bobo$3bo15b2o$3b4o$b2o3bo3b2o$o2b",
                    "3o4b2o$2obo$3bo$3b2o3$11b2o$12bo$9b3o$9bo!"
                )),
                new Component(-29, 43, Pattern.ReadRLE(
                    "x = 23, y = 21, rule = B3/S23",
                    "4bo$2b5o14b2o$bo5bo13bo$bo2b3o12bobo$2obo15b2o$o2b4o$b2o3bo3b2o$3b3o4b",
                    "2o$3bo$2obo$2ob2o2$9b2o$9bo$6b2obo3b2o$4bo2bob2o2b2o$4b2obo$7bo5b2o$7b",
                    "2o5bo$12bo$12b2o!"
                )),
                new Component(-31, 42, Pattern.ReadRLE(
                    "x = 25, y = 18, rule = B3/S23",
                    "4b2o$5bo$3bo19b2o$3b2o18bo$b2o3bo14bobo$o2b4o14b2o$2obo$bobob2o5b2o$bo",
                    "bob2o5b2o$2obo$3bo$3bobo$4b2o2$13b2o$14bo$11b3o$11bo!"
                )),
                new Component(-31, 42, Pattern.ReadRLE(
                    "x = 25, y = 22, rule = B3/S23",
                    "4b2o$5bo$3bo19b2o$3b2o18bo$b2o3bo14bobo$o2b4o14b2o$2obo$bobob2o5b2o$bo",
                    "bob2o5b2o$2obo$3bo$3bobo$4b2o$11b2o$11bo$8b2obo3b2o$6bo2bob2o2b2o$6b2o",
                    "bo$9bo5b2o$9b2o5bo$14bo$14b2o!"
                ))
            };
            var newGuns = new Dictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            int mul3min = 1;
            int mul3max = 4;
            int mul4min = 1;
            int mul4max = 4;
            int shiftMin = 0;
            int shiftMax = 100;

            int gunCount =
                (mul3max - mul3min + 1) *
                (mul4max - mul4min + 1) *
                (shiftMax - shiftMin + 1);

            Console.Write($"Generating {gunCount} guns...");

            for (int mul3 = mul3min; mul3 <= mul3max; mul3++)
            {
                for (int mul4 = mul4min; mul4 <= mul4max; mul4++)
                {
                    int mul = mul3 * mul4;

                    byte hack = mul == 1 ? (byte)1 : (byte)0;
                    part1.Pattern[53, 27] = hack;
                    part1.Pattern[53, 28] = hack;
                    part1.Pattern[54, 27] = hack;
                    part1.Pattern[54, 28] = hack;

                    for (int shift = shiftMin; shift <= shiftMax; shift++)
                    {
                        int shiftD = shift / 2;
                        int shiftM = shift % 2;
                        int shiftA = shiftD + shiftM;
                        int shiftB = shiftD;

                        Component part3 = parts3[mul3 - 1];
                        Component part4 = parts4[mul4 - 1];

                        part2.X2 = -shiftA;
                        part2.Y2 = -shiftA;
                        part3.X2 = -shiftB;
                        part3.Y2 = shiftB;
                        part4.X2 = -shiftA - shiftB;
                        part4.Y2 = -shiftA + shiftB;

                        Pattern gun = Combine(part1, part2, part3, part4);

                        int period = 0;
                        Pattern normalizedGun = gun.Normalize(ref period);
                        if (normalizedGun == null)
                        {
                            Console.Write('x');
                            //gun.WriteRLE($"gun_x_{mul3}_{mul4}_{shift}.rle");
                            continue;
                        }
                        else
                            Console.Write('.');

                        int area = normalizedGun.Width * normalizedGun.Height;
                        if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                            continue;

                        newGuns[period] = normalizedGun;
                        newGunsCosts[period] = area;
                    }
                }
            }
            Console.WriteLine(" Done");

            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            string logName = "report.txt";
            File.Delete(logName);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                if (!IsPrime(period) || period > 9999)
                    continue;

                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                string reportLine = $"gun_{period,-4}: {costS} -> {area,6}";
                Console.WriteLine(reportLine);
                File.AppendAllLines(logName, new string[] { reportLine });
                gun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » June 19th, 2024, 12:56 pm

Vort wrote:
June 19th, 2024, 11:14 am
[...]
Code below contains some speed and readability improvements, but it is not enough: with this code, checking of 1616 guns took 2 hours.
Rewriting this code in C++ can speed up execution by approximately 50 times, making this approach usable enough.
[...]
How about rewriting the code to use lifelib via Python 3? (Tutorials/lifelib)
Things like evolving a pattern by n ticks, translations, parsing and generating RLE are already implemented. (The generated RLE would be actually run-length encoded, reducing the volume of submissions in batches.)

Code: Select all

import lifelib
sess = lifelib.load_rules("b3s23")
lt = sess.lifetree(n_layers = 1)

part1 = lt.pattern("""
x = 89, y = 108, rule = B3/S23
30b2o$30bobo$32bo4b2o$28b4ob2o2bo2bo$28bo2bobobobob2o$31bobobobo$32b2o
bobo$36bo2$22b2o$23bo7b2o$23bobo5b2o$24b2o7$34b2o$34bo$35b3o$37bo4$40b
o$38b3o$37bo$24bo12b2o$22b3o47b2o$21bo50b2o$4bo17bob3o$2b5o14b2obo2bo$
bo5bo13bo3b2o$bo2b3o12bobo18b2o$2obo15b2o19b2o31b2o$o2b4o62b2obobo$b2o
3bo3b2o58bobo$3b3o4b2o58bo2bo$3bo45bo3b2o16bobo$2obo44bobo3bo17bo$2ob
2o42bobo3bo$43b2obobo3bo$43b2obo2b4obo5b2o$11b2o34bobo3bobo5bo$12bo30b
2ob2o2bo2bobo2b3o26b2o$9b3o32bobo2b2o3bo3bo28b2o$9bo22b2o10bobo$32b2o
11bo2$67b2o$66bobo$66bo$65b2o7b2o$74b2o2$82b2obo$82b2ob3o$88bo$82b2ob
3o$81bo2b2o$80bobo$79bobob2obo$62b2o16bo2bob2o$63bo8b3o8bo$63bobo8bo7b
2o$64b2o7b3o3bobo2b2o$79b2o2bo2bo$84b2o10$65b2o15b2o$65b2o15bobo$84bo$
84b2o6$77bo$75b3o$74bo$74b2o9$69b2o$69bo2bo$70b2obo$73bo$68bo4bob2o$
66b3o3b2ob2o$65bo$65b2o!
""")

print("#C population (generation 0) = {}".format(part1.population))
print(part1.rle_string())

part1_evolved = part1[665]

print("#C population (generation 665) = {}".format(part1_evolved.population))
print(part1_evolved.rle_string())

xored = part1 ^ part1_evolved
print("#C population (XOR) = {}".format(xored.population))
print(xored.rle_string())
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 19th, 2024, 3:34 pm

chris_c wrote:
March 27th, 2019, 1:16 pm
Here is 1025-4999:

1025 (7344, 'p00559x5_7')
1026 (6300, 'p00441x2_9')
...
I compared primes from this list with data from Catagolue.
Not much left to completely process this source: 105 guns.

Code: Select all

gun_1031:  13224 ->   8064   p00863_21
gun_1033:        ->   7865   p00905_16
gun_1039:  13455 ->   8255   p00863_22
gun_1049:  11926 ->   7995   p00905_18
gun_1051:   8382 ->   8001   p00867_23
gun_1061:  18354 ->   8256   p00853_26
gun_1063:        ->   8580   p00863_25
gun_1069:   8840 ->   8450   p00853_27
gun_1087:        ->   8911   p00863_28
gun_1091:  19044 ->   8580   p00867_28
gun_1093:  19454 ->   8778   p00853_30
gun_1097:        ->   8385   p00905_24
gun_1103:        ->   9045   p00863_30
gun_1109:  12024 ->   8910   p00853_32
gun_1117:  20300 ->   9112   p00853_33
gun_1123:  20164 ->   8976   p00867_32
gun_1129:        ->   8911   p00905_28
gun_1151:        ->   9729   p00863_36
gun_1153:        ->   9248   p00905_31
gun_1163:  21609 ->   9373   p00827_42
gun_1171:  12350 ->   9568   p00827_43
gun_1181:  10355 ->   9936   p00853_41
gun_1187:  22500 ->   9765   p00827_45
gun_1193:        ->   9729   p00905_36
gun_1201:        ->   9940   p00905_37
gun_1213:  23864 ->  10508   p00853_45
gun_1217:        ->  10080   p00905_39
gun_1223:        ->  10800   p00863_45
gun_1229:  24486 ->  10650   p00853_47
gun_1231:        ->  11023   p00863_46
gun_1237:  24800 ->  10872   p00853_48
gun_1249:  10773 ->  10656   p00905_43
gun_1259:  25281 ->  10573   p00827_54
gun_1277:  26400 ->  11388   p00853_53
gun_1279:        ->  11682   p00991_36
gun_1283:  26244 ->  10989   p00827_57
gun_1289:        ->  11169   p00905_48
gun_1291:  26569 ->  10989   p00827_58
gun_1297:        ->  11396   p00905_49
gun_1301:  27384 ->  11766   p00853_56
gun_1303:        ->  12060   p00991_39
gun_1307:  27225 ->  11200   p00827_60
gun_1319:        ->  12312   p00863_57
gun_1321:        ->  11775   p00905_52
gun_1327:        ->  12444   p00991_42
gun_1361:        ->  12312   p00905_57
gun_1367:        ->  13104   p00863_63
gun_1373:  30444 ->  12936   p00853_65
gun_1381:  30794 ->  13182   p00853_66
gun_1399:        ->  13632   p00991_51
gun_1409:        ->  13104   p00905_63
gun_1423:        ->  14040   p00991_54
gun_1427:  32400 ->  12960   p00827_75
gun_1429:  32936 ->  14000   p00853_72
gun_1433:        ->  13509   p00905_66
gun_1439:        ->  14337   p00863_72
gun_1447:        ->  14454   p00991_57
gun_1451:  33489 ->  13189   p00827_78
gun_1453:  34034 ->  14418   p00853_75
gun_1459:  33856 ->  13420   p00827_79
gun_1483:  34969 ->  13653   p00827_82
gun_1489:        ->  14596   p00905_73
gun_1499:  35721 ->  13888   p00827_84
gun_1511:        ->  15624   p00863_81
gun_1523:  36864 ->  14364   p00827_87
gun_1531:  37249 ->  14364   p00827_88
gun_1543:        ->  16170   p00991_69
gun_1549:  38606 ->  16150   p00853_87
gun_1553:        ->  15624   p00905_81
gun_1559:        ->  16512   p00863_87
gun_1567:        ->  16614   p00991_72
gun_1579:  39601 ->  15093   p00827_94
gun_1583:        ->  16965   p00863_90
gun_1597:  41000 ->  17052   p00853_93
gun_1601:        ->  16512   p00905_87
gun_1607:        ->  17424   p00863_93
gun_1613:  41814 ->  17226   p00853_95
gun_1627:  42025 ->  15840   p00827_100
gun_1663:        ->  18450   p00991_84
gun_1693:  21840 ->  18928   p00853_105
gun_1697:        ->  18360   p00905_99
gun_1787:  21646 ->  18460   p00827_120
gun_1867:  20825 ->  19845   p00827_130
gun_1877:  24585 ->  22638   p00853_128
gun_1907:  21516 ->  20700   p00827_135
gun_1931:  24150 ->  20989   p00827_138
gun_1979:  24633 ->  21868   p00827_144
gun_1987:  24794 ->  22165   p00827_145
gun_2003:  24955 ->  22464   p00827_147
gun_2011:  24955 ->  22464   p00827_148
gun_2027:  25116 ->  22765   p00827_150
gun_2083:  26080 ->  23989   p00827_157
gun_2099:  26404 ->  24300   p00827_159
gun_2131:  27058 ->  24928   p00827_163
gun_2179:  28054 ->  25885   p00827_169
gun_2203:  28390 ->  26208   p00827_172
gun_2243:  29410 ->  27189   p00827_177
gun_2251:  29410 ->  27189   p00827_178
gun_2267:  29754 ->  27520   p00827_180
gun_2339:  31504 ->  29205   p00827_189
gun_2347:  31680 ->  29205   p00827_190
gun_2371:  32574 ->  29893   p00827_193
gun_2411:  33840 ->  30589   p00827_198
gun_2459:  35502 ->  31648   p00827_204
gun_2467:  35880 ->  32005   p00827_205
However it looks like automating this task will consume more time than manually adjusting these guns.
Last edited by Vort on June 19th, 2024, 4:37 pm, edited 1 time in total.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 19th, 2024, 3:46 pm

confocaloid wrote:
June 19th, 2024, 12:56 pm
How about rewriting the code to use lifelib via Python 3? (Tutorials/lifelib)
I will consider this option if I decide to port my code to other languages, thanks.
confocaloid wrote:
June 19th, 2024, 12:56 pm
The generated RLE would be actually run-length encoded, reducing the volume of submissions in batches.
Is it that important? Catagolue prettify uploaded data anyway.

One of the goals of my code is to show how many things can be achieved without external dependencies and with relatively small program size.
If I rewrite `WriteRLE` function, it will become large without providing much advantage.
Also now it is 100% bug free. If I add real RLE compression, then I may also add bugs, which may be hard to track with 4 hour data processing intervals of Catagolue.
I may do it however. Will think about it more.

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » June 19th, 2024, 9:38 pm

Vort wrote:
June 19th, 2024, 3:46 pm
[...]
confocaloid wrote:
June 19th, 2024, 12:56 pm
The generated RLE would be actually run-length encoded, reducing the volume of submissions in batches.
Is it that important? Catagolue prettify uploaded data anyway.

One of the goals of my code is to show how many things can be achieved without external dependencies and with relatively small program size.
If I rewrite `WriteRLE` function, it will become large without providing much advantage.
Also now it is 100% bug free. If I add real RLE compression, then I may also add bugs, which may be hard to track with 4 hour data processing intervals of Catagolue.
I may do it however. Will think about it more.
The points about avoiding bugs and keeping the code simple and self-contained are valid points.

One potential advantage of RLE compression, is that it can become easier to reuse the same code (once written and debugged) in other CGoL projects, as long as it's a function that accepts a pattern and returns conforming RLE.

One actual advantage, for submitting glider guns (or glider syntheses) to Catagolue, would be a significant reduction in the volume of update logs (for example: 7123031375, 7139015761) and the intermediate readsynth queue.

The logs include every submitted RLE, almost unchanged (except for the header); prettification happens at some later point. As a consequence, some logs (for example 7117451250) become too large to be preserved, and there's a message at the end that says "Job's log exceeded limit of 4194304 bytes. Job execution will continue but no more output will be collected." which means some information of interest (e.g. details about processing later RLE submissions, the list of apgcodes at the end) can become lost/unavailable.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 20th, 2024, 5:58 am

I rewrote WriteRLE function.
It's still not perfect, but should not overflow Catagolue logs anymore.

Also I processed p00827 family, 42 guns were uploaded:

Code: Select all

Generating 201 guns.............................................................
................................................................................
............................................................... Done
gun_1051:   8382 ->   8064
gun_1091:  19044 ->   8613
gun_1123:  20164 ->   8989
gun_1163:  21609 ->   9373
gun_1171:  12350 ->   9568
gun_1187:  22500 ->   9765
gun_1259:  25281 ->  10573
gun_1283:  26244 ->  10989
gun_1291:  26569 ->  10989
gun_1307:  27225 ->  11200
gun_1427:  32400 ->  12960
gun_1451:  33489 ->  13189
gun_1459:  33856 ->  13420
gun_1483:  34969 ->  13653
gun_1499:  35721 ->  13888
gun_1523:  36864 ->  14364
gun_1531:  37249 ->  14364
gun_1579:  39601 ->  15093
gun_1627:  42025 ->  15840
gun_1787:  21646 ->  18460
gun_1867:  20825 ->  19845
gun_1907:  21516 ->  20700
gun_1931:  24150 ->  20989
gun_1979:  24633 ->  21868
gun_1987:  24794 ->  22165
gun_2003:  24955 ->  22464
gun_2011:  24955 ->  22464
gun_2027:  25116 ->  22765
gun_2083:  26080 ->  23989
gun_2099:  26404 ->  24300
gun_2131:  27058 ->  24928
gun_2179:  28054 ->  25885
gun_2203:  28390 ->  26208
gun_2243:  29410 ->  27189
gun_2251:  29410 ->  27189
gun_2267:  29754 ->  27520
gun_2339:  31504 ->  29205
gun_2347:  31680 ->  29205
gun_2371:  32574 ->  29893
gun_2411:  33840 ->  30589
gun_2459:  35502 ->  31648
gun_2467:  35880 ->  32005

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication145
{
    class Pattern : IEquatable<Pattern>
    {
        public readonly int Width;
        public readonly int Height;
        static byte[] lookup;
        byte[] cells;

        static Pattern()
        {
            lookup = new byte[16];
            lookup[3] = 1;
            lookup[10] = 1;
            lookup[11] = 1;
        }

        public Pattern(int width, int height)
        {
            Width = width;
            Height = height;
            cells = new byte[Width * Height];
        }

        public Pattern(int width, int height, Pattern source, int offsetX, int offsetY)
            : this(width, height)
        {
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    this[x, y] = source[x + offsetX, y + offsetY];
        }

        public byte this[int x, int y]
        {
            get
            {
                return cells[x + y * Width];
            }
            set
            {
                cells[x + y * Width] = value;
            }
        }

        public Pattern Advance()
        {
            var result = new Pattern(Width, Height);
            for (int y = 0; y < Height; y++)
            {
                int ym1 = y == 0 ? Height - 1 : y - 1;
                int yp1 = y == Height - 1 ? 0 : y + 1;
                for (int x = 0; x < Width; x++)
                {
                    int xm1 = x == 0 ? Width - 1 : x - 1;
                    int xp1 = x == Width - 1 ? 0 : x + 1;
                    int neighbours =
                        this[xm1, ym1] +
                        this[x, ym1] +
                        this[xp1, ym1] +
                        this[xm1, y] +
                        this[xp1, y] +
                        this[xm1, yp1] +
                        this[x, yp1] +
                        this[xp1, yp1];
                    result[x, y] = lookup[neighbours & 7 | this[x, y] << 3];
                }
            }
            return result;
        }

        public void Clear(int startX, int startY, int countX, int countY)
        {
            for (int y = 0; y < countY; y++)
                for (int x = 0; x < countX; x++)
                    this[x + startX, y + startY] = 0;
        }

        public bool Search(Pattern pattern, int startX, int startY, int countX, int countY)
        {
            for (int y1 = 0; y1 < countY; y1++)
            {
                for (int x1 = 0; x1 < countX; x1++)
                {
                    bool found = true;
                    for (int y2 = 0; y2 < pattern.Height; y2++)
                    {
                        for (int x2 = 0; x2 < pattern.Width; x2++)
                        {
                            if (this[startX + x1 + x2, startY + y1 + y2] != pattern[x2, y2])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (!found)
                            break;
                    }
                    if (found)
                        return true;
                }
            }
            return false;
        }

        public Pattern Normalize(ref int period)
        {
            Pattern gliderTop1 = ReadRLE("x = 3, y = 3", "3o$2bo$bo!");
            Pattern gliderTop2 = ReadRLE("x = 3, y = 3", "3o$o$bo!");
            Pattern gliderBottom1 = ReadRLE("x = 3, y = 3", "bo$2bo$3o!");
            Pattern gliderBottom2 = ReadRLE("x = 3, y = 3", "bo$o$3o!");
            Pattern gliderLeft1 = ReadRLE("x = 3, y = 3", "2o$obo$o!");
            Pattern gliderLeft2 = ReadRLE("x = 3, y = 3", "o$obo$2o!");
            Pattern gliderRight1 = ReadRLE("x = 3, y = 3", "2bo$obo$b2o!");
            Pattern gliderRight2 = ReadRLE("x = 3, y = 3", "b2o$obo$2bo!");

            Pattern expanded = new Pattern(Width + 6, Height + 6);
            expanded.Stamp(this, 3, 3);

            int lastPeriod = int.MinValue;
            int gliderTick = int.MaxValue;
            var latestGenerations = new List<Pattern>();
            for (int tick = 0; tick < 40000; tick++)
            {
                bool gliderFound =
                    expanded.Search(gliderTop1, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderTop2, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderBottom1, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderBottom2, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderLeft1, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderLeft2, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight1, Width + 3, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight2, Width + 3, 0, 1, Height + 4);
                if (gliderFound)
                {
                    expanded.Clear(0, 0, expanded.Width, 3);
                    expanded.Clear(0, Height + 3, expanded.Width, 3);
                    expanded.Clear(0, 0, 3, expanded.Height);
                    expanded.Clear(Width + 3, 0, 3, expanded.Height);
                    period = tick - gliderTick;
                    if (period == lastPeriod)
                        return new Pattern(Width, Height, latestGenerations[0], 3, 3);
                    else
                    {
                        gliderTick = tick;
                        lastPeriod = period;
                    }
                }
                latestGenerations.Add(expanded);
                if (latestGenerations.Count > 12)
                    latestGenerations.RemoveAt(0);
                expanded = expanded.Advance();
            }
            return null;
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.Height; y++)
                for (int x = 0; x < stamp.Width; x++)
                    this[x + xo, y + yo] |= stamp[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {Width}, y = {Height}, rule = B3/S23");
            var tags = new List<char>();
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                    tags.Add(this[x, y] == 1 ? 'o' : 'b');
                tags.Add(y == Height - 1 ? '!' : '$');
            }
            int lineLength = 0;
            for (int i = 0; i < tags.Count; i++)
            {
                int runCount = 1;
                while (i + 1 < tags.Count && tags[i] == tags[i + 1])
                {
                    i++;
                    runCount++;
                }
                string run = runCount == 1 ? $"{tags[i]}" : $"{runCount}{tags[i]}";
                if (lineLength + run.Length > 70)
                {
                    sb.AppendLine();
                    lineLength = 0;
                }
                sb.Append(run);
                lineLength += run.Length;
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public static Pattern ReadRLE(params string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";
            Pattern pattern = null;
            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                {
                    var match = Regex.Match(line, "^x = ([0-9]+), y = ([0-9]+)");
                    if (!match.Success)
                        throw new Exception();
                    int width = int.Parse(match.Groups[1].Value);
                    int height = int.Parse(match.Groups[2].Value);
                    pattern = new Pattern(width, height);
                    continue;
                }

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                pattern[x, y] = c == 'o' ? (byte)1 : (byte)0;
                                x++;
                                pattern.WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
            return pattern;
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        public override int GetHashCode()
        {
            int shift = 0;
            int hash = Width << 16 | Height;
            for (int i = 0; i < cells.Length; i++)
            {
                hash = hash ^ cells[i] << shift;
                shift = (shift + 1) & 31;
            }
            return hash;
        }

        public bool Equals(Pattern other)
        {
            if (Width != other.Width || Height != other.Height)
                return false;
            for (int i = 0; i < cells.Length; i++)
                if (cells[i] != other.cells[i])
                    return false;
            return true;
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += Width;
            else if (x >= Width)
                x -= Width;
            if (y < 0)
                y += Height;
            else if (y >= Height)
                y -= Width;
        }
    }

    class Component
    {
        public int X1;
        public int Y1;
        public int X2;
        public int Y2;
        public Pattern Pattern;

        public int X
        {
            get { return X1 + X2; }
        }

        public int Y
        {
            get { return Y1 + Y2; }
        }

        public Component(int x, int y, Pattern pattern)
        {
            X1 = x;
            Y1 = y;
            Pattern = pattern;
        }
    };

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        static Pattern Combine(params Component[] components)
        {
            int minX = int.MaxValue;
            int minY = int.MaxValue;

            foreach (var component in components)
            {
                minX = Math.Min(minX, component.X);
                minY = Math.Min(minY, component.Y);
            }

            int width = 0;
            int height = 0;
            foreach (var component in components)
            {
                width = Math.Max(width,
                    component.X + component.Pattern.Width - minX);
                height = Math.Max(height,
                    component.Y + component.Pattern.Height - minY);
            }

            Pattern pattern = new Pattern(width, height);
            foreach (var component in components)
            {
                pattern.Stamp(component.Pattern,
                    component.X - minX, component.Y - minY);
            }
            return pattern;
        }

        Program()
        {
            Component part1 = new Component(0, 0, Pattern.ReadRLE(
                "x = 62, y = 52, rule = B3/S23",
                "42bo$42b3o$45bo$29bo14bobo$27b3o14bobo$26bo18bo$26b2o3$34b2o$35bo24b2o",
                "$35bob2o21b2o$27b2o4b3o2bo$27b2o3bo3b2o$32b4o$18b2o15bo4b2o$17bobo12b",
                "3o4bobo$17bo13bo7bo$16b2o14b5ob2o7b2o$36bobo8b2o$32b2o2bobo$32b2o3bo",
                "17b2obo$55b2ob3o$61bo$55b2ob3o$54bo2b2o$53bobo$35bo16bobob2obo$35b3o",
                "15bo2bob2o$bo36bo17bo$b3o33b2o16b2o$4bo47bobo2b2o$3b2o47b2o2bo2bo$57b",
                "2o3$21b3o34b2o$21bo36bo$22bo33bobo$13b2o41b2o$6b2o5bobo$6b2o7bo14b2o$",
                "15b2o12bo$30bobo5b2o$2bo28bo6b2o$bobob2o31bo$bobobobo27b2o$2obobobo2bo",
                "23bo2bo$bo2b2ob4o23bobo$bo4bo28bo25bo$2b3obo2b2o31b2o15bobo$4b2o3b2o",
                "31b2o16b2o!"
            ));
            Component part2 = new Component(-25, -23, Pattern.ReadRLE(
                "x = 50, y = 60, rule = B3/S23",
                "39b2o3b2o$39b2o2bob3o$43bo4bo$39b4ob2o2bo$39bo2bobobob2o$42bobobobo$",
                "43b2obobo$47bo2$33b2o$34bo7b2o$34bobo5b2o$35b2o7$45b2o$45bo$46b3o$48bo",
                "21$4bo$2b5o14b2o$bo5bo13bo$bo2b3o12bobo$2obo15b2o$o2b4o$b2o3bo3b2o$3b",
                "3o4b2o$3bo$2obo$2ob2o3$11b2o$12bo$9b3o$9bo!"
            ));
            Component part3 = new Component(-25, -23, Pattern.ReadRLE(
                "x = 28, y = 38, rule = B3/S23",
                "17b2o3b2o$17b2o2bob3o$21bo4bo$17b4ob2o2bo$17bo2bobobob2o$20bobobobo$",
                "21b2obobo$25bo2$11b2o$12bo7b2o$12bobo5b2o$13b2o7$23b2o$23bo$4bo19b3o$",
                "2b5o14b3o2bo$bo5bo13bo2bo$bo2b3o12bobo2b2o$2obo15b2o$o2b4o$b2o3bo3b2o$",
                "3b3o4b2o$3bo$2obo$2ob2o3$11b2o$12bo$9b3o$9bo!"
            ));

            var newGuns = new Dictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            int shiftMin = 0;
            int shiftMax = 200;

            int gunCount = shiftMax - shiftMin + 1;

            Console.Write($"Generating {gunCount} guns...");

            for (int shift = shiftMin; shift <= shiftMax; shift++)
            {
                int shiftD = shift / 2;
                int shiftM = shift % 2;
                int shiftA = shiftD + shiftM;
                int shiftB = shiftD;

                part2.X2 = -shiftA;
                part2.Y2 = -shiftA;
                part3.X2 = -shiftB;
                part3.Y2 = -shiftB;

                Pattern gun = Combine(part1, part2, part3);

                int period = 0;
                Pattern normalizedGun = gun.Normalize(ref period);
                if (normalizedGun == null)
                {
                    Console.Write('x');
                    //gun.WriteRLE($"gun_x_{shift}.rle");
                    continue;
                }
                else
                    Console.Write('.');

                int area = normalizedGun.Width * normalizedGun.Height;
                if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                    continue;

                newGuns[period] = normalizedGun;
                newGunsCosts[period] = area;
            }
            Console.WriteLine(" Done");

            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            string logName = "report.txt";
            File.Delete(logName);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                if (!IsPrime(period) || period > 9999)
                    continue;

                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                string reportLine = $"gun_{period,-4}: {costS} -> {area,6}";
                Console.WriteLine(reportLine);
                File.AppendAllLines(logName, new string[] { reportLine });
                gun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 20th, 2024, 10:05 am

I extended p00827 family by adding one more trombone slide:

Code: Select all

x = 106, y = 105, rule = LifeSuper
17.2S3.2S15.2pA3.2pA15.2Q3.2Q$17.2S2.S.3S13.2pA2.pA.3pA13.2Q2.Q.3Q$
21.S4.S16.pA4.pA16.Q4.Q$17.4S.2S2.S12.4pA.2pA2.pA12.4Q.2Q2.Q$17.S2.S.
S.S.2S11.pA2.pA.pA.pA.2pA11.Q2.Q.Q.Q.2Q$19.BSBSBS.S14.BpABpABpA.pA14.
BQBQBQ.Q$20.B2SBS.S15.B2pABpA.pA15.B2QBQ.Q$21.2B.BS17.2B.BpA17.2B.BQ$
20.3B19.3B19.3B$11.2S6.4B10.2pA6.4B10.2Q6.4B$12.S6.B2S3B9.pA6.B2pA3B
9.Q6.B2Q3B$12.S.SB3.B2S3B9.pA.pAB3.B2pA3B9.Q.QB3.B2Q3B$13.2SB.10B8.2pA
B.10B8.2QB.10B13.A$15.13B9.13B9.13B10.3A$15.14B8.14B8.14B8.A$15.15B7.
15B7.15B7.2A$17.8B2.4B8.8B2.4B8.8B2.4B3.5B$17.6B5.4B7.6B5.4B7.6B5.4B
2.3B$16.9B4.4B5.9B4.4B5.9B4.9B7.2A.2A$15.4B4.2S5.4B3.4B4.2pA5.4B3.4B
4.2Q5.8B8.A.2A$14.4B5.S7.4B.4B5.pA7.4B.4B5.Q7.10B3.B.A$4.S8.4B7.3S5.
7B7.3pA5.7B7.3Q4.7B2A2B.B3A$2.5S5.4B5.3S2.S6.5B10.pA6.5B10.Q4.7B2A3BA
B2.2A$.S5.S4.4B5.S2.S8.5B17.5B15.12B4A2.A$.S2.3SB2.7B.BS.S2.2S6.7B15.
7B12.2AB.7B3.2B.A.2A$2S.S.2B3.7B.B2S10.4B.4B13.4B.4B10.A.AB.7B2.B3A2.
A$S2.4S12B11.4B3.4B11.4B3.4B9.A5.4B4.A5.A$.2S2.BS3B2S7B10.4B5.4B9.4B
5.4B7.2A5.4B5.5A$3.3SB.2B2S7B9.4B7.4B7.4B7.4B12.4B8.A$3.S.B3.10B8.4B
9.4B5.4B9.4B10.4B$2S.S8.8B6.4B11.4B3.4B11.4B8.4B$2S.2S7.9B4.4B13.4B.
4B13.4B6.4B$13.3B2.4B2.4B15.7B15.4B4.4B$11.5B3.8B17.5B17.4B2.4B$11.2S
7.6B18.5B18.8B$12.S8.4B18.7B18.6B$9.3S8.6B16.4B.4B18.4B$9.S9.8B14.4B
3.4B16.6B$18.4B2.4B12.4B5.4B14.8B$17.4B4.4B10.4B7.4B12.4B2.4B$16.4B6.
4B8.4B9.4B10.4B4.4B$15.4B8.4B6.4B11.4B8.4B6.4B$14.4B10.4B4.4B13.4B6.
4B8.4B7.A$4.pA8.4B12.4B2.4B15.4B4.4B10.4B6.3A$2.5pA5.4B5.2pA7.8B17.4B
2.4B12.4B8.A$.pA5.pA4.4B5.pA9.6B19.8B9.A4.4B6.A.A$.pA2.3pAB2.7B.BpA.pA
10.4B21.6B8.3A5.4B5.A.AB$2pA.pA.2B3.7B.B2pA10.6B21.4B8.A9.4B5.A3B$pA
2.4pA12B11.8B19.6B7.2A9.4B6.4B$.2pA2.BpA3B2pA7B10.4B2.4B17.8B3.5B10.
4B5.6B$3.3pAB.2B2pA7B9.4B4.4B15.4B2.4B2.3B13.4B4.7B$3.pA.B3.10B8.4B6.
4B13.4B4.9B7.2A4.4B2.8B.4B.B$2pA.pA8.8B6.4B8.4B11.4B6.8B8.A5.17B.B2A$
2pA.2pA7.9B4.4B10.4B9.4B8.10B3.B.A.2A3.18B2A$13.3B2.4B2.4B12.4B7.4B9.
7B2A2B.B3A2.A3.16B.2B$11.5B3.8B14.4B5.4B10.7B2A3BAB2.2A4.16B$11.2pA7.
6B16.4B3.4B11.12B4A6.15B$12.pA8.4B18.4B.4B10.2AB.7B3.2B.A4.2AB.12B$9.
3pA8.6B18.7B10.A.AB.7B2.B3A4.A.AB2.11B$9.pA9.8B18.5B11.A5.4B4.A7.A5.
10B$18.4B2.4B6.A10.5B10.2A5.4B5.5A.2A5.2B2A6B$17.4B4.4B5.3A7.7B15.4B
10.A.A5.3B2A6B$16.4B6.4B7.A5.4B.4B13.4B7.2A2.A.A6.10B$15.4B8.4B5.2A4.
4B3.4B11.4B8.2A3.A7.8B.B2A.A$14.4B10.4B4.9B5.4B9.4B21.7B3.B2AB3A$4.Q
8.4B12.4B5.6B7.4B7.4B22.6B6.B4.A$2.5Q5.4B5.2Q7.4B2.8B8.4B5.4B24.6B4.
2A.3A$.Q5.Q4.4B5.Q9.15B7.4B3.4B25.5B4.A2.2A$.Q2.3QB2.7B.BQ.Q10.14B8.
4B.4B25.8B.A.A$2Q.Q.2B3.7B.B2Q12.13B9.7B17.A8.8BA.A.2A.A$Q2.4Q12B15.
10B.B2A8.5B18.3A6.6B.2BAB.A.2A$.2Q2.BQ3B2Q7B17.3B2AB3.BA.A7.5B21.A4.
7B2.2B2.A$3.3QB.2B2Q7B17.3B2AB6.A6.7B19.2A4.7B3.B.2A$3.Q.B3.10B19.4B
6.2A4.4B.4B18.4B.8B2.A.A2.2A$2Q.Q8.8B18.3B12.4B3.4B19.11B2.2A2.A2.A$
2Q.2Q7.9B14.AB.2B12.4B5.4B17.12B7.2A$13.3B2.4B9.2A.A.AB2AB10.4B7.4B
16.12B$11.5B3.4B8.2A.A.ABABAB8.4B9.4B15.11B$11.2Q7.4B10.A.A.A.A2.A5.
4B11.B3A13.9B12.2A$12.Q8.4B9.A2.2A.4A4.4B13.A3B9.2B.10B11.A$9.3Q10.4B
6.3A4.A7.4B15.A3B7.16B.B4.BA.A$9.Q13.4B4.A7.A.A4.4B17.4B3.23B2.B2A$
24.4B4.3A5.2A3.4B19.32B$25.4B5.3A7.4B21.5B2A25B$26.4B7.A5.4B23.3BA27B
$27.4B5.2A4.4B25.3BABA5B2A17B$28.4B4.9B28.2BA6B2A17B$29.4B5.6B30.8BA
8B5.B.4B$30.4B2.8B30.5B2A7B11.4B$31.15B28.4BA2BA6B12.4B$32.14B32.ABA
4.2B14.4B$33.13B33.A6.2B14.3BA$34.10B.B2A37.B2AB14.ABA$36.3B2AB3.BA.A
37.2A16.2A$36.3B2AB6.A56.B$38.4B6.2A$38.3B$35.AB.2B$34.A.AB2AB$34.A.A
BABAB$33.2A.A.A.A2.A$34.A2.2A.4A$34.A4.A$35.3A.A2.2A$37.2A3.2A!
Results are not bad:

Code: Select all

gun_1787:  18460 ->  11130
gun_1811:  16492 ->  11342
gun_1867:  19845 ->  11990
gun_1907:  20700 ->  12210
gun_1931:  20989 ->  12432
gun_1979:  21868 ->  12882
gun_1987:  22165 ->  13110
gun_2003:  22464 ->  13110
gun_2011:  22464 ->  13340
gun_2027:  22765 ->  13340
gun_2083:  23989 ->  14042
gun_2099:  24300 ->  14042
gun_2131:  24928 ->  14520
gun_2179:  25885 ->  15006
gun_2203:  26208 ->  15252
gun_2243:  27189 ->  15500
gun_2251:  27189 ->  15750
gun_2267:  27520 ->  15750
gun_2339:  29205 ->  16512
gun_2347:  29205 ->  16770
gun_2371:  29893 ->  17030
gun_2411:  30589 ->  17292
gun_2459:  31648 ->  17822
gun_2467:  32005 ->  18090
gun_2531:  30561 ->  18632
gun_2539:  30728 ->  18906
gun_2659:  31977 ->  20306
gun_2683:  32524 ->  20592
gun_2707:  32886 ->  20880
gun_2731:  33250 ->  21170
gun_2851:  24150 ->  22650
gun_2971:  24786 ->  24180
gun_3019:  25110 ->  24806

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication145
{
    class Pattern : IEquatable<Pattern>
    {
        public readonly int Width;
        public readonly int Height;
        static byte[] lookup;
        byte[] cells;

        static Pattern()
        {
            lookup = new byte[16];
            lookup[3] = 1;
            lookup[10] = 1;
            lookup[11] = 1;
        }

        public Pattern(int width, int height)
        {
            Width = width;
            Height = height;
            cells = new byte[Width * Height];
        }

        public Pattern(int width, int height, Pattern source, int offsetX, int offsetY)
            : this(width, height)
        {
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    this[x, y] = source[x + offsetX, y + offsetY];
        }

        public byte this[int x, int y]
        {
            get
            {
                return cells[x + y * Width];
            }
            set
            {
                cells[x + y * Width] = value;
            }
        }

        public Pattern Advance()
        {
            var result = new Pattern(Width, Height);
            for (int y = 0; y < Height; y++)
            {
                int ym1 = y == 0 ? Height - 1 : y - 1;
                int yp1 = y == Height - 1 ? 0 : y + 1;
                for (int x = 0; x < Width; x++)
                {
                    int xm1 = x == 0 ? Width - 1 : x - 1;
                    int xp1 = x == Width - 1 ? 0 : x + 1;
                    int neighbours =
                        this[xm1, ym1] +
                        this[x, ym1] +
                        this[xp1, ym1] +
                        this[xm1, y] +
                        this[xp1, y] +
                        this[xm1, yp1] +
                        this[x, yp1] +
                        this[xp1, yp1];
                    result[x, y] = lookup[neighbours & 7 | this[x, y] << 3];
                }
            }
            return result;
        }

        public void Clear(int startX, int startY, int countX, int countY)
        {
            for (int y = 0; y < countY; y++)
                for (int x = 0; x < countX; x++)
                    this[x + startX, y + startY] = 0;
        }

        public bool Search(Pattern pattern, int startX, int startY, int countX, int countY)
        {
            for (int y1 = 0; y1 < countY; y1++)
            {
                for (int x1 = 0; x1 < countX; x1++)
                {
                    bool found = true;
                    for (int y2 = 0; y2 < pattern.Height; y2++)
                    {
                        for (int x2 = 0; x2 < pattern.Width; x2++)
                        {
                            if (this[startX + x1 + x2, startY + y1 + y2] != pattern[x2, y2])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (!found)
                            break;
                    }
                    if (found)
                        return true;
                }
            }
            return false;
        }

        public Pattern Normalize(ref int period)
        {
            Pattern gliderTop1 = ReadRLE("x = 3, y = 3", "3o$2bo$bo!");
            Pattern gliderTop2 = ReadRLE("x = 3, y = 3", "3o$o$bo!");
            Pattern gliderBottom1 = ReadRLE("x = 3, y = 3", "bo$2bo$3o!");
            Pattern gliderBottom2 = ReadRLE("x = 3, y = 3", "bo$o$3o!");
            Pattern gliderLeft1 = ReadRLE("x = 3, y = 3", "2o$obo$o!");
            Pattern gliderLeft2 = ReadRLE("x = 3, y = 3", "o$obo$2o!");
            Pattern gliderRight1 = ReadRLE("x = 3, y = 3", "2bo$obo$b2o!");
            Pattern gliderRight2 = ReadRLE("x = 3, y = 3", "b2o$obo$2bo!");

            Pattern expanded = new Pattern(Width + 6, Height + 6);
            expanded.Stamp(this, 3, 3);

            int lastPeriod = int.MinValue;
            int gliderTick = int.MaxValue;
            var latestGenerations = new List<Pattern>();
            for (int tick = 0; tick < 40000; tick++)
            {
                bool gliderFound =
                    expanded.Search(gliderTop1, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderTop2, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderBottom1, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderBottom2, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderLeft1, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderLeft2, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight1, Width + 3, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight2, Width + 3, 0, 1, Height + 4);
                if (gliderFound)
                {
                    expanded.Clear(0, 0, expanded.Width, 3);
                    expanded.Clear(0, Height + 3, expanded.Width, 3);
                    expanded.Clear(0, 0, 3, expanded.Height);
                    expanded.Clear(Width + 3, 0, 3, expanded.Height);
                    period = tick - gliderTick;
                    if (period == lastPeriod)
                        return new Pattern(Width, Height, latestGenerations[0], 3, 3);
                    else
                    {
                        gliderTick = tick;
                        lastPeriod = period;
                    }
                }
                latestGenerations.Add(expanded);
                if (latestGenerations.Count > 12)
                    latestGenerations.RemoveAt(0);
                expanded = expanded.Advance();
            }
            return null;
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.Height; y++)
                for (int x = 0; x < stamp.Width; x++)
                    this[x + xo, y + yo] |= stamp[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {Width}, y = {Height}, rule = B3/S23");
            var tags = new List<char>();
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                    tags.Add(this[x, y] == 1 ? 'o' : 'b');
                tags.Add(y == Height - 1 ? '!' : '$');
            }
            int lineLength = 0;
            for (int i = 0; i < tags.Count; i++)
            {
                int runCount = 1;
                while (i + 1 < tags.Count && tags[i] == tags[i + 1])
                {
                    i++;
                    runCount++;
                }
                string run = runCount == 1 ? $"{tags[i]}" : $"{runCount}{tags[i]}";
                if (lineLength + run.Length > 70)
                {
                    sb.AppendLine();
                    lineLength = 0;
                }
                sb.Append(run);
                lineLength += run.Length;
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public static Pattern ReadRLE(params string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";
            Pattern pattern = null;
            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                {
                    var match = Regex.Match(line, "^x = ([0-9]+), y = ([0-9]+)");
                    if (!match.Success)
                        throw new Exception();
                    int width = int.Parse(match.Groups[1].Value);
                    int height = int.Parse(match.Groups[2].Value);
                    pattern = new Pattern(width, height);
                    continue;
                }

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                pattern[x, y] = c == 'o' ? (byte)1 : (byte)0;
                                x++;
                                pattern.WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
            return pattern;
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        public override int GetHashCode()
        {
            int shift = 0;
            int hash = Width << 16 | Height;
            for (int i = 0; i < cells.Length; i++)
            {
                hash = hash ^ cells[i] << shift;
                shift = (shift + 1) & 31;
            }
            return hash;
        }

        public bool Equals(Pattern other)
        {
            if (Width != other.Width || Height != other.Height)
                return false;
            for (int i = 0; i < cells.Length; i++)
                if (cells[i] != other.cells[i])
                    return false;
            return true;
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += Width;
            else if (x >= Width)
                x -= Width;
            if (y < 0)
                y += Height;
            else if (y >= Height)
                y -= Width;
        }
    }

    class Component
    {
        public int X1;
        public int Y1;
        public int X2;
        public int Y2;
        public Pattern Pattern;

        public int X
        {
            get { return X1 + X2; }
        }

        public int Y
        {
            get { return Y1 + Y2; }
        }

        public Component(int x, int y, Pattern pattern)
        {
            X1 = x;
            Y1 = y;
            Pattern = pattern;
        }
    };

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        static Pattern Combine(params Component[] components)
        {
            int minX = int.MaxValue;
            int minY = int.MaxValue;

            foreach (var component in components)
            {
                minX = Math.Min(minX, component.X);
                minY = Math.Min(minY, component.Y);
            }

            int width = 0;
            int height = 0;
            foreach (var component in components)
            {
                width = Math.Max(width,
                    component.X + component.Pattern.Width - minX);
                height = Math.Max(height,
                    component.Y + component.Pattern.Height - minY);
            }

            Pattern pattern = new Pattern(width, height);
            foreach (var component in components)
            {
                pattern.Stamp(component.Pattern,
                    component.X - minX, component.Y - minY);
            }
            return pattern;
        }

        Program()
        {
            Component part1 = new Component(0, 0, Pattern.ReadRLE(
                "x = 75, y = 93, rule = B3/S23",
                "53bo$51b3o$50bo$50b2o3$58b2ob2o$59bob2o$59bo$51b2o4b3o$51b2o3bo3b2o$",
                "56b4o2bo$42b2o15bob2o$41bobo12b3o2bo$41bo13bo5bo$40b2o14b5o$58bo14$55b",
                "o$55b3o$58bo$42bo14bobo$40b3o14bobo$39bo18bo$39b2o3$47b2o$48bo24b2o$",
                "48bob2o21b2o$40b2o4b3o2bo$40b2o3bo3b2o$45b4o$31b2o15bo4b2o$30bobo12b3o",
                "4bobo$30bo13bo7bo$3bo25b2o14b5ob2o7b2o$3b3o43bobo8b2o$6bo38b2o2bobo$5b",
                "2o38b2o3bo17b2obo$68b2ob3o$74bo$68b2ob3o$67bo2b2o$66bobo$48bo16bobob2o",
                "bo$15b2o31b3o15bo2bob2o$8b2o5bobo33bo17bo$8b2o7bo32b2o16b2o$17b2o46bob",
                "o2b2o$65b2o2bo2bo$4bo65b2o$2obobob2o$2obobobobo$3bobobobo2bo21b3o34b2o",
                "$3bo2b2ob4o21bo36bo$b3o4bo26bo33bobo$o7bobo58b2o$b3o5b2o$3b3o37b2o$6bo",
                "35bo$5b2o36bobo5b2o$44bo6b2o$51bo$48b2o$47bo2bo$47bobo$48bo25bo$15b2o",
                "38b2o15bobo$8b2o5bobo37b2o16b2o$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobobo$",
                "2b2obobobo2bo$3bo2b2ob4o$3bo4bo$4b3obo2b2o$6b2o3b2o!"
            ));
            Component part2 = new Component(-31, -12, Pattern.ReadRLE(
                "x = 28, y = 38, rule = B3/S23",
                "17b2o3b2o$17b2o2bob3o$21bo4bo$17b4ob2o2bo$17bo2bobobob2o$20bobobobo$",
                "21b2obobo$25bo2$11b2o$12bo7b2o$12bobo5b2o$13b2o7$23b2o$23bo$4bo19b3o$",
                "2b5o14b3o2bo$bo5bo13bo2bo$bo2b3o12bobo2b2o$2obo15b2o$o2b4o$b2o3bo3b2o$",
                "3b3o4b2o$3bo$2obo$2ob2o3$11b2o$12bo$9b3o$9bo!"
            ));
            Component part3 = new Component(-31, -12, Pattern.ReadRLE(
                "x = 50, y = 60, rule = B3/S23",
                "39b2o3b2o$39b2o2bob3o$43bo4bo$39b4ob2o2bo$39bo2bobobob2o$42bobobobo$",
                "43b2obobo$47bo2$33b2o$34bo7b2o$34bobo5b2o$35b2o7$45b2o$45bo$46b3o$48bo",
                "21$4bo$2b5o14b2o$bo5bo13bo$bo2b3o12bobo$2obo15b2o$o2b4o$b2o3bo3b2o$3b",
                "3o4b2o$3bo$2obo$2ob2o3$11b2o$12bo$9b3o$9bo!"
            ));
            Component part4 = new Component(-31, -12, Pattern.ReadRLE(
                "x = 72, y = 82, rule = B3/S23",
                "61b2o3b2o$61b2o2bob3o$65bo4bo$61b4ob2o2bo$61bo2bobobob2o$64bobobobo$",
                "65b2obobo$69bo2$55b2o$56bo7b2o$56bobo5b2o$57b2o7$67b2o$67bo$68b3o$70bo",
                "43$4bo$2b5o14b2o$bo5bo13bo$bo2b3o12bobo$2obo15b2o$o2b4o$b2o3bo3b2o$3b",
                "3o4b2o$3bo$2obo$2ob2o3$11b2o$12bo$9b3o$9bo!"
            ));

            var newGuns = new Dictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            int shiftMin = 0;
            int shiftMax = 200;

            int gunCount = shiftMax - shiftMin + 1;

            Console.Write($"Generating {gunCount} guns...");

            for (int shift = shiftMin; shift <= shiftMax; shift++)
            {
                int shiftD = shift / 3;
                int shiftM = shift % 3;
                int shiftA = shiftD + (shiftM > 0 ? 1 : 0);
                int shiftB = shiftD + (shiftM > 1 ? 1 : 0);
                int shiftC = shiftD;

                part2.X2 = -shiftA;
                part2.Y2 = -shiftA;
                part3.X2 = -shiftB;
                part3.Y2 = -shiftB;
                part4.X2 = -shiftC;
                part4.Y2 = -shiftC;

                Pattern gun = Combine(part1, part2, part3, part4);

                int period = 0;
                Pattern normalizedGun = gun.Normalize(ref period);
                if (normalizedGun == null)
                {
                    Console.Write('x');
                    //gun.WriteRLE($"gun_x_{shift}.rle");
                    continue;
                }
                else
                    Console.Write('.');

                int area = normalizedGun.Width * normalizedGun.Height;
                if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                    continue;

                newGuns[period] = normalizedGun;
                newGunsCosts[period] = area;
            }
            Console.WriteLine(" Done");

            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            string logName = "report.txt";
            File.Delete(logName);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                if (!IsPrime(period) || period > 9999)
                    continue;

                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                string reportLine = $"gun_{period,-4}: {costS} -> {area,6}";
                Console.WriteLine(reportLine);
                File.AppendAllLines(logName, new string[] { reportLine });
                gun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

hotdogPi
Posts: 1696
Joined: August 12th, 2020, 8:22 pm

Re: Small Four-Digit Prime Period Guns

Post by hotdogPi » June 20th, 2024, 10:40 am

Is there any reason this is limited to primes other than the thread title?
User:HotdogPi/My discoveries

Periods discovered: 5-16,⑱,⑳G,㉑G,㉒㉔㉕,㉗-㉛,㉜SG,㉞㉟㊱㊳㊵㊷㊹㊺㊽㊿,54G,55G,56,57G,60,62-66,68,70,73,74S,75,76S,80,84,88,90,96
100,02S,06,08,10,12,14G,16,17G,20,26G,28,38,44,47,48,54,56,72,74,80,92,96S
217,486,576

S: SKOP
G: gun

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 20th, 2024, 11:11 am

hotdogPi wrote:
June 20th, 2024, 10:40 am
Is there any reason this is limited to primes other than the thread title?
Of course, my programs can be used to generate non-prime guns as well.
But, except for corner cases, they will be larger than prime gun + period multiplier.

As for more general question of filling database with new autogenerated content - I don't know if this is good idea.
Probably, separate discussion is needed for this question.
However, any person can do it without discussion and I'm sure it will happen sooner or later, so, maybe, there is no sense in making restrictions.

Since my answer is not good enough, it's better to wait for other opinions.

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » June 20th, 2024, 12:14 pm

Prime-period guns cannot be easily obtained from lower-period guns by period multiplication. (While period multiplication can be done in several different ways to obtain composite periods.) A very compact prime-period gun implies reasonably compact guns for multiples of that period.
At the same time, there are "few" four-digit primes (1061 out of 9000), so practically it makes sense to focus on them.

That being said, some composite periods still remain interesting (e.g. products of two large primes), and this forum thread already contains some composite-period guns.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 20th, 2024, 2:46 pm

I took me a while to understand how to properly expand p00853.
Probably obvious for many people here, but I will show it anyway:

Code: Select all

x = 129, y = 64, rule = LifeSuper
27.A43.2S$25.3A42.S.S$24.A39.2S4.S24.2S$24.2A36.S2.S2.2S.4S20.S.S$20.
6B36.2S.S.S.S.S2.S22.S4.2S$7.A11.5B41.S.SBSBSB20.4S.2S2.S2.S$7.3A8.7B
40.S.SB2SB21.S2.S.S.S.S.2S$10.A6.9B40.SB.2B24.BSBSBS.S$9.2A6.9B43.3B
24.B2SBS.S$9.5B2.13B40.4B6.2S16.2B.BS$11.18B.2B35.3B2SB6.S16.3B$10.2A
19B2A34.3B2SB3.BS.S7.2S6.4B$10.2A17B.B2A32.10B.B2S9.S6.B2S3B$11.B.17B
.B32.13B11.S.SB3.B2S3B8.Q$13.16B34.14B12.2SB.10B6.3Q$14.14B34.15B14.
13B8.Q$15.8B2.4B32.4B2.8B16.14B6.Q.Q$16.7B3.4B30.4B5.6B16.15B5.Q.QB$
13.11B3.4B28.4B4.9B17.8B2.4B5.Q3B$12.12B4.4B26.4B5.2S4.4B16.6B5.4B6.
4B$3.2A7.12B5.4B24.4B7.S5.4B14.9B4.4B5.6B$2.A2.A2.2A2.11B7.4B22.4B5.
3S7.4B12.4B4.2S5.4B4.7B$3.2A2.A.A2.8B.4B6.4B20.4B6.S10.4B10.4B5.S7.4B
2.8B.4B.B$5.2A.B3.7B4.2A7.4B18.4B19.4B8.4B7.3S5.17B.B2Q$5.A2.2B2.7B4.
A9.4B16.4B21.4B6.4B10.S6.18B2Q$2.2A.A.BA2B.6B6.3A7.4B14.4B23.4B4.4B
18.16B.2B$2.A.2A.A.A8B8.A8.4B12.4B25.4B2.4B19.16B$6.A.A.8B18.4B10.4B
27.8B20.15B$3.2A2.A4.5B20.4B8.4B29.6B19.2QB.12B$.3A.2A4.6B21.4B6.4B
31.4B19.Q.QB2.11B$A4.B6.6B21.4B4.4B31.6B18.Q5.10B$.3AB2AB3.7B22.4B2.
4B31.8B16.2Q5.2B2Q6B$3.A.2AB.8B24.8B31.4B2.4B21.3B2Q6B$7.10B25.6B31.
4B4.4B21.10B$7.6B2A3B25.4B31.4B6.4B20.8B.B2Q.Q$7.6B2A2B5.2A18.6B29.4B
8.4B18.7B3.B2QB3Q$7.10B5.A18.8B27.4B10.4B17.6B6.B4.Q$6.11B2.BA.A17.4B
2.4B25.4B12.4B17.6B4.2Q.3Q$6.12B.B2A17.4B4.4B23.4B14.4B16.5B4.Q2.2Q$
5.15B18.4B6.4B21.4B16.4B14.8B.Q.Q$4.16B17.4B8.4B19.4B18.4B4.Q8.8BQ.Q.
3Q$.2B.16B5.pA10.4B10.4B10.pA6.4B20.4B3.3Q6.6B.2BQB.Q2.Q$2A18B5.3pA7.
4B12.4B7.3pA5.4B22.4B5.Q4.7B2.2B2.Q.Q.Q$2AB.17B7.pA5.4B14.4B5.pA7.4B
24.4B3.2Q4.7B3.B.2Q2.Q.Q$.B.4B.8B2.4B5.2pA4.4B16.4B4.2pA5.4B26.4B2.4B
.8B2.Q.Q2.Q.Q.Q$8.7B4.4B4.9B18.9B4.4B28.4B3.11B2.2Q2.2Q.2Q$9.6B5.4B5.
6B20.6B5.4B30.4B.12B$11.4B6.4B2.8B20.8B2.4B32.B3Q12B$13.3BA5.15B16.
15B34.Q13B10.Q$14.BA.A5.14B16.14B36.Q9B11.3Q$15.A.A6.13B16.13B36.12B
9.Q$16.A8.10B.B2pA12.2pAB.10B36.16B6.2Q$17.3A7.3B2pAB3.BpA.pA10.pA.pA
B3.B2pA3B31.Q6.24B$19.A7.3B2pAB6.pA10.pA6.B2pA3B31.3Q3.23B$29.4B6.2pA
8.2pA6.4B36.Q2.24B$29.3B26.3B35.Q.B.24B$26.pAB.2B28.2B.BpA32.2Q27B$
25.pA.pAB2pAB26.B2pABpA.pA29.2Q2.Q22B.4B$25.pA.pABpABpAB24.BpABpABpA.
pA28.Q2.3Q3B3.2B3.B7.2B3.4B$22.2pA.pA.pA.pA.pA2.pA20.pA2.pA.pA.pA.pA.
2pA26.Q4.2B3.4B.3B5.BQ2B3.4B$22.pA2.pA2.2pA.4pA20.4pA.2pA2.pA2.pA27.
4Q5.B2QB.B2QB4.Q.Q5.3BQ$24.2pA4.pA28.pA4.2pA31.Q7.2Q3.2Q6.Q7.QBQ$30.pA
.pA24.pA.pA39.Q27.2Q$31.2pA24.2pA39.2Q28.B!

Code: Select all

gun_1061:  18354 ->   8256
gun_1069:   8840 ->   8450
gun_1093:  19454 ->   8778
gun_1109:  12024 ->   8910
gun_1117:  20300 ->   9112
gun_1181:  10355 ->   9936
gun_1213:  23864 ->  10508
gun_1229:  24486 ->  10650
gun_1237:  24800 ->  10872
gun_1277:  26400 ->  11388
gun_1301:  27384 ->  11766
gun_1373:  30444 ->  12936
gun_1381:  30794 ->  13182
gun_1429:  32936 ->  14000
gun_1453:  34034 ->  14418
gun_1549:  38606 ->  16150
gun_1597:  41000 ->  17052
gun_1613:  41814 ->  17226
gun_1693:  21840 ->  18928
gun_1877:  24585 ->  22638

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication145
{
    class Pattern : IEquatable<Pattern>
    {
        public readonly int Width;
        public readonly int Height;
        static byte[] lookup;
        byte[] cells;

        static Pattern()
        {
            lookup = new byte[16];
            lookup[3] = 1;
            lookup[10] = 1;
            lookup[11] = 1;
        }

        public Pattern(int width, int height)
        {
            Width = width;
            Height = height;
            cells = new byte[Width * Height];
        }

        public Pattern(int width, int height, Pattern source, int offsetX, int offsetY)
            : this(width, height)
        {
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    this[x, y] = source[x + offsetX, y + offsetY];
        }

        public byte this[int x, int y]
        {
            get
            {
                return cells[x + y * Width];
            }
            set
            {
                cells[x + y * Width] = value;
            }
        }

        public Pattern Advance()
        {
            var result = new Pattern(Width, Height);
            for (int y = 0; y < Height; y++)
            {
                int ym1 = y == 0 ? Height - 1 : y - 1;
                int yp1 = y == Height - 1 ? 0 : y + 1;
                for (int x = 0; x < Width; x++)
                {
                    int xm1 = x == 0 ? Width - 1 : x - 1;
                    int xp1 = x == Width - 1 ? 0 : x + 1;
                    int neighbours =
                        this[xm1, ym1] +
                        this[x, ym1] +
                        this[xp1, ym1] +
                        this[xm1, y] +
                        this[xp1, y] +
                        this[xm1, yp1] +
                        this[x, yp1] +
                        this[xp1, yp1];
                    result[x, y] = lookup[neighbours & 7 | this[x, y] << 3];
                }
            }
            return result;
        }

        public void Clear(int startX, int startY, int countX, int countY)
        {
            for (int y = 0; y < countY; y++)
                for (int x = 0; x < countX; x++)
                    this[x + startX, y + startY] = 0;
        }

        public bool Search(Pattern pattern, int startX, int startY, int countX, int countY)
        {
            for (int y1 = 0; y1 < countY; y1++)
            {
                for (int x1 = 0; x1 < countX; x1++)
                {
                    bool found = true;
                    for (int y2 = 0; y2 < pattern.Height; y2++)
                    {
                        for (int x2 = 0; x2 < pattern.Width; x2++)
                        {
                            if (this[startX + x1 + x2, startY + y1 + y2] != pattern[x2, y2])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (!found)
                            break;
                    }
                    if (found)
                        return true;
                }
            }
            return false;
        }

        public Pattern Normalize(ref int period)
        {
            Pattern gliderTop1 = ReadRLE("x = 3, y = 3", "3o$2bo$bo!");
            Pattern gliderTop2 = ReadRLE("x = 3, y = 3", "3o$o$bo!");
            Pattern gliderBottom1 = ReadRLE("x = 3, y = 3", "bo$2bo$3o!");
            Pattern gliderBottom2 = ReadRLE("x = 3, y = 3", "bo$o$3o!");
            Pattern gliderLeft1 = ReadRLE("x = 3, y = 3", "2o$obo$o!");
            Pattern gliderLeft2 = ReadRLE("x = 3, y = 3", "o$obo$2o!");
            Pattern gliderRight1 = ReadRLE("x = 3, y = 3", "2bo$obo$b2o!");
            Pattern gliderRight2 = ReadRLE("x = 3, y = 3", "b2o$obo$2bo!");

            Pattern expanded = new Pattern(Width + 6, Height + 6);
            expanded.Stamp(this, 3, 3);

            int lastPeriod = int.MinValue;
            int gliderTick = int.MaxValue;
            var latestGenerations = new List<Pattern>();
            for (int tick = 0; tick < 40000; tick++)
            {
                bool gliderFound =
                    expanded.Search(gliderTop1, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderTop2, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderBottom1, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderBottom2, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderLeft1, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderLeft2, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight1, Width + 3, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight2, Width + 3, 0, 1, Height + 4);
                if (gliderFound)
                {
                    expanded.Clear(0, 0, expanded.Width, 3);
                    expanded.Clear(0, Height + 3, expanded.Width, 3);
                    expanded.Clear(0, 0, 3, expanded.Height);
                    expanded.Clear(Width + 3, 0, 3, expanded.Height);
                    period = tick - gliderTick;
                    if (period == lastPeriod)
                        return new Pattern(Width, Height, latestGenerations[0], 3, 3);
                    else
                    {
                        gliderTick = tick;
                        lastPeriod = period;
                    }
                }
                latestGenerations.Add(expanded);
                if (latestGenerations.Count > 12)
                    latestGenerations.RemoveAt(0);
                expanded = expanded.Advance();
            }
            return null;
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.Height; y++)
                for (int x = 0; x < stamp.Width; x++)
                    this[x + xo, y + yo] |= stamp[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {Width}, y = {Height}, rule = B3/S23");
            var tags = new List<char>();
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                    tags.Add(this[x, y] == 1 ? 'o' : 'b');
                tags.Add(y == Height - 1 ? '!' : '$');
            }
            int lineLength = 0;
            for (int i = 0; i < tags.Count; i++)
            {
                int runCount = 1;
                while (i + 1 < tags.Count && tags[i] == tags[i + 1])
                {
                    i++;
                    runCount++;
                }
                string run = runCount == 1 ? $"{tags[i]}" : $"{runCount}{tags[i]}";
                if (lineLength + run.Length > 70)
                {
                    sb.AppendLine();
                    lineLength = 0;
                }
                sb.Append(run);
                lineLength += run.Length;
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public static Pattern ReadRLE(params string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";
            Pattern pattern = null;
            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                {
                    var match = Regex.Match(line, "^x = ([0-9]+), y = ([0-9]+)");
                    if (!match.Success)
                        throw new Exception();
                    int width = int.Parse(match.Groups[1].Value);
                    int height = int.Parse(match.Groups[2].Value);
                    pattern = new Pattern(width, height);
                    continue;
                }

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                pattern[x, y] = c == 'o' ? (byte)1 : (byte)0;
                                x++;
                                pattern.WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
            return pattern;
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        public override int GetHashCode()
        {
            int shift = 0;
            int hash = Width << 16 | Height;
            for (int i = 0; i < cells.Length; i++)
            {
                hash = hash ^ cells[i] << shift;
                shift = (shift + 1) & 31;
            }
            return hash;
        }

        public bool Equals(Pattern other)
        {
            if (Width != other.Width || Height != other.Height)
                return false;
            for (int i = 0; i < cells.Length; i++)
                if (cells[i] != other.cells[i])
                    return false;
            return true;
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += Width;
            else if (x >= Width)
                x -= Width;
            if (y < 0)
                y += Height;
            else if (y >= Height)
                y -= Width;
        }
    }

    class Component
    {
        public int X1;
        public int Y1;
        public int X2;
        public int Y2;
        public Pattern Pattern;

        public int X
        {
            get { return X1 + X2; }
        }

        public int Y
        {
            get { return Y1 + Y2; }
        }

        public Component(int x, int y, Pattern pattern)
        {
            X1 = x;
            Y1 = y;
            Pattern = pattern;
        }
    };

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        static Pattern Combine(params Component[] components)
        {
            int minX = int.MaxValue;
            int minY = int.MaxValue;

            foreach (var component in components)
            {
                minX = Math.Min(minX, component.X);
                minY = Math.Min(minY, component.Y);
            }

            int width = 0;
            int height = 0;
            foreach (var component in components)
            {
                width = Math.Max(width,
                    component.X + component.Pattern.Width - minX);
                height = Math.Max(height,
                    component.Y + component.Pattern.Height - minY);
            }

            Pattern pattern = new Pattern(width, height);
            foreach (var component in components)
            {
                pattern.Stamp(component.Pattern,
                    component.X - minX, component.Y - minY);
            }
            return pattern;
        }

        Program()
        {
            Component part1 = new Component(0, 0, Pattern.ReadRLE(
                "x = 33, y = 54, rule = B3/S23",
                "27bo$25b3o$24bo$24b2o2$7bo$7b3o$10bo$9b2o3$10b2o19b2o$10b2o19b2o8$3b2o",
                "$2bo2bo2b2o$3b2o2bobo$5b2o16b2o$5bo17bo$2b2obo2bo15b3o$2bob2obobo16bo$",
                "6bobo$3b2o2bo$b3ob2o$o$b3ob2o$3bob2o2$13b2o$13b2o7b2o$22bo$20bobo$20b",
                "2o4$2o$2o5$16bo$15bobo$15bobo$16bo$17b3o$19bo!"
            ));
            Component part2 = new Component(22, 41, Pattern.ReadRLE(
                "x = 46, y = 23, rule = B3/S23",
                "3bo38bo$3b3o34b3o$6bo32bo$5b2o32b2o7$15b2o12b2o$8b2o5bobo10bobo5b2o$8b",
                "2o7bo10bo7b2o$17b2o8b2o2$4bo36bo$3bobob2o28b2obobo$3bobobobo26bobobobo",
                "$2obobobobo2bo20bo2bobobobob2o$o2bo2b2ob4o20b4ob2o2bo2bo$2b2o4bo28bo4b",
                "2o$8bobo24bobo$9b2o24b2o!"
            ));
            Component part3 = new Component(62, 0, Pattern.ReadRLE(
                "x = 44, y = 25, rule = B3/S23",
                "9b2o$8bobo$2b2o4bo24b2o$o2bo2b2ob4o20bobo$2obobobobo2bo22bo4b2o$3bobob",
                "obo21b4ob2o2bo2bo$3bobob2o22bo2bobobobob2o$4bo29bobobobo$35b2obobo$17b",
                "2o20bo$8b2o7bo$8b2o5bobo7b2o$15b2o9bo7b2o$26bobo5b2o$27b2o5$5b2o$6bo$",
                "3b3o31b2o$3bo33bo$38b3o$40bo!"
            ));
            Component part4 = new Component(93, 13, Pattern.ReadRLE(
                "x = 36, y = 51, rule = B3/S23",
                "16bo$16b3o$19bo$18bobo$18bobo$19bo5$34b2o$34b2o4$14b2o$13bobo$13bo$12b",
                "2o7b2o$21b2o2$29b2obo$29b2ob3o$35bo$29b2ob3o$28bo2b2o$27bobo$9bo16bobo",
                "b3o$9b3o15bo2bo2bo$12bo17bobobo$11b2o16b2o2bobo$26bobo2bobobo$26b2o2b",
                "2ob2o2$9b3o$9bo23bo$10bo20b3o$30bo$30b2o$bo$b3o$4bo$3bo$3b2o$b2o2bo$o",
                "2b3o$bo23bo$2b4o6b2o3b2o5bobo8bo$4bo7b2o3b2o6bo7bobo$6bo27b2o$5b2o!"
            ));

            var newGuns = new Dictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            int shiftMin = 0;
            int shiftMax = 150;

            int gunCount = shiftMax - shiftMin + 1;

            Console.Write($"Generating {gunCount} guns...");

            for (int shift = shiftMin; shift <= shiftMax; shift++)
            {
                int shiftD = shift / 3;
                int shiftM = shift % 3;
                int shiftA = shiftD + (shiftM > 0 ? 1 : 0);
                int shiftB = shiftD + (shiftM > 1 ? 1 : 0);
                int shiftC = shiftD;

                part2.X2 = shiftA;
                part2.Y2 = shiftA;
                part3.X2 = shiftA + shiftB;
                part3.Y2 = shiftA - shiftB;
                part4.X2 = shiftA + shiftB + shiftC;
                part4.Y2 = shiftA - shiftB + shiftC;

                Pattern gun = Combine(part1, part2, part3, part4);

                int period = 0;
                Pattern normalizedGun = gun.Normalize(ref period);
                if (normalizedGun == null)
                {
                    Console.Write('x');
                    gun.WriteRLE($"gun_x_{shift}.rle");
                    continue;
                }
                else
                    Console.Write('.');

                int area = normalizedGun.Width * normalizedGun.Height;
                if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                    continue;

                newGuns[period] = normalizedGun;
                newGunsCosts[period] = area;
            }
            Console.WriteLine(" Done");

            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            string logName = "report.txt";
            File.Delete(logName);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                if (!IsPrime(period) || period > 9999)
                    continue;

                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                string reportLine = $"gun_{period,-4}: {costS} -> {area,6}";
                Console.WriteLine(reportLine);
                File.AppendAllLines(logName, new string[] { reportLine });
                gun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 20th, 2024, 4:40 pm

Vort wrote:
June 19th, 2024, 3:34 pm
Not much left to completely process this source: 105 guns.
Only 27 guns left:

Code: Select all

gun_1031:  13224 ->   8064   p00863_21
gun_1039:  13455 ->   8255   p00863_22
gun_1051:   8064 ->   8001   p00867_23
gun_1063:        ->   8580   p00863_25
gun_1087:        ->   8911   p00863_28
gun_1091:   8613 ->   8580   p00867_28
gun_1103:        ->   9045   p00863_30
gun_1123:   8989 ->   8976   p00867_32
gun_1151:        ->   9729   p00863_36
gun_1223:        ->  10800   p00863_45
gun_1231:        ->  11023   p00863_46
gun_1279:        ->  11682   p00991_36
gun_1303:        ->  12060   p00991_39
gun_1319:        ->  12312   p00863_57
gun_1327:        ->  12444   p00991_42
gun_1367:        ->  13104   p00863_63
gun_1399:        ->  13632   p00991_51
gun_1423:        ->  14040   p00991_54
gun_1439:        ->  14337   p00863_72
gun_1447:        ->  14454   p00991_57
gun_1511:        ->  15624   p00863_81
gun_1543:        ->  16170   p00991_69
gun_1559:        ->  16512   p00863_87
gun_1567:        ->  16614   p00991_72
gun_1583:        ->  16965   p00863_90
gun_1607:        ->  17424   p00863_93
gun_1663:        ->  18450   p00991_84
upd. Done. All guns from this source are processed.

Updated area chart:
gun_coll_area_v14.png
gun_coll_area_v14.png (45.85 KiB) Viewed 2596 times

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » June 23rd, 2024, 3:42 pm

I significantly changed my gun generation script:
1. Simulation is 5 times faster (now 1 gun needs ~1 second to validate);
2. Parameters generation is separated from validation;
3. Guns are generated in random order to produce more uniform load.

Also this script allowed to process gun_9973 family:

Code: Select all

gun_1783:  20776 ->  14756
gun_1789:  19005 ->  14762
gun_1823:  16482 ->  15367
gun_1831:  18760 ->  15494
gun_1847:  20305 ->  15744
gun_1861:  19936 ->  15875
gun_1877:  22638 ->  16128
gun_1879:  20286 ->  16250
gun_1901:  20880 ->  16512
gun_1933:  21900 ->  17030
gun_1949:  22046 ->  17292
gun_1973:  22192 ->  17688
gun_1997:  22484 ->  18090
gun_2029:  22776 ->  18632
gun_2039:  24585 ->  18900
gun_2069:  23068 ->  19460
gun_2081:  25564 ->  17030
gun_2087:  26040 ->  19734
gun_2089:  25885 ->  17161
gun_2113:  26208 ->  17292
gun_2129:  26533 ->  17423
gun_2137:  26860 ->  17554
gun_2153:  27189 ->  17685
gun_2281:  30728 ->  19877
gun_2377:  31832 ->  14760
gun_2393:  15240 ->  14760
gun_2411:  17292 ->  13920
gun_2441:  32922 ->  15250
gun_2459:  17822 ->  14396
gun_2467:  18090 ->  14518
gun_2473:  33652 ->  15748
gun_2521:  33306 ->  16254
gun_2531:  18632 ->  15125
gun_2539:  18906 ->  15250
gun_2579:  16184 ->  15621
gun_2593:  34224 ->  17028
gun_2609:  34410 ->  17028
gun_2617:  34410 ->  17290
gun_2633:  34782 ->  17290
gun_2657:  34968 ->  17554
gun_2659:  20306 ->  16510
gun_2663:  34532 ->  17408
gun_2671:  30976 ->  17408
gun_2677:  34338 ->  15246
gun_2683:  20592 ->  16768
gun_2687:  31329 ->  17544
gun_2689:  35343 ->  18088
gun_2693:  34515 ->  15372
gun_2707:  20880 ->  17028
gun_2711:  35084 ->  17680
gun_2713:  35532 ->  18358
gun_2719:  32041 ->  17680
gun_2729:  35910 ->  18358
gun_2731:  21170 ->  17290
gun_2741:  19028 ->  15624
gun_2749:  35476 ->  15624
gun_2753:  36099 ->  18630
gun_2767:  22638 ->  17952
gun_2777:  36290 ->  18904
gun_2789:  36234 ->  15876
gun_2791:  22484 ->  18088
gun_2797:  36432 ->  15876
gun_2837:  21903 ->  16128
gun_2851:  22650 ->  18630
gun_2861:  21900 ->  16254
gun_2879:  23079 ->  18632
gun_2887:  22922 ->  18632
gun_2903:  22922 ->  18768
gun_2909:  22046 ->  16637
gun_2917:  22197 ->  16768
gun_2927:  23373 ->  18904
gun_2957:  22338 ->  17157
gun_2999:  23360 ->  19312
gun_3023:  23814 ->  19448
gun_3037:  22630 ->  18088
gun_3061:  22932 ->  18358
gun_3079:  23961 ->  19720
gun_3109:  23079 ->  18904
gun_3119:  24585 ->  19992
gun_3691:  31680 ->  14520
gun_3739:  24462 ->  15006
gun_3779:  24472 ->  15252
gun_3797:  22344 ->  14762
gun_3803:  24472 ->  15006
gun_3821:  22344 ->  14520
gun_3851:  24633 ->  15500
gun_3853:  22644 ->  14640
gun_3877:  22644 ->  15252
gun_3907:  24948 ->  16256
gun_3917:  22638 ->  15500
gun_3923:  24955 ->  15750
gun_3931:  25110 ->  16002
gun_3947:  24955 ->  16512
gun_3989:  22932 ->  15750
gun_4003:  25272 ->  16256
gun_4007:  19044 ->  15120
gun_4013:  22932 ->  15624
gun_4019:  25277 ->  16770
gun_4021:  23088 ->  15750
gun_4027:  25434 ->  17030
gun_4049:  25102 ->  17680
gun_4051:  25434 ->  16770
gun_4073:  25256 ->  17544
gun_4079:  23506 ->  15624
gun_4091:  25438 ->  17030
gun_4093:  23384 ->  16128
gun_4099:  25596 ->  17292
gun_4111:  23961 ->  15624
gun_4127:  23652 ->  15498
gun_4129:  24776 ->  17952
gun_4133:  23373 ->  16383
gun_4139:  25599 ->  17556
gun_4153:  24928 ->  17816
gun_4157:  23373 ->  17030
gun_4159:  24272 ->  15876
gun_4177:  24928 ->  18224
gun_4201:  25245 ->  18088
gun_4211:  26082 ->  17822
gun_4217:  25885 ->  18360
gun_4219:  26243 ->  18090
gun_4229:  23828 ->  17292
gun_4231:  21025 ->  16002
gun_4241:  25885 ->  18224
gun_4243:  26243 ->  17822
gun_4253:  23828 ->  17160
gun_4259:  26406 ->  18360
gun_4261:  23989 ->  17292
gun_4271:  24750 ->  16256
gun_4273:  25564 ->  18224
gun_4283:  26406 ->  18090
gun_4289:  26208 ->  18496
gun_4297:  25885 ->  18632
gun_4327:  21904 ->  16128
gun_4337:  26533 ->  18768
gun_4339:  26895 ->  18906
gun_4349:  24450 ->  18090
gun_4357:  24613 ->  18360
gun_4363:  27224 ->  18632
gun_4373:  24764 ->  17955
gun_4391:  22500 ->  17030
gun_4397:  24928 ->  18632
gun_4409:  27189 ->  18904
gun_4421:  25245 ->  18360
gun_4423:  22801 ->  17030
gun_4441:  26860 ->  18904
gun_4447:  26690 ->  16899
gun_4451:  27722 ->  19460
gun_4457:  27520 ->  19176
gun_4463:  26702 ->  17292
gun_4481:  27520 ->  19040
gun_4493:  25896 ->  18768
gun_4513:  27189 ->  19040
gun_4517:  26219 ->  19460
gun_4519:  23716 ->  18090
gun_4549:  26386 ->  19460
gun_4561:  27520 ->  19312
gun_4567:  27864 ->  17688
gun_4583:  22338 ->  18090
gun_4591:  22638 ->  18360
gun_4639:  23244 ->  18906
gun_4649:  24178 ->  19720
gun_4657:  24490 ->  20002
gun_4663:  23088 ->  18632
gun_4673:  23868 ->  19584
gun_4679:  22484 ->  19182
gun_4703:  23393 ->  18906
gun_4721:  24645 ->  20002
gun_4729:  23712 ->  20286
gun_4751:  22932 ->  19460
gun_4759:  23236 ->  19740
gun_4783:  23079 ->  19460
gun_4793:  23864 ->  20286
gun_4799:  23691 ->  20022
gun_4801:  24174 ->  20572
gun_4817:  24800 ->  21150
gun_5077:  23079 ->  15252
gun_5101:  23068 ->  14520
gun_5167:  23961 ->  15006
gun_5189:  23691 ->  15750
gun_5197:  23214 ->  16002
gun_5231:  16728 ->  15500
gun_5237:  23520 ->  15750
gun_5261:  23360 ->  15128
gun_5279:  16864 ->  15500
gun_5303:  24900 ->  14883
gun_5309:  23989 ->  16512
gun_5333:  23828 ->  15750
gun_5351:  24585 ->  16256
gun_5381:  24462 ->  15750
gun_5387:  26568 ->  17408
gun_5393:  26533 ->  15372
gun_5399:  25217 ->  16256
gun_5407:  25536 ->  16512
gun_5413:  24462 ->  16770
gun_5417:  26533 ->  15750
gun_5431:  25536 ->  15750
gun_5437:  24613 ->  16002
gun_5441:  26208 ->  15372
gun_5443:  26732 ->  17544
gun_5449:  26533 ->  15498
gun_5471:  17408 ->  15624
gun_5477:  24776 ->  17292
gun_5479:  25551 ->  15750
gun_5501:  24928 ->  16512
gun_5503:  26180 ->  16512
gun_5507:  27060 ->  17680
gun_5519:  17544 ->  17030
gun_5521:  27189 ->  15876
gun_5527:  26026 ->  15875
gun_5531:  27552 ->  18088
gun_5557:  25245 ->  16770
gun_5563:  27885 ->  17816
gun_5569:  26860 ->  15876
gun_5573:  25410 ->  17292
gun_5581:  25410 ->  17556
gun_5591:  26520 ->  16256
gun_5639:  26702 ->  16383
gun_5641:  27520 ->  16512
gun_5647:  26860 ->  16512
gun_5651:  28054 ->  18496
gun_5653:  25896 ->  16899
gun_5657:  27189 ->  15750
gun_5659:  28220 ->  18632
gun_5669:  25896 ->  17292
gun_5683:  28390 ->  18224
gun_5689:  27189 ->  16512
gun_5693:  26219 ->  18090
gun_5701:  26219 ->  18360
gun_5711:  18088 ->  17030
gun_5717:  26386 ->  17292
gun_5737:  28188 ->  16512
gun_5741:  26712 ->  18090
gun_5743:  27692 ->  18090
gun_5749:  26712 ->  18360
gun_5779:  28728 ->  18360
gun_5783:  28026 ->  17822
gun_5791:  28188 ->  18090
gun_5801:  28525 ->  17030
gun_5807:  18360 ->  17160
gun_5813:  27209 ->  18906
gun_5821:  27209 ->  17688
gun_5827:  28730 ->  19040
gun_5839:  28372 ->  18090
gun_5843:  29068 ->  14518
gun_5849:  28362 ->  17030
gun_5851:  29237 ->  14760
gun_5857:  28525 ->  17292
gun_5861:  27378 ->  14750
gun_5867:  29240 ->  15250
gun_5869:  27710 ->  14994
gun_5879:  28875 ->  17822
gun_5881:  28536 ->  16512
gun_5897:  28864 ->  17030
gun_5903:  18769 ->  18632
gun_5923:  29412 ->  15250
gun_5927:  29058 ->  17822
gun_5939:  29754 ->  15748
gun_5953:  29216 ->  17292
gun_5981:  28386 ->  16758
gun_5987:  29756 ->  15498
gun_6007:  29913 ->  18906
gun_6011:  30272 ->  16254
gun_6029:  28896 ->  16500
gun_6037:  28896 ->  16758
gun_6043:  30272 ->  15498
gun_6047:  19600 ->  16244
gun_6053:  28896 ->  15488
gun_6067:  30448 ->  16254
gun_6073:  30090 ->  18090
gun_6079:  30609 ->  16768
gun_6089:  30430 ->  18492
gun_6091:  30275 ->  15250
gun_6101:  29410 ->  17018
gun_6113:  30609 ->  17822
gun_6121:  30780 ->  18090
gun_6131:  30798 ->  16510
gun_6133:  29754 ->  16244
gun_6143:  20164 ->  16899
gun_6151:  30798 ->  17030
gun_6163:  30798 ->  15748
gun_6173:  29928 ->  17544
gun_6197:  30275 ->  16500
gun_6199:  31500 ->  16899
gun_6203:  31325 ->  17028
gun_6211:  30800 ->  17290
gun_6217:  31494 ->  18090
gun_6221:  30450 ->  17280
gun_6229:  30450 ->  17544
gun_6247:  31683 ->  16768
gun_6257:  32025 ->  18492
gun_6263:  32037 ->  17030
gun_6269:  30800 ->  17018
gun_6271:  32214 ->  17161
gun_6277:  30800 ->  17280
gun_6287:  21025 ->  17423
gun_6299:  31680 ->  16510
gun_6301:  30976 ->  18078
gun_6311:  32220 ->  16899
gun_6317:  31329 ->  16758
gun_6323:  31860 ->  17290
gun_6329:  32218 ->  18632
gun_6337:  32396 ->  18906
gun_6343:  32400 ->  17423
gun_6353:  32752 ->  19182
gun_6359:  32760 ->  17685
gun_6361:  32578 ->  19320
gun_6367:  32940 ->  16899
gun_6373:  31506 ->  16758
gun_6379:  32040 ->  17290
gun_6389:  31862 ->  17280
gun_6397:  31862 ->  17544
gun_6421:  32040 ->  18348
gun_6427:  32396 ->  17028
gun_6449:  33666 ->  18906
gun_6451:  32578 ->  17820
gun_6469:  32399 ->  18078
gun_6473:  33670 ->  19320
gun_6481:  33852 ->  19458
gun_6491:  32757 ->  17290
gun_6521:  33856 ->  19182
gun_6529:  34040 ->  19320
gun_6547:  33120 ->  17290
gun_6551:  34410 ->  18216
gun_6553:  34225 ->  19734
gun_6563:  33485 ->  17820
gun_6569:  34595 ->  20010
gun_6571:  33485 ->  18088
gun_6577:  34780 ->  19182
gun_6581:  33485 ->  18078
gun_6599:  34592 ->  17947
gun_6607:  34780 ->  18216
gun_6619:  33666 ->  17820
gun_6637:  34034 ->  18078
gun_6653:  34034 ->  18620
gun_6659:  34216 ->  19180
gun_6661:  34034 ->  18894
gun_6673:  35532 ->  19872
gun_6689:  35532 ->  20148
gun_6691:  34587 ->  18358
gun_6701:  34587 ->  18348
gun_6703:  35717 ->  17816
gun_6709:  34587 ->  18620
gun_6719:  23716 ->  18216
gun_6733:  34770 ->  19448
gun_6737:  36100 ->  20010
gun_6761:  36290 ->  20424
gun_6763:  35144 ->  18904
gun_6779:  35144 ->  19458
gun_6781:  35144 ->  19170
gun_6791:  36278 ->  18760
gun_6793:  36480 ->  20010
gun_6803:  35328 ->  18358
gun_6823:  36660 ->  17947
gun_6827:  35705 ->  19180
gun_6829:  35705 ->  18894
gun_6833:  37056 ->  19734
gun_6841:  36666 ->  19872
gun_6857:  37054 ->  20148
gun_6863:  24649 ->  19312
gun_6869:  35890 ->  20294
gun_6883:  36270 ->  19180
gun_6899:  36270 ->  19738
gun_6907:  36270 ->  20020
gun_6911:  24964 ->  19035
gun_6917:  36270 ->  20010
gun_6947:  36839 ->  19458
gun_6949:  36456 ->  19170
gun_6959:  25281 ->  18760
gun_6961:  38218 ->  20010
gun_6967:  38200 ->  19035
gun_6971:  36839 ->  20304
gun_6977:  38016 ->  20286
gun_6983:  31584 ->  19591
gun_6991:  31941 ->  19872
gun_6997:  37026 ->  20868
gun_7001:  38208 ->  20700
gun_7013:  37026 ->  19448
gun_7019:  37412 ->  20020
gun_7027:  37412 ->  20304
gun_7039:  31229 ->  19591
gun_7043:  33855 ->  20878
gun_7057:  32697 ->  20700
gun_7069:  31450 ->  21450
gun_7079:  31752 ->  19035
gun_7103:  26244 ->  19872
gun_7109:  30895 ->  20868
gun_7121:  32870 ->  20838
gun_7129:  33234 ->  21128
gun_7151:  26569 ->  19591
gun_7159:  32661 ->  19872
gun_7177:  34161 ->  20838
gun_7193:  33425 ->  21420
gun_7207:  32110 ->  19591
gun_7247:  27225 ->  21016
gun_7297:  34161 ->  21128
gun_7321:  33792 ->  22010
gun_7793:  26850 ->  15250
gun_7817:  26460 ->  16000
gun_7841:  27000 ->  16768
gun_7867:  26313 ->  14518
gun_7873:  26820 ->  15250
gun_7883:  25740 ->  15004
gun_7907:  26280 ->  15748
gun_7937:  27331 ->  14760
gun_7963:  26640 ->  15004
gun_7993:  26754 ->  16510
gun_8009:  27118 ->  17028
gun_8011:  26788 ->  16510
gun_8017:  27300 ->  17290
gun_8059:  26969 ->  15498
gun_8081:  27846 ->  16768
gun_8089:  27084 ->  17028
gun_8093:  26754 ->  15246
gun_8101:  26936 ->  15372
gun_8111:  28365 ->  17544
gun_8117:  27300 ->  15624
gun_8123:  26754 ->  15004
gun_8147:  17680 ->  15748
gun_8161:  27816 ->  16768
gun_8171:  27084 ->  16510
gun_8179:  27084 ->  16768
gun_8209:  27968 ->  15748
gun_8219:  17816 ->  15498
gun_8231:  28336 ->  18224
gun_8233:  27784 ->  16510
gun_8237:  27600 ->  16254
gun_8243:  27450 ->  16254
gun_8269:  27784 ->  15498
gun_8273:  28520 ->  17820
gun_8287:  28675 ->  17816
gun_8291:  17952 ->  17820
gun_8293:  27784 ->  15876
gun_8297:  28120 ->  16000
gun_8311:  29230 ->  18224
gun_8329:  28305 ->  17028
gun_8353:  28490 ->  17820
gun_8363:  18088 ->  17554
gun_8369:  28860 ->  18358
gun_8377:  28644 ->  16000
gun_8387:  28120 ->  15748
gun_8389:  28305 ->  16128
gun_8419:  28305 ->  16768
gun_8423:  29016 ->  18768
gun_8429:  28644 ->  17290
gun_8443:  28305 ->  17554
gun_8461:  28830 ->  16002
gun_8467:  28644 ->  18358
gun_8501:  28830 ->  17028
gun_8513:  29359 ->  17820
gun_8521:  29359 ->  18088
gun_8537:  29359 ->  18630
gun_8539:  28830 ->  18088
gun_8563:  29172 ->  16254
gun_8573:  29359 ->  16768
gun_8581:  29359 ->  17028
gun_8597:  29359 ->  17554
gun_8599:  22499 ->  19040
gun_8609:  29704 ->  18358
gun_8627:  29359 ->  18358
gun_8629:  29704 ->  16128
gun_8641:  29892 ->  16768
gun_8647:  30456 ->  18496
gun_8663:  22800 ->  18768
gun_8669:  29892 ->  17290
gun_8677:  29892 ->  17554
gun_8681:  30240 ->  18088
gun_8689:  30240 ->  18358
gun_8693:  29892 ->  18088
gun_8699:  29892 ->  18088
gun_8707:  29892 ->  18358
gun_8713:  30429 ->  19180
gun_8731:  29892 ->  19180
gun_8737:  30429 ->  17290
gun_8741:  30240 ->  17028
gun_8747:  30240 ->  17028
gun_8753:  30429 ->  17820
gun_8761:  30780 ->  18088
gun_8779:  30240 ->  18088
gun_8783:  20724 ->  19448
gun_8803:  30429 ->  18904
gun_8807:  30970 ->  19856
gun_8819:  30429 ->  19458
gun_8821:  30780 ->  17028
gun_8831:  30970 ->  18904
gun_8837:  30780 ->  17554
gun_8839:  31160 ->  19040
gun_8849:  30970 ->  18358
gun_8861:  30970 ->  18358
gun_8863:  31324 ->  19448
gun_8867:  19320 ->  18358
gun_8887:  31324 ->  19856
gun_8893:  31324 ->  16768
gun_8923:  30970 ->  17554
gun_8929:  31515 ->  18358
gun_8933:  31324 ->  18088
gun_8941:  31515 ->  18358
gun_8951:  31872 ->  19584
gun_8963:  31324 ->  18904
gun_8969:  31872 ->  19738
gun_8971:  31324 ->  19180
gun_8999:  32064 ->  19040
gun_9001:  32064 ->  18088
gun_9007:  32064 ->  19176
gun_9011:  19880 ->  17820
gun_9013:  31872 ->  18088
gun_9029:  31872 ->  18630
gun_9041:  32064 ->  19458
gun_9043:  31872 ->  18904
gun_9049:  32424 ->  19738
gun_9059:  31872 ->  19458
gun_9067:  31872 ->  19738
gun_9091:  32064 ->  17820
gun_9103:  32617 ->  19448
gun_9109:  32424 ->  18630
gun_9127:  32617 ->  19856
gun_9133:  32617 ->  19458
gun_9137:  32617 ->  20020
gun_9151:  32980 ->  20562
gun_9157:  32617 ->  17554
gun_9161:  32980 ->  20878
gun_9173:  32617 ->  18088
gun_9181:  32980 ->  18358
gun_9187:  32617 ->  18358
gun_9199:  33174 ->  19720
gun_9203:  32617 ->  18904
gun_9209:  33174 ->  19738
gun_9221:  32980 ->  19738
gun_9227:  20735 ->  19738
gun_9239:  25599 ->  20850
gun_9241:  33540 ->  20878
gun_9257:  33540 ->  18630
gun_9277:  33540 ->  18904
gun_9281:  33540 ->  19458
gun_9283:  19050 ->  18904
gun_9293:  33540 ->  19458
gun_9311:  33735 ->  20562
gun_9319:  33735 ->  20850
gun_9323:  33540 ->  20304
gun_9337:  34104 ->  21460
gun_9341:  33735 ->  18358
gun_9343:  34104 ->  19448
gun_9349:  33735 ->  18630
gun_9371:  21315 ->  19180
gun_9377:  34104 ->  20020
gun_9391:  34300 ->  20562
gun_9397:  34104 ->  20304
gun_9403:  33735 ->  20304
gun_9413:  34104 ->  18088
gun_9419:  34104 ->  20878
gun_9421:  34300 ->  18358
gun_9431:  26568 ->  19584
gun_9433:  34672 ->  19180
gun_9437:  34300 ->  18904
gun_9439:  34672 ->  19720
gun_9461:  34300 ->  19738
gun_9463:  34672 ->  20276
gun_9467:  34300 ->  19738
gun_9473:  34672 ->  20590
gun_9479:  34869 ->  20850
gun_9491:  34300 ->  20590
gun_9497:  34869 ->  21460
gun_9511:  34869 ->  22022
gun_9521:  34869 ->  22348
gun_9533:  34869 ->  19458
gun_9539:  34672 ->  19458
gun_9547:  34672 ->  19738
gun_9551:  35244 ->  20562
gun_9587:  22200 ->  21168
gun_9613:  35442 ->  19458
gun_9619:  35244 ->  22348
gun_9623:  27555 ->  20276
gun_9629:  35442 ->  20020
gun_9631:  35820 ->  20562
gun_9661:  35820 ->  21168
gun_9677:  35820 ->  18904
gun_9679:  36019 ->  22320
gun_9719:  36400 ->  20850
gun_9733:  36019 ->  20878
gun_9743:  36400 ->  21726
gun_9749:  36019 ->  21460
gun_9767:  36600 ->  22620
gun_9781:  36400 ->  19738
gun_9791:  36600 ->  20562
gun_9829:  36600 ->  21460
gun_9839:  36984 ->  22320
gun_9871:  37185 ->  23532

Code: Select all

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication145
{
    class Pattern : IEquatable<Pattern>
    {
        public readonly int Width;
        public readonly int Height;

        public readonly int WordWidth;
        public readonly int WordCount;
        ulong[] cells;

        public Pattern(int width, int height)
        {
            Width = width;
            Height = height;
            WordWidth = (Width + 15) / 16;
            WordCount = WordWidth * Height;
            cells = new ulong[WordCount];
        }

        public Pattern(int width, int height, Pattern source, int offsetX, int offsetY)
            : this(width, height)
        {
            for (int y = 0; y < Height; y++)
                for (int x = 0; x < Width; x++)
                    this[x, y] = source[x + offsetX, y + offsetY];
        }

        public bool this[int x, int y]
        {
            get
            {
                int div = x / 16;
                int shift = x % 16 * 4;
                return ((cells[div + y * WordWidth] >> shift) & 0xFUL) == 1;
            }
            set
            {
                int div = x / 16;
                int shift = x % 16 * 4;
                cells[div + y * WordWidth] &= ~(0xFUL << shift);
                cells[div + y * WordWidth] |= (value ? 1UL : 0UL) << shift;
            }
        }

        private ulong[] ShiftLeft(ulong[] src)
        {
            ulong[] result = new ulong[WordCount];
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < WordWidth; x++)
                {
                    ulong w = src[x + y * WordWidth];
                    result[x + y * WordWidth] |= w >> 4;
                    if (x != 0)
                        result[x - 1 + y * WordWidth] |= w << 60;
                    else
                    {
                        int shift = ((Width + 15) % 16) * 4;
                        result[WordWidth - 1 + y * WordWidth] |= (w & 0xFUL) << shift;
                    }
                }
            }
            return result;
        }

        private ulong[] ShiftRight(ulong[] src)
        {
            ulong[] result = new ulong[WordCount];
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < WordWidth; x++)
                {
                    ulong w = src[x + y * WordWidth];
                    result[x + y * WordWidth] |= w << 4;
                    if (x != WordWidth - 1)
                        result[x + 1 + y * WordWidth] |= w >> 60;
                    else
                    {
                        int shift1 = 64 - (Width % 16) * 4;
                        ulong mask = 0xFFFFFFFFFFFFFFFFUL >> shift1;
                        result[x + y * WordWidth] &= mask;
                        int shift2 = ((Width - 1) % 16) * 4;
                        result[y * WordWidth] |= w >> shift2;
                    }
                }
            }
            return result;
        }

        public Pattern Advance()
        {
            var result = new Pattern(Width, Height);
            var n1 = ShiftLeft(cells);
            var n2 = ShiftRight(cells);
            for (int i = 0; i < cells.Length; i++)
            {
                int im1 = i - WordWidth < 0 ? i - WordWidth + WordCount : i - WordWidth;
                int ip1 = i + WordWidth >= WordCount ? i + WordWidth - WordCount : i + WordWidth;
                ulong center = cells[i];
                ulong neighbours = n1[i] + n2[i] + n1[im1] +
                    cells[im1] + n2[im1] + n1[ip1] + cells[ip1] + n2[ip1];
                neighbours &= 0x7777777777777777UL;
                ulong born = neighbours | (center << 3);
                born ^= ~0x3333333333333333UL;
                born &= (born >> 2);
                born &= (born >> 1);
                born &= 0x1111111111111111UL;
                ulong stay = ((neighbours & ~0x1111111111111111UL) >> 1) | (center << 2);
                stay ^= ~0x5555555555555555UL;
                stay &= stay >> 2;
                stay &= stay >> 1;
                stay &= 0x1111111111111111UL;
                result.cells[i] = born | stay;
            }
            return result;
        }

        public void Clear(int startX, int startY, int countX, int countY)
        {
            for (int y = 0; y < countY; y++)
                for (int x = 0; x < countX; x++)
                    this[x + startX, y + startY] = false;
        }

        public bool Search(Pattern pattern, int startX, int startY, int countX, int countY)
        {
            for (int y1 = 0; y1 < countY; y1++)
            {
                for (int x1 = 0; x1 < countX; x1++)
                {
                    bool found = true;
                    for (int y2 = 0; y2 < pattern.Height; y2++)
                    {
                        for (int x2 = 0; x2 < pattern.Width; x2++)
                        {
                            if (this[startX + x1 + x2, startY + y1 + y2] != pattern[x2, y2])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (!found)
                            break;
                    }
                    if (found)
                        return true;
                }
            }
            return false;
        }

        public Pattern Normalize(ref int period)
        {
            Pattern gliderTop1 = ReadRLE("x = 3, y = 3", "3o$2bo$bo!");
            Pattern gliderTop2 = ReadRLE("x = 3, y = 3", "3o$o$bo!");
            Pattern gliderBottom1 = ReadRLE("x = 3, y = 3", "bo$2bo$3o!");
            Pattern gliderBottom2 = ReadRLE("x = 3, y = 3", "bo$o$3o!");
            Pattern gliderLeft1 = ReadRLE("x = 3, y = 3", "2o$obo$o!");
            Pattern gliderLeft2 = ReadRLE("x = 3, y = 3", "o$obo$2o!");
            Pattern gliderRight1 = ReadRLE("x = 3, y = 3", "2bo$obo$b2o!");
            Pattern gliderRight2 = ReadRLE("x = 3, y = 3", "b2o$obo$2bo!");

            Pattern expanded = new Pattern(Width + 6, Height + 6);
            expanded.Stamp(this, 3, 3);

            int lastPeriod = int.MinValue;
            int gliderTick = int.MaxValue;
            var latestGenerations = new List<Pattern>();
            for (int tick = 0; tick < 40000; tick++)
            {
                bool gliderFound =
                    expanded.Search(gliderTop1, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderTop2, 0, 0, Width + 4, 1) ||
                    expanded.Search(gliderBottom1, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderBottom2, 0, Height + 3, Width + 4, 1) ||
                    expanded.Search(gliderLeft1, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderLeft2, 0, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight1, Width + 3, 0, 1, Height + 4) ||
                    expanded.Search(gliderRight2, Width + 3, 0, 1, Height + 4);
                if (gliderFound)
                {
                    expanded.Clear(0, 0, expanded.Width, 3);
                    expanded.Clear(0, Height + 3, expanded.Width, 3);
                    expanded.Clear(0, 0, 3, expanded.Height);
                    expanded.Clear(Width + 3, 0, 3, expanded.Height);
                    period = tick - gliderTick;
                    if (period == lastPeriod)
                        return new Pattern(Width, Height, latestGenerations[0], 3, 3);
                    else
                    {
                        gliderTick = tick;
                        lastPeriod = period;
                    }
                }
                latestGenerations.Add(expanded);
                if (latestGenerations.Count > 12)
                    latestGenerations.RemoveAt(0);
                expanded = expanded.Advance();
            }
            return null;
        }

        public void Stamp(Pattern stamp, int xo, int yo)
        {
            for (int y = 0; y < stamp.Height; y++)
                for (int x = 0; x < stamp.Width; x++)
                    this[x + xo, y + yo] |= stamp[x, y];
        }

        public void WriteRLE(string fileName, string comment = null)
        {
            var sb = new StringBuilder();
            if (comment != null)
                sb.AppendLine($"#C {comment}");
            sb.AppendLine($"x = {Width}, y = {Height}, rule = B3/S23");
            var tags = new List<char>();
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                    tags.Add(this[x, y] ? 'o' : 'b');
                tags.Add(y == Height - 1 ? '!' : '$');
            }
            int lineLength = 0;
            for (int i = 0; i < tags.Count; i++)
            {
                int runCount = 1;
                while (i + 1 < tags.Count && tags[i] == tags[i + 1])
                {
                    i++;
                    runCount++;
                }
                string run = runCount == 1 ? $"{tags[i]}" : $"{runCount}{tags[i]}";
                if (lineLength + run.Length > 70)
                {
                    sb.AppendLine();
                    lineLength = 0;
                }
                sb.Append(run);
                lineLength += run.Length;
            }
            File.WriteAllText(fileName, sb.ToString());
        }

        public static Pattern ReadRLE(params string[] lines)
        {
            int x = 0;
            int y = 0;

            string scount = "";
            Pattern pattern = null;
            foreach (var line in lines)
            {
                if (line.StartsWith("#"))
                    continue;
                if (line.StartsWith("x"))
                {
                    var match = Regex.Match(line, "^x = ([0-9]+), y = ([0-9]+)");
                    if (!match.Success)
                        throw new Exception();
                    int width = int.Parse(match.Groups[1].Value);
                    int height = int.Parse(match.Groups[2].Value);
                    pattern = new Pattern(width, height);
                    continue;
                }

                for (int i = 0; i < line.Length; i++)
                {
                    char c = line[i];
                    if (c >= '0' && c <= '9')
                    {
                        scount += c;
                    }
                    else
                    {
                        if (c == '$')
                        {
                            x = 0;
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            y += count;
                            scount = "";
                        }
                        else if (c == '!')
                            break;
                        else if (c == 'o' || c == 'b')
                        {
                            int count = 1;
                            if (scount != "")
                                count = int.Parse(scount);
                            for (int k = 0; k < count; k++)
                            {
                                pattern[x, y] = c == 'o';
                                x++;
                                pattern.WrapCoordinates(ref x, ref y);
                            }
                            scount = "";
                        }
                    }
                }
            }
            return pattern;
        }

        public void ReadRLE(string fileName)
        {
            ReadRLE(File.ReadAllLines(fileName));
        }

        public override int GetHashCode()
        {
            int shift = 0;
            ulong hash = (ulong)(Width << 16 | Height);
            for (int i = 0; i < cells.Length; i++)
            {
                hash = hash ^ cells[i] << shift;
                shift = (shift + 1) & 3;
            }
            return (int)(hash ^ hash >> 32);
        }

        public bool Equals(Pattern other)
        {
            if (Width != other.Width || Height != other.Height)
                return false;
            for (int i = 0; i < cells.Length; i++)
                if (cells[i] != other.cells[i])
                    return false;
            return true;
        }

        void WrapCoordinates(ref int x, ref int y)
        {
            if (x < 0)
                x += Width;
            else if (x >= Width)
                x -= Width;
            if (y < 0)
                y += Height;
            else if (y >= Height)
                y -= Width;
        }
    }

    class Component
    {
        public int X1;
        public int Y1;
        public int X2;
        public int Y2;
        public Pattern Pattern;

        public int X
        {
            get { return X1 + X2; }
        }

        public int Y
        {
            get { return Y1 + Y2; }
        }

        public Component(int x, int y, Pattern pattern)
        {
            X1 = x;
            Y1 = y;
            Pattern = pattern;
        }
    }

    class Params
    {
        public int Slide1;
        public int Slide2;
        public int Mul1;
        public int Mul2;
        public int Mod;
    }

    static class ShuffleClass
    {
        private static Random rng = new Random(1234321);

        public static void Shuffle<T>(this IList<T> list)
        {
            int n = list.Count;
            while (n > 1)
            {
                n--;
                int k = rng.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }
    }

    class Program
    {
        public static bool IsPrime(int number)
        {
            if (number <= 1) return false;
            if (number == 2) return true;
            if (number % 2 == 0) return false;

            var boundary = (int)Math.Floor(Math.Sqrt(number));

            for (int i = 3; i <= boundary; i += 2)
                if (number % i == 0)
                    return false;

            return true;
        }

        static Dictionary<int, int> ParseCosts(string costsS)
        {
            var costs = new Dictionary<int, int>();
            if (costsS != null)
            {
                var lines = costsS.Split('\n');
                for (int i = 1; i < lines.Length - 1; i++)
                {
                    var spl = lines[i].Split(',');
                    int period = int.Parse(spl[0].Trim('"').Split('_')[1]);
                    int area = int.Parse(spl[1].Trim('"'));
                    costs.Add(period, area);
                }
            }
            return costs;
        }

        static Pattern Combine(params Component[] components)
        {
            int minX = int.MaxValue;
            int minY = int.MaxValue;

            foreach (var component in components)
            {
                if (component == null)
                    continue;
                minX = Math.Min(minX, component.X);
                minY = Math.Min(minY, component.Y);
            }

            int width = 0;
            int height = 0;
            foreach (var component in components)
            {
                if (component == null)
                    continue;
                width = Math.Max(width,
                    component.X + component.Pattern.Width - minX);
                height = Math.Max(height,
                    component.Y + component.Pattern.Height - minY);
            }

            Pattern pattern = new Pattern(width, height);
            foreach (var component in components)
            {
                if (component == null)
                    continue;
                pattern.Stamp(component.Pattern,
                    component.X - minX, component.Y - minY);
            }
            return pattern;
        }

        Program()
        {
            Component part1 = new Component(0, 0, Pattern.ReadRLE(
                "x = 67, y = 92, rule = B3/S23",
                "$39b2o$39bo$10b2o29bo$10bo2bo8b2o16b2o$12b2o8bo15bo3b2o$8b4o11bo14b4o",
                "2bo$8bo3b4o4b3o19b2o$10bobo2bo4bo19b2o$9b2o30bo$8bo2bo29bobo$6bo2bobo",
                "30b2o$6b2obob2o$9bo$9bob2o$8b2obo$11bo$11b2o9$12b2o$13bo$10b3o$10bo6$",
                "3b2o$4bo$4bobo15b2o$5b2o15b2o10$3b2o$2bo2bo2b2o$3b2o2bobo3b3o7b2o$5b2o",
                "7bo8bobo$5bo8b3o8bo$2b2obo2bo16b2o$2bob2obobo$6bobo$3b2o2bo$b3ob2o$o$b",
                "3ob2o$3bob2o2$13b2o$13b2o7b2o$22bo$20bobo$20b2o2$43bo11b2o$42bobo10b2o",
                "$2o28bo3bo3b2o2bobo$2o26b3o2bobo2bo2b2ob2o$27bo5bobo3bobo$27b2o5bob4o",
                "2bob2o$36bo3bobob2o$35bo3bobo$16bo17bo3bobo$15bobo16b2o3bo$15bobo$16bo",
                "$17b3o$19bo27b2o$47b2o$62b2o$61bo2bo$62b2obo$15b2o48bo$15b2o48b2o$50b",
                "2o$51bo$48b3o$48bo!"
            ));
            Component part2 = new Component(50, 71, Pattern.ReadRLE(
                "x = 41, y = 49, rule = B3/S23",
                "31bo$29b3o$28bo$28b2o3$36b2o$37bo$37bob2o$29b2o4b3o2bo$29b2o3bo3b2o$",
                "34b4o$20b2o15bo$19bobo12b3o$19bo13bo$18b2o14b5o$38bo$36bo$36b2o8$3bo$",
                "3b3o$6bo$5b2o7$15b2o$8b2o5bobo$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobobo$",
                "2obobobobo2bo$o2bo2b2ob4o$2b2o4bo$8bobo$9b2o!"
            ));
            Component[] parts3 = new Component[]
            {
                new Component(71, 96, Pattern.ReadRLE(
                    "x = 19, y = 23, rule = B3/S23",
                    "3bo$3b3o$6bo$5b2o7$15b2o$8b2o5bobo$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobo",
                    "bo$2obobobobo2bo$o2bo2b2ob4o$2b2o4bo$8bobo$9b2o!"
                )),
                new Component(73, 96, Pattern.ReadRLE(
                    "x = 21, y = 23, rule = B3/S23",
                    "bo$b3o$4bo$3b2o5$14b2ob2o$14b2obo2bo$19b2o$6b2o$6b2o4bo2bo$12b4o$18bo$",
                    "2bo11b5o$bobob2o7bo$bobobobo8bo$2obobobo2bo4b2o$bo2b2ob4o$bo4bo$2b3obo",
                    "2b2o$4b2o3b2o!"
                )),
                new Component(72, 96, Pattern.ReadRLE(
                    "x = 18, y = 25, rule = B3/S23",
                    "2bo$2b3o$5bo$4b2o7$14b2o$7b2o5bobo$7b2o7bo$16b2o5$4b2ob2o$2o3bob2o2b2o",
                    "$o2bobo6bo$2b2ob7o$4bo$4bob4o$5b2o2bo!"
                )),
                new Component(72, 96, Pattern.ReadRLE(
                    "x = 22, y = 25, rule = B3/S23",
                    "2bo$2b3o$5bo$4b2o5$15b2ob2o$15b2obo2bo$20b2o$7b2o$7b2o4bo2bo$13b4o$19b",
                    "o$15b5o$15bo$17bo$4b2ob2o7b2o$2o3bob2o2b2o$o2bobo6bo$2b2ob7o$4bo$4bob",
                    "4o$5b2o2bo!"
                ))
            };
            Component[] parts4 = new Component[]
            {
                new Component(93, 66, Pattern.ReadRLE(
                    "x = 23, y = 19, rule = B3/S23",
                    "13bo$11b3o$10bo$10b2o3$18b2o$19bo$19bob2o$11b2o4b3o2bo$11b2o3bo3b2o$",
                    "16b4o$2b2o15bo$bobo12b3o$bo13bo$2o14b5o$20bo$18bo$18b2o!"
                )),
                new Component(93, 62, Pattern.ReadRLE(
                    "x = 23, y = 21, rule = B3/S23",
                    "9b2o$10bo$8bo5b2o$8b2o5bo$15bob2o$8b2o2b2obo2bo$8b2o3bob2o$13bo$12b2o",
                    "2$18b2ob2o$19bob2o$19bo$11b2o4b3o$11b2o3bo3b2o$16b4o2bo$2b2o15bob2o$bo",
                    "bo12b3o2bo$bo13bo5bo$2o14b5o$18bo!"
                )),
                new Component(93, 66, Pattern.ReadRLE(
                    "x = 25, y = 18, rule = B3/S23",
                    "13bo$11b3o$10bo$10b2o2$19b2o$19bobo$21bo$21bob2o$11b2o5b2obobo$11b2o5b",
                    "2obobo$21bob2o$2b2o14b4o2bo$bobo14bo3b2o$bo18b2o$2o19bo$19bo$19b2o!"
                )),
                new Component(93, 62, Pattern.ReadRLE(
                    "x = 25, y = 22, rule = B3/S23",
                    "9b2o$10bo$8bo5b2o$8b2o5bo$15bob2o$8b2o2b2obo2bo$8b2o3bob2o$13bo$12b2o$",
                    "19b2o$19bobo$21bo$21bob2o$11b2o5b2obobo$11b2o5b2obobo$21bob2o$2b2o14b",
                    "4o2bo$bobo14bo3b2o$bo18b2o$2o19bo$19bo$19b2o!"
                ))
            };
            Component[] parts5 = new Component[]
            {
                new Component(45, 0, Pattern.ReadRLE(
                    "x = 81, y = 61, rule = B3/S23",
                    "45b2o3b2o$45b2o2bob3o$17bo31bo4bo$16bobo26b4ob2o2bo$16bobo7b2o17bo2bob",
                    "obob2o$14b3ob2o6b2o20bobobobo$13bo19b2o14b2obobo$14b3ob2o13b2o18bo$16b",
                    "ob2o$39b2o$40bo7b2o$40bobo5b2o$29bo11b2o$28bobo$27bo2bo$28b2o9b2o30bo$",
                    "39b2o28b3o$68bo$68b2o$17b2o32b2o$17b2o32bo$52b3o21b2ob2o$54bo22bob2o$",
                    "15bo61bo$13b3o53b2o4b3o$12bo56b2o3bo3b2o$12b2o60b4o2bo$60b2o15bob2o$",
                    "59bobo12b3o2bo$47bo11bo13bo5bo$31b2o14b3o8b2o14b5o$31bo18bo25bo$32b3o",
                    "14b2o$2b2o30bo$bobo5b2o$bo7b2o$2o$27bo$14bo12b3o$10b2obobo14bo$9bobobo",
                    "bo13b2o$6bo2bobobob2o$6b4ob2o2bo47b2o$10bo4bo2b2ob2o40b2o$6b2o2bob3o3b",
                    "2obo$6b2o3b2o8bo$21b3o4b2o11b2o$19b2o3bo3b2o11b2o9b2o$18bo2b4o26bo2bo$",
                    "18b2obo15b2o12bobo$19bo2b3o12bobo12bo$19bo5bo13bo$20b5o14b2o$22bo$62b",
                    "2obo$47b2o13b2ob3o$47b2o19bo$54b2o6b2ob3o$54b2o7bobo$63bobo$64bo!"
                )),
                new Component(45, -8, Pattern.ReadRLE(
                    "x = 91, y = 65, rule = B3/S23",
                    "23bo$22bobo$22bobo7b2o$20b3ob2o6b2o$19bo19b2o$20b3ob2o13b2o$22bob2o34b",
                    "o$59bobo$59bob3o$56b2obo4bo$35bo20bobobobobo$34bobo21bobob2o4b2o$33bo",
                    "2bo13b2o5bobo8bo$34b2o9b2o3b2o6bo7bobo$45b2o19b2o3$23b2o30b2o$15b2o6b",
                    "2o29bo2bo$15bo3b2o34b2o24bo$11b2o4bo2bo58b3o$6b2o3b2o3b4o58bo$ob2obobo",
                    "70b2o$2obobo10b2o$4b2o10bobo$17b2o44b2o21b2ob2o$50b2o10bobo22bob2o$46b",
                    "2obobo10b2o23bo$37b2o7bob2obobo25b2o4b3o$37bo14b2o3b2o3b4o13b2o3bo3b2o",
                    "$38b3o16b2o4bo2bo17b4o2bo$9b2o29bo20bo3b2o3b2o15bob2o$8bo2bo49b2o6bobo",
                    "12b3o2bo$9b2o46bo11bo13bo5bo$57b3o8b2o14b5o$60bo25bo$20b2o37b2o$4b2o6b",
                    "o7bobo$4b2o5bobo8bo$12bobob2o4b2o$10bobobobobo$10b2obo4bo$13bob3o$13bo",
                    "bo$14bo2$73b2o$73b2o$30bo$30b3o$33bo17b2o$32b2o17b2o9b2o$61bo2bo$61bob",
                    "o$21b2ob2o36bo$21b2obo$24bo$24b3o4b2o$22b2o3bo3b2o39b2obo$21bo2b4o29b",
                    "2o13b2ob3o$21b2obo15b2o15b2o19bo$22bo2b3o12bobo21b2o6b2ob3o$22bo5bo13b",
                    "o21b2o7bobo$23b5o14b2o29bobo$25bo48bo!"
                )),
                null,
                new Component(41, 10, Pattern.ReadRLE(
                    "x = 62, y = 54, rule = B3/S23",
                    "31bo$30bobo$30bob3o$27b2obo4bo$27bobobobobo$29bobob2o4b2o$21b2o5bobo8b",
                    "o$21b2o6bo7bobo$37b2o$15bo$13b3o$12bo13b2o$12b2o11bo2bo$26b2o24bo$50b",
                    "3o$49bo$49b2o3$2b2o30b2o21b2ob2o$bobo5b2o10b2o10bobo22bob2o$bo7b2o6b2o",
                    "bobo10b2o23bo$2o15bob2obobo25b2o4b3o$23b2o3b2o3b4o13b2o3bo3b2o$14bo13b",
                    "2o4bo2bo17b4o2bo$10b2obobo16bo3b2o3b2o15bob2o$9bobobobo16b2o6bobo12b3o",
                    "2bo$6bo2bobobob2o23bo13bo5bo$6b4ob2o2bo23b2o14b5o$10bo4bo41bo$6b2o2bob",
                    "3o36b2o$6b2o3b2o38bo$52bo$51b2o$36b2o12bo$36b2o12b3o$53bo$52b2o$42bo$",
                    "41bobo$33b2o6bobo$33bo2bo5bo10b2o$34b2obo15b2o$31b3o2bo$30bo3b2o$31b2o",
                    "22b2o$32bob2o14b2obo2bo$32bo2bo13bobob2o$33b2o14b2o2bo$53bobo$37b2o15b",
                    "2o$38bo$35b3o$35bo!"
                )),
                new Component(41, 10, Pattern.ReadRLE(
                    "x = 63, y = 46, rule = B3/S23",
                    "31bo$30bobo$30bob3o$27b2obo4bo$27bobobobobo$29bobob2o4b2o$21b2o5bobo8b",
                    "o$21b2o6bo7bobo$37b2o$15bo$13b3o$12bo13b2o$12b2o11bo2bo$26b2o$53bo$51b",
                    "3o$50bo$50b2o2$2b2o30b2o$bobo5b2o10b2o10bobo22b2ob2o$bo7b2o6b2obobo10b",
                    "2o24bob2o$2o15bob2obobo34bo$23b2o3b2o3b4o14b2o4b3o$14bo13b2o4bo2bo13b",
                    "2o3bo3b2o$10b2obobo16bo3b2o18b4o2bo$9bobobobo16b2o8b2o15bob2o$6bo2bobo",
                    "bob2o24bobo12b3o2bo$6b4ob2o2bo25bo13bo5bo$10bo4bo17bo6b2o14b5o$6b2o2bo",
                    "b3o18b3o22bo$6b2o3b2o23bo$35b2o3$24b2ob2o$24b2obo$27bo$27b3o4b2o$25b2o",
                    "3bo3b2o$24bo2b4o$24b2obo15b2o$25bo2b3o12bobo$25bo5bo13bo$26b5o14b2o$",
                    "28bo!"
                )),
                new Component(35, -4, Pattern.ReadRLE(
                    "x = 71, y = 70, rule = B3/S23",
                    "39bo$38bobo$38bob3o$35b2obo4bo$35bobobobobo$37bobob2o4b2o$29b2o5bobo8b",
                    "o$29b2o6bo7bobo$45b2o3$34b2o$33bo2bo$34b2o4$15bo$13b3o$12bo29b2o$12b2o",
                    "15b2o10bobo$25b2obobo10b2o$25bob2obobo$31b2o3b2o3b4o3b2o$36b2o4bo2bo3b",
                    "o$40bo3b2o2bo$40b2o6b2o$2b2o46bo12b2o$bobo5b2o37b3o12b2o$bo7b2o36bo$2o",
                    "45b2o$58bo$14bo42bobo$10b2obobo41bobo6b2o$9bobobobo30b2o10bo5bo2bo$6bo",
                    "2bobobob2o29b2o15bob2o$6b4ob2o2bo48bo2b3o$10bo4bo49b2o3bo$6b2o2bob3o",
                    "29b2o22b2o$6b2o3b2o31bo2bob2o14b2obo$46b2obobo13bo2bo$47bo2b2o14b2o$",
                    "45bobo$45b2o15b2o$62bo$63b3o$59b2o4bo$59bo$60bo$59b2o$44b2o12bo$44b2o",
                    "12b3o$61bo$60b2o$50bo$49bobo$41b2o6bobo$41bo2bo5bo10b2o$42b2obo15b2o$",
                    "39b3o2bo$38bo3b2o$39b2o22b2o$40bob2o14b2obo2bo$40bo2bo13bobob2o$41b2o",
                    "14b2o2bo$61bobo$45b2o15b2o$46bo$43b3o$43bo!"
                )),
                new Component(43, -3, Pattern.ReadRLE(
                    "x = 88, y = 65, rule = B3/S23",
                    "20bo$19bobo$19bobo7b2o$17b3ob2o6b2o$16bo19b2o$17b3ob2o13b2o$19bob2o34b",
                    "o$56bobo$56bob3o$53b2obo4bo$32bo20bobobobobo$31bobo21bobob2o4b2o$30bo",
                    "2bo13b2o5bobo8bo$31b2o9b2o3b2o6bo7bobo$42b2o19b2o3$20b2o30b2o$20b2o29b",
                    "o2bo$52b2o24bo$76b3o$75bo$75b2o2$15bo$13b3o44b2o21b2ob2o$12bo34b2o10bo",
                    "bo22bob2o$12b2o29b2obobo10b2o23bo$34b2o7bob2obobo25b2o4b3o$34bo14b2o3b",
                    "2o3b4o13b2o3bo3b2o$35b3o16b2o4bo2bo17b4o2bo$37bo20bo3b2o3b2o15bob2o$",
                    "58b2o6bobo12b3o2bo$54bo11bo13bo5bo$2b2o50b3o8b2o14b5o$bobo5b2o46bo25bo",
                    "$bo7b2o45b2o$2o2$14bo$10b2obobo$9bobobobo$6bo2bobobob2o$6b4ob2o2bo16bo",
                    "$10bo4bo16b3o$6b2o2bob3o20bo$6b2o3b2o21b2o34b2o$70b2o2$23b2ob2o$23b2ob",
                    "o21b2o$26bo21b2o9b2o$26b3o4b2o23bo2bo$24b2o3bo3b2o23bobo$23bo2b4o29bo$",
                    "23b2obo15b2o$24bo2b3o12bobo$24bo5bo13bo$25b5o14b2o23b2obo$27bo26b2o13b",
                    "2ob3o$54b2o19bo$61b2o6b2ob3o$61b2o7bobo$70bobo$71bo!"
                )),
                new Component(45, -10, Pattern.ReadRLE(
                    "x = 93, y = 76, rule = B3/S23",
                    "25bo$24bobo$24bobo7b2o$22b3ob2o6b2o$21bo19b2o$22b3ob2o13b2o$24bob2o34b",
                    "o$61bobo$61bob3o$58b2obo4bo$37bo20bobobobobo$36bobo21bobob2o4b2o$35bo",
                    "2bo13b2o5bobo8bo$36b2o9b2o3b2o6bo7bobo$47b2o19b2o3$25b2o30b2o$25b2o29b",
                    "o2bo$57b2o24bo$15b2o64b3o$15bo3b2o59bo$11b2o4bo2bo59b2o$6b2o3b2o3b4o$o",
                    "b2obobo$2obobo10b2o47b2o21b2ob2o$4b2o10bobo33b2o10bobo22bob2o$17b2o29b",
                    "2obobo10b2o23bo$39b2o7bob2obobo25b2o4b3o$39bo14b2o3b2o3b4o13b2o3bo3b2o",
                    "$40b3o16b2o4bo2bo17b4o2bo$42bo20bo3b2o3b2o15bob2o$63b2o6bobo12b3o2bo$",
                    "9b2o48bo11bo13bo5bo$8bo2bo47b3o8b2o14b5o$9b2o51bo25bo$61b2o2$20b2o$4b",
                    "2o6bo7bobo$4b2o5bobo8bo$12bobob2o4b2o$10bobobobobo$10b2obo4bo$13bob3o$",
                    "13bobo$14bo60b2o$75b2o3$53b2o$53b2o9b2o$49b2o12bo2bo$49bo13bobo$50bo",
                    "13bo$49b2o$34b2o12bo$34b2o12b3o$51bo22b2obo$50b2o7b2o13b2ob3o$40bo18b",
                    "2o19bo$39bobo24b2o6b2ob3o$31b2o6bobo24b2o7bobo$31bo2bo5bo10b2o22bobo$",
                    "32b2obo15b2o23bo$29b3o2bo$28bo3b2o$29b2o22b2o$30bob2o14b2obo2bo$30bo2b",
                    "o13bobob2o$31b2o14b2o2bo$51bobo$35b2o15b2o$36bo$33b3o$33bo!"
                )),
            };

            Console.Write("Preparing parameters...");

            var costsS = new WebClient().DownloadString(
                "https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
            var costs = ParseCosts(costsS);

            var paramsList = new List<Params>();

            for (int mul1 = 1; mul1 <= 4; mul1++)
            {
                for (int mul2 = 1; mul2 <= 4; mul2++)
                {
                    int mul = mul1 * mul2;
                    if (mul1 > mul2 || mul == 1 || mul == 16)
                        continue;
                    for (int mod = 0; mod < 4; mod++)
                    {
                        for (int slide1 = 0; slide1 < 20; slide1++)
                        {
                            for (int slide2a = 0; slide2a < mul; slide2a++)
                            {
                                paramsList.Add(new Params
                                {
                                    Mul1 = mul1,
                                    Mul2 = mul2,
                                    Mod = mod + (mul % 2) * 4,
                                    Slide1 = slide1,
                                    Slide2 = slide1 + slide2a
                                });
                            }
                        }
                    }
                }
            }

            paramsList.Shuffle();

            Console.WriteLine(" Done");

            var newGuns = new SortedDictionary<int, Pattern>();
            var newGunsCosts = new Dictionary<int, int>();

            int failed = 0;
            for (int i = 0; i < paramsList.Count; i++)
            {
                Params p = paramsList[i];

                Component part3 = parts3[p.Mul1 - 1];
                Component part4 = parts4[p.Mul2 - 1];
                Component part5 = parts5[p.Mod];

                part2.X2 = p.Slide1;
                part2.Y2 = p.Slide1;
                part3.X2 = p.Slide2;
                part3.Y2 = p.Slide2;
                part4.X2 = p.Slide2;
                part4.Y2 = p.Slide2;

                Pattern gun = Combine(part1, part2, part3, part4, part5);

                Console.Write("\r" + new string(' ', 50) + "\r");
                Console.Write($"Current: {i,5}, Failed: {failed,5}, Total: {paramsList.Count}");

                int period = 0;
                Pattern normalizedGun = gun.Normalize(ref period);
                if (normalizedGun == null)
                {
                    failed++;
                    gun.WriteRLE($"gun_x_{p.Mul1}_{p.Mul2}_{p.Mod}_{p.Slide1}_{p.Slide2}.rle");
                    continue;
                }
                int area = normalizedGun.Width * normalizedGun.Height;
                if (newGuns.ContainsKey(period) && area >= newGunsCosts[period])
                    continue;

                newGuns[period] = normalizedGun;
                newGunsCosts[period] = area;
            }
            Console.WriteLine();

            string logName = "report.txt";
            File.Delete(logName);

            foreach (var kv in newGuns)
            {
                int period = kv.Key;
                if (!IsPrime(period) || period > 9999)
                    continue;

                Pattern gun = kv.Value;
                int area = newGunsCosts[period];

                string costS = "      ";
                if (costs.ContainsKey(period))
                {
                    costS = $"{costs[period],6}";
                    if (costs[period] <= area)
                        continue;
                }
                string reportLine = $"gun_{period,-4}: {costS} -> {area,6}";
                Console.WriteLine(reportLine);
                File.AppendAllLines(logName, new string[] { reportLine });
                gun.WriteRLE($"gun_{period}.rle");
            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}
upd. I executed few more passes of this algorithm, added several new guns to cut the spikes from minimum (blue) line and here is how area chart looks now:
gun_coll_area_v16.png
gun_coll_area_v16.png (50.51 KiB) Viewed 2179 times
Last edited by Vort on June 24th, 2024, 4:37 am, edited 1 time in total.

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » June 23rd, 2024, 4:03 pm

Vort wrote:
June 23rd, 2024, 3:42 pm
Also this script allowed to process gun_9973 family:
These runs and the resulting reductions are impressive.

One thought here, is that the collection of four-digit guns might become "more or less completed" (with reductions slowing down) after finitely many improvements. Catagolue doesn't collect periods above 9999. (And perhaps it shouldn't collect them; I think it would become impractical to collect individual guns at that point.) This leads to the idea of a software tool that would loop through all known gun families/gun designs, and automatically assemble "on demand" a compact gun of any higher period.

If you keep the code for "already processed" families, it might be possible to collect all that code into a single combined software tool. The input would be the desired period; the output would be either the most compact gun of that period that can be made, or multiple guns (one gun from every known family) sorted by the bounding box area.

User avatar
Vort
Posts: 84
Joined: May 14th, 2024, 6:35 am

Re: Small Four-Digit Prime Period Guns

Post by Vort » July 1st, 2024, 5:16 am

There are 5 guns left to optimize for achieving sub 25k maximum:
"gun_3529","30090"
"gun_3457","29040"
"gun_3449","28875"
"gun_3433","28536"
"gun_3361","26404"
gun_coll_area_v19.png
gun_coll_area_v19.png (66.83 KiB) Viewed 1334 times
confocaloid wrote:
June 23rd, 2024, 4:03 pm
This leads to the idea of a software tool that would loop through all known gun families/gun designs, and automatically assemble "on demand" a compact gun of any higher period.
Four-digit period guns are compact and easily adjustable because two snarks allow for x1..x16 multiplication.
To achieve larger multiplication, code will need to support adjustable multipliers (or variable amount of multipliers).
It is possible, right, but not as easy as collecting already available designs in one place.

User avatar
confocaloid
Posts: 3524
Joined: February 8th, 2022, 3:15 pm

Re: Small Four-Digit Prime Period Guns

Post by confocaloid » July 1st, 2024, 6:56 am

Jormungant wrote:
March 27th, 2019, 7:31 pm
Well, I had to try already, at least... So, here is a P1993 gun, so a valid entry for the proof of concept:
[...]
This is quite versatile as you might have guessed. Variants will be needed to fix the 8-way parity issue, but this should allow to cover the whole 4 digit range (and beyond).
Same design, gun_6917 in 126-by-111 (down from 145-by-138):

Code: Select all

x = 126, y = 111, rule = B3/S23
59bo11b2o$58bobo10b2o$50bo3b2o2bobo$36bo12bobo2bo2b2ob2o$36b3o10bobo3b
obo$39bo10bob4o2bob2o$12b2o24b2o12bo3bobob2o$13bo37bo3bobo$7b2o2bo4bo
33bo3bobo$7bo2bob5o33b2o3bo$4b2obob2o18b2o35b2o$4bo2bo3b3ob4o10bo36b2o
$6bob2o3bobo2bo8bobo32b2o$5b2obo18b2o32bo2bo$8bo53b3o$8b2o52b2o14b2o7b
2o$77bo2bo6b2o$78b2obo$81bo$81b2o$8b2o56b2o$8bo58bo$5b2obo29b2o24b3o$
5bobo30b2o11b2o11bo$51bo$47bo4b3o$45b3o6bo$44bo28b2o$44b2o26bobo$72bo$
53b2o16b2o$53bobo$55bo$55bob2o13b2o$52b2obobo13bo2bo2b2o11b2o$47b2o3b
2obobo14b2o2bobo11b2o$47b2o6bob2o15b2o$36b2o14b4o2bo15bo$6b2o27bobo14b
o3b2o13b2obo2bo$2b2o3bo27bo18b2o15bob2obobo$2bo2bobobo24b2o19bo19bobo$
4b2obob3o41bo18b2o2bo$6bobo3bo40b2o15b3ob2o$6bobo2b2o56bo$7bo62b3ob2o$
72bob2o49bo$123bobo$82b2o40b2o$53b2o27b2o7b2o21b2o$53bobo35bo22bo$55bo
4b2o27bobo24bo$51b4ob2o2bo2bo25b2o5b2o14b5o$51bo2bobobobob2o33bo13bo$
54bobobobo36bobo12b3o$19bo35b2obobo37b2o15bo$17b3o39bo9b2o41b4o$16bo
52b2o36b2o3bo3b2o$15bobo27b2o60b2o4b3o2bo$15bobo28bo7b2o59bob2o$16bo
29bobo5b2o59bo$47b2o65b2o$85bo$84bobo$84bobo19b2o$2o83bo20bo$2o84b3o
18b3o$88bo20bo$57b2o$57bo$20b2o36b3o$20bobo37bo$22bo$13b2o7b2o$13b2o
35bo$51b2o$3bob2o43b2o67b2o$b3ob2o112bo$o120bo$b3ob2o94b2o14b5o$3b2o2b
o94bo13bo$6bobo93bobo12b3o$2bob2obobo16bo43bo32b2o15bo$2b2obo2bo15b3o
41b3o46b4o$5bo17bo43bo44b2o3bo3b2o$5b2o16b2o42b2o43b2o4b3o2bo$3b2o2bob
o110bob2o$2bo2bo2b2o87bo22bo$3b2o90b3o21b2o$94bo$94b2o$111b2o$57b2o52b
o$56bobo5b2o46b3o$56bo7b2o48bo$55b2o$10b2o19b2o$10b2o19b2o36bo14b2o$
65b2obobo12bobo8bo$64bobobobo12bo9bobo$9b2o50bo2bobobobob2o8b2o9bobo$
10bo50b4ob2o2bo2bo20bo$7b3o55bo4b2o$7bo55bobo$63b2o$91b2ob2o$87b2o2b2o
bo3b2o$87bo6bobo2bo$88b7ob2o$95bo$20b2o68b4obo$20b2o68bo2b2o!
#C [[ MAXGRIDSIZE 9 KILLGLIDERS ]]
gun_2843 in 126-by-112 (down from 136-by-130):

Code: Select all

x = 126, y = 112, rule = B3/S23
60bo11b2o$59bobo10b2o$51bo3b2o2bobo$37bo12bobo2bo2b2ob2o$37b3o10bobo3b
obo$40bo10bob4o2bob2o$13b2o24b2o12bo3bobob2o$14bo37bo3bobo$8b2o2bo4bo
33bo3bobo$8bo2bob5o33b2o3bo$5b2obob2o18b2o36bo$5bo2bo3b3ob4o10bo35bobo
$7bob2o3bobo2bo8bobo32bo4bo$6b2obo18b2o34b3o$9bo54bo$9b2o68b2o7b2o$78b
o2bo6b2o$79b2obo$82bo$82b2o$9b2o56b2o$9bo58bo$6b2obo29b2o24b3o$6bobo
30b2o11b2o11bo$52bo$48bo4b3o$46b3o6bo$45bo28b2o$45b2o26bobo$73bo$72b2o
$53b2o$54bo$54bob2o15b2o$46b2o4b3o2bo14bo2bo2b2o11b2o$46b2o3bo3b2o16b
2o2bobo11b2o$51b4o20b2o$37b2o15bo20bo$7b2o27bobo12b3o18b2obo2bo$3b2o3b
o27bo13bo21bob2obobo$3bo2bobobo24b2o14b5o20bobo$5b2obob3o42bo17b2o2bo$
7bobo3bo39bo17b3ob2o$7bobo2b2o39b2o15bo$8bo62b3ob2o48bo$73bob2o46bobo$
124b2o$83b2o$54b2o27b2o7b2o21b2o$54bobo35bo22bo$56bo4b2o27bobo24bo$52b
4ob2o2bo2bo25b2o5b2o14b5o$52bo2bobobobob2o33bo13bo$55bobobobo36bobo12b
3o$56b2obobo37b2o15bo$19bo40bo9b2o41b4o$17b3o50b2o36b2o3bo3b2o$16bo29b
2o60b2o4b3o2bo$15bobo29bo7b2o59bob2o$15bobo29bobo5b2o59bo$16bo31b2o65b
2o$86bo$85bobo$85bobo19b2o$86bo20bo$2o85b3o18b3o$2o87bo20bo$58b2o$58bo
$59b3o$10b2o8b2o39bo$10b2o8bobo$14bo7bo$13b2o7b2o$12bo2bo$12bobo$3bob
2o6b2o39bo66b2o$b3ob2o48b2o64bo$o53b2o67bo$b3ob2o96b2o14b5o$3b2o2bo96b
o13bo$6bobo62bo32bobo12b3o$2bob2obobo16bo42b3o33b2o15bo$2b2obo2bo15b3o
41bo50b4o$5bo17bo44b2o44b2o3bo3b2o$5b2o16b2o89b2o4b3o2bo$3b2o2bobo112b
ob2o$2bo2bo2b2o89bo22bo$3b2o92b3o21b2o$96bo$96b2o$58b2o53b2o$57bobo5b
2o46bo$57bo7b2o23bo23b3o$56b2o31bobo24bo$82b2ob2o3bo$10b2o19b2o37bo9bo
2bob2o$10b2o19b2o33b2obobo8b2o$65bobobobo24bo$62bo2bobobobob2o10bo2bo
6bobo$9b2o51b4ob2o2bo2bo10b4o6bobo$10bo55bo4b2o9bo13bo$7b3o54bobo15b5o
$7bo56b2o20bo$84bo$84b2o7b2ob2o$89b2o2b2obo3b2o$89bo6bobo2bo$90b7ob2o$
97bo$20b2o70b4obo$20b2o70bo2b2o!
#C [[ MAXGRIDSIZE 9 KILLGLIDERS ]]
Vort wrote:
July 1st, 2024, 5:16 am
There are 5 guns left to optimize for achieving sub 25k maximum:
"gun_3529","30090"
"gun_3457","29040"
"gun_3449","28875"
"gun_3433","28536"
"gun_3361","26404"
[...]
All five periods are 1 (mod 8) and in roughly the same range, so could be covered by a single design.

Here is gun_3361 in 144-by-132 (down from 164-by-161), using the same design as above, but with a different Herschel-to-glider converter used in the pulse-dividing track:

Code: Select all

x = 144, y = 132, rule = B3/S23
58bo11b2o$57bobo10b2o$49bo3b2o2bobo$35bo12bobo2bo2b2ob2o$35b3o10bobo3b
obo$38bo10bob4o2bob2o$11b2o24b2o12bo3bobob2o$12bo37bo3bobo$6b2o2bo4bo
33bo3bobo$6bo2bob5o33b2o3bo$3b2obob2o18b2o9b3o$3bo2bo3b3ob4o10bo10b3o$
5bob2o3bobo2bo8bobo8b2o3bo$4b2obo18b2o9bo2b3o19b2o$7bo29b4o2bo18b2o$7b
2o30bob3o33b2o7b2o$41bo34bo2bo6b2o$77b2obo$80bo$80b2o$7b2o28b2o26b2o$
7bo28bo2bo26bo$4b2obo28bo2bo23b3o$4bobo30bobo10b2o11bo$50bo$46bo4b3o$
44b3o6bo$43bo28b2o$43b2o26bobo$71bo$70b2o$51b2o$52bo$52bob2o15b2o$44b
2o4b3o2bo14bo2bo2b2o11b2o$44b2o3bo3b2o16b2o2bobo11b2o$49b4o20b2o$35b2o
15bo20bo$5b2o27bobo12b3o18b2obo2bo$b2o3bo27bo13bo21bob2obobo$bo2bobobo
24b2o14b5o20bobo$3b2obob3o42bo17b2o2bo$5bobo3bo39bo17b3ob2o$5bobo2b2o
39b2o15bo$6bo62b3ob2o$71bob2o$50b2o$50bobo28b2o$52bo4b2o22b2o7b2o$48b
4ob2o2bo2bo29bo$48bo2bobobobob2o27bobo$51bobobobo30b2o$52b2obobo$19bo
36bo$17b3o$16bo25b2o24b2o$15bobo25bo7b2o15b2o$15bobo25bobo5b2o$16bo27b
2o3$84bo$83bobo$2o81bobo$2o82bo58bo$54b2o29b3o53bobo$54bo32bo54b2o$55b
3o$20b2o35bo$20bobo$22bo$13b2o7b2o112b2o$13b2o121bo$138bo$3bob2o111b2o
14b5o$b3ob2o112bo13bo$o118bobo12b3o$b3ob2o113b2o15bo$3b2o2bo126b4o$6bo
bo120b2o3bo3b2o$2bob2obobo3b2o11bo102b2o4b3o2bo$2b2obo2bo4bobo8b3o110b
ob2o$5bo7bo9bo113bo$5b2o16b2o111b2o$3b2o2bobo$2bo2bo2b2o10b2o$3b2o15b
2o106b2o$17b3o108bo$18bo2b2o40bobo63b3o$17b3ob2o41b2o65bo$20b2o14b2o
26bo$16b2o2bo15bo$17b3o14bobo$18bo15b2o$10b2o$10b2o$139b2o$139bo$9b2o
130bo$10bo110b2o14b5o$7b3o112bo13bo$7bo15b2o5b2o90bobo12b3o$24bo5bo92b
2o15bo$21b3o7b3o103b4o$21bo11bo58bo39b2o3bo3b2o$90b3o39b2o4b3o2bo$89bo
50bob2o$89b2o26bo22bo$115b3o21b2o$114bo$114b2o$131b2o$131bo$108bo23b3o
$79b2o26bobo24bo$78bobo5b2o12b2ob2o3bo$78bo7b2o10bo2bob2o$77b2o19b2o$
114bo$91bo11bo2bo6bobo$87b2obobo10b4o6bobo$86bobobobo7bo13bo$83bo2bobo
bobob2o4b5o$83b4ob2o2bo2bo8bo$87bo4b2o8bo$85bobo14b2o7b2ob2o$85b2o20b
2o2b2obo3b2o$107bo6bobo2bo$108b7ob2o$115bo$110b4obo$110bo2b2o!
#C [[ MAXGRIDSIZE 9 KILLGLIDERS ]]
edit 1: this also solves gun_3529 in 151-by-139 (down from 177-by-170), gun_3433 in 147-by-135 (down from 174-by-164), gun_3449 in 147-by-135 (down from 175-by-165), gun_3457 in 148-by-135 (down from 176-by-165).

edit 2: submitted and processed in jobs/7234571596.
Last edited by confocaloid on July 1st, 2024, 8:45 am, edited 1 time in total.
127:1 B3/S234c User:Confocal/R (isotropic CA, incomplete)
Unlikely events happen.
My silence does not imply agreement, nor indifference. If I disagreed with something in the past, then please do not construe my silence as something that could change that.

simeks
Posts: 418
Joined: March 11th, 2015, 12:03 pm
Location: Sweden

Re: Small Four-Digit Prime Period Guns

Post by simeks » July 1st, 2024, 7:22 am

Vort wrote:
July 1st, 2024, 5:16 am
There are 5 guns left to optimize for achieving sub 25k maximum:
"gun_3529","30090"
"gun_3457","29040"
"gun_3449","28875"
"gun_3433","28536"
"gun_3361","26404"
I was curious how far you would get with just a Snark loop, so here's p3529 in 151x125 = 18875:

Code: Select all

x = 151, y = 125, rule = LifeHistory
97.2A11.A$96.B2AB9.A.A$97.3B9.A.A2.2A3.A$96.B.B9.2A.2A2.A2.A.A$96.5B
8.B2.A.A3.A.A$96.6B6.2ABA2.4A.A$21.2A16.2A16.2A16.2A19.8B4.2A.A.A3.A$
21.A.A15.A.A15.A.A15.A.A19.13B2.A.AB2.A15.2A$23.A4.2A11.A4.2A11.A4.2A
11.A4.2A11.13B5.A.A2B.A14.A$19.4A.2A2.A2.A5.4A.2A2.A2.A5.4A.2A2.A2.A
5.4A.2A2.A2.A8.15B5.A2B.2A11.BA.A$19.A2.A.A.A.A.2A5.A2.A.A.A.A.2A5.A
2.A.A.A.A.2A5.A2.A.A.A.A.2A8.15B4.3B12.2A.B2A$21.BABABA.A10.BABABA.A
10.BABABA.A10.BABABA.A10.17B.B.2B12.B2A2B$22.B2ABA.A11.B2ABA.A11.B2AB
A.A11.B2ABA.A10.29B6.4B$23.2B.BA13.2B.BA13.2B.BA13.2B.BA10.13B2A16B3.
6B$22.3B15.3B15.3B15.3B12.14B2A16B2.6B$13.2A6.4B6.2A6.4B6.2A6.4B6.2A
6.4B11.2AB3.27B.7B9.2A$14.A6.B2A3B5.A6.B2A3B5.A6.B2A3B5.A6.B2A3B8.A2.
A4.35B6.2B2AB6.2A$14.A.AB3.B2A3B5.A.AB3.B2A3B5.A.AB3.B2A3B5.A.AB3.B2A
3B7.A.2A5.6B3.B2.2B2.20B5.4B7.A$15.2AB.10B4.2AB.10B4.2AB.10B4.2AB.10B
5.A7.6B14.21B.6B2.BA.A$17.13B5.13B5.13B5.13B3.2A6.9B14.27B.B2A$17.14B
4.14B4.14B4.14B9.4B4.2A15.28B$17.15B3.15B3.15B3.15B7.4B5.A15.29B$19.
8B2.4B4.8B2.4B4.8B2.4B4.8B2.4B5.4B7.3A12.29B$19.6B5.4B3.6B5.4B3.6B5.
4B3.6B5.4B3.4B10.A10.2AB.3B2.22B$18.9B4.4B.9B4.4B.9B4.4B.9B4.4B.4B21.
A.AB6.13B.9B$17.4B4.2A5.7B4.2A5.7B4.2A5.7B4.2A5.7B22.A8.12B2.11B$16.
4B5.A7.5B5.A7.5B5.A7.5B5.A7.5B22.2A7.12B3.BAB.B3.4B$3.2A10.4B7.3A4.5B
6.3A4.5B6.3A4.5B6.3A4.5B30.10B6.A.A.2A3.3BA$4.A9.4B10.A3.7B7.A3.7B7.A
3.7B7.A3.7B28.4B.6B4.3A.ABA5.ABA$2.A10.4B14.4B.4B9.4B.4B9.4B.4B9.4B.
4B26.4B3.B.B5.A3.A4.A4.2A$2.5A5.4B5.2A7.4B3.4B7.4B3.4B7.4B3.4B7.4B3.
4B24.4B5.3B4.2A2.A.4A5.B$7.A4.4B5.A7.4B5.4B5.4B5.4B5.4B5.4B5.4B5.4B
22.4B5.B2AB9.A$4.3AB2.7B.BA.A6.4B7.4B3.4B7.4B3.4B7.4B3.4B7.4B20.4B7.
2A12.A$3.A.2B3.7B.B2A6.4B9.4B.4B9.4B.4B9.4B.4B9.4B18.4B21.2A$3.4A12B
7.4B11.7B11.7B11.7B11.4B16.4B$.2A2.BA3B2A7B6.4B13.5B13.5B13.5B13.4B
14.4B$A2.3AB.2B2A7B5.4B14.5B13.5B13.5B14.4B12.4B$2A.A.B3.10B4.4B14.7B
11.7B11.7B14.4B10.4B$3.A8.8B2.4B14.4B.4B9.4B.4B9.4B.4B14.4B8.4B$3.2A
7.13B14.4B3.4B7.4B3.4B7.4B3.4B14.4B6.A3B$13.3B2.6B14.4B5.4B5.4B5.4B5.
4B5.4B14.4B4.BABA5.A$11.5B3.4B14.4B7.4B3.4B7.4B3.4B7.4B14.4B2.2B2A4.
3A$11.2A5.6B12.4B9.4B.4B9.4B.4B9.4B14.8B4.A$12.A4.8B10.4B11.7B7.A3.7B
11.4B14.6B5.2A$9.3A4.4B2.4B8.4B13.5B6.3A4.5B13.4B14.4B3.5B$3.2A4.A5.
4B4.4B6.4B14.5B5.A7.5B14.4B12.6B2.3B$4.A9.4B6.4B4.4B14.7B4.2A5.7B14.
4B10.13B7.2A$2.A10.4B8.4B2.4B14.4B.9B4.4B.4B14.4B8.4B2.8B8.A$2.5A5.4B
5.2A3.8B14.4B3.6B5.4B3.4B14.4B6.4B4.10B3.B.A.2A$7.A4.4B5.A5.6B14.4B4.
8B2.4B5.4B14.4B4.4B5.7B2A2B.B3A2.A$4.3AB2.7B.BA.A6.4B14.4B3.15B7.4B
14.4B2.4B6.7B2A3BAB2.2A$3.A.2B3.7B.B2A6.6B12.4B4.14B9.4B14.8B7.12B4A$
3.4A12B7.8B10.4B5.13B11.4B14.6B6.2AB.7B3.2B.A$.2A2.BA3B2A7B6.4B2.4B8.
4B4.2AB.10B13.4B14.4B6.A.AB.7B2.B3A$A2.3AB.2B2A7B5.4B4.4B6.4B4.A.AB3.
B2A3B16.4B12.6B5.A5.4B4.A$2A.A.B3.10B4.4B6.4B4.4B5.A6.B2A3B17.4B10.8B
3.2A5.4B5.5A$3.A8.8B2.4B8.4B2.4B5.2A6.4B20.4B8.4B2.4B8.4B10.A$3.2A7.
13B10.8B15.3B21.4B6.4B4.4B6.4B9.A$13.3B2.6B12.6B17.2B.BA19.4B4.4B6.4B
4.4B5.A4.2A$11.5B3.4B14.4B17.B2ABA.A19.4B2.4B8.4B2.4B4.3A$11.2A5.6B
12.6B15.BABABA.A20.8B10.8B4.A$12.A4.8B10.8B12.A2.A.A.A.A.2A18.6B12.6B
5.2A$9.3A4.4B2.4B8.4B2.4B11.4A.2A2.A2.A19.4B14.4B3.5B$3.2A4.A5.4B4.4B
6.4B4.4B14.A4.2A20.6B12.6B2.3B$4.A9.4B6.4B4.4B6.4B11.A.A25.8B10.13B7.
2A$2.A10.4B8.4B2.4B8.4B10.2A25.4B2.4B8.4B2.8B8.A$2.5A5.4B5.2A3.8B10.
4B35.4B4.4B6.4B4.10B3.B.A.2A$7.A4.4B5.A5.6B12.4B33.4B6.4B4.4B5.7B2A2B
.B3A2.A$4.3AB2.7B.BA.A6.4B14.4B31.4B8.4B2.4B6.7B2A3BAB2.2A$3.A.2B3.7B
.B2A6.6B14.4B29.4B10.8B7.12B4A$3.4A12B7.8B14.4B27.4B12.6B6.2AB.7B3.2B
.A$.2A2.BA3B2A7B6.4B2.4B14.4B25.4B14.4B6.A.AB.7B2.B3A$A2.3AB.2B2A7B5.
4B4.4B14.4B23.4B14.6B5.A5.4B4.A$2A.A.B3.10B4.4B6.4B14.4B21.4B14.8B3.
2A5.4B5.5A$3.A8.8B2.4B8.4B14.4B19.4B14.4B2.4B8.4B10.A$3.2A7.13B10.4B
14.4B17.4B14.4B4.4B6.4B9.A$13.3B2.6B12.4B14.4B15.4B14.4B6.4B4.4B5.A4.
2A$11.5B3.4B14.4B14.4B13.4B14.4B8.4B2.4B4.3A$11.2A5.6B14.4B14.4B11.4B
14.4B10.8B4.A$12.A4.8B14.4B14.4B9.4B14.4B12.6B5.2A$9.3A4.4B2.4B14.4B
14.4B7.4B14.4B14.4B3.5B$3.2A4.A5.4B4.4B14.4B14.4B5.4B14.4B14.6B2.3B$
4.A9.4B6.4B14.4B14.4B3.4B14.4B14.13B7.2A$2.A10.4B8.4B14.4B14.4B.4B14.
4B14.4B2.8B8.A$2.5A5.4B5.2A3.4B14.4B14.7B14.4B14.4B4.10B3.B.A.2A$7.A
4.4B5.A5.4B14.4B14.5B14.4B14.4B5.7B2A2B.B3A2.A$4.3AB2.7B.BA.A6.4B14.
4B13.5B13.4B14.4B6.7B2A3BAB2.2A$3.A.2B3.7B.B2A8.4B14.4B11.7B11.4B14.
4B7.12B4A$3.4A12B11.4B14.4B9.4B.4B9.4B14.4B6.2AB.7B3.2B.A$.2A2.BA3B2A
7B12.4B14.4B7.4B3.4B7.4B14.4B6.A.AB.7B2.B3A$A2.3AB.2B2A7B13.4B14.4B5.
4B5.4B5.4B14.4B7.A5.4B4.A$2A.A.B3.10B14.4B14.4B3.4B7.4B3.4B14.4B7.2A
5.4B5.5A$3.A8.8B14.4B14.4B.4B9.4B.4B14.4B14.4B10.A$3.2A7.9B14.4B14.7B
11.7B14.4B14.4B9.A$13.3B2.4B14.4B14.5B13.5B14.4B14.4B10.2A$11.5B3.4B
14.4B13.5B13.5B13.4B14.4B$11.2A7.4B14.4B11.7B11.7B11.4B14.4B$12.A8.4B
14.4B9.4B.4B9.4B.4B9.4B14.4B$9.3A10.4B14.4B7.4B3.4B7.4B3.4B7.4B14.4B$
9.A13.4B14.4B5.4B5.4B5.4B5.4B5.4B14.4B$24.4B14.4B3.4B7.4B3.4B7.4B3.4B
14.4B$25.4B14.4B.4B9.4B.4B9.4B.4B14.4B$26.4B6.A7.7B3.A7.7B3.A7.7B3.A
10.4B$27.4B5.3A6.5B4.3A6.5B4.3A6.5B4.3A7.4B$28.4B7.A5.5B7.A5.5B7.A5.
5B7.A5.4B$29.4B5.2A4.7B5.2A4.7B5.2A4.7B5.2A4.4B$30.4B4.9B.4B4.9B.4B4.
9B.4B4.9B$31.4B5.6B3.4B5.6B3.4B5.6B3.4B5.6B$32.4B2.8B4.4B2.8B4.4B2.8B
4.4B2.8B$33.15B3.15B3.15B3.15B$34.14B4.14B4.14B4.14B$35.13B5.13B5.13B
5.13B$36.10B.B2A4.10B.B2A4.10B.B2A4.10B.B2A$38.3B2AB3.BA.A5.3B2AB3.BA
.A5.3B2AB3.BA.A5.3B2AB3.BA.A$38.3B2AB6.A5.3B2AB6.A5.3B2AB6.A5.3B2AB6.
A$40.4B6.2A6.4B6.2A6.4B6.2A6.4B6.2A$40.3B15.3B15.3B15.3B$37.AB.2B13.A
B.2B13.AB.2B13.AB.2B$36.A.AB2AB11.A.AB2AB11.A.AB2AB11.A.AB2AB$36.A.AB
ABAB10.A.ABABAB10.A.ABABAB10.A.ABABAB$33.2A.A.A.A.A2.A5.2A.A.A.A.A2.A
5.2A.A.A.A.A2.A5.2A.A.A.A.A2.A$33.A2.A2.2A.4A5.A2.A2.2A.4A5.A2.A2.2A.
4A5.A2.A2.2A.4A$35.2A4.A11.2A4.A11.2A4.A11.2A4.A$41.A.A15.A.A15.A.A
15.A.A$42.2A16.2A16.2A16.2A!

Post Reply