Done. Maximum is dropped from 122624 to 69734:
To achieve this I improved program from my previous post by adding enumeration of multipliers (1, 2, 3, 4) and mod 8 values (1, 3, 5, 9):
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(130, 120);
Pattern part2 = new Pattern(47, 41);
Pattern part3 = new Pattern(45, 32);
Pattern part41 = new Pattern(124, 66);
Pattern part43 = new Pattern(101, 49);
Pattern part45 = new Pattern(86, 70);
Pattern part47 = new Pattern(74, 76);
Pattern part51 = new Pattern(19, 23);
Pattern part52 = new Pattern(21, 23);
Pattern part53 = new Pattern(18, 25);
Pattern part54 = new Pattern(22, 25);
var parts4 = new Dictionary<int, Pattern>();
var parts4x = new Dictionary<int, int>();
var parts4y = new Dictionary<int, int>();
parts4[1] = part41;
parts4x[1] = 60;
parts4y[1] = 80;
parts4[3] = part43;
parts4x[3] = 60;
parts4y[3] = 72;
parts4[5] = part45;
parts4x[5] = 60;
parts4y[5] = 57;
parts4[7] = part47;
parts4x[7] = 72;
parts4y[7] = 57;
var parts5 = new Dictionary<int, Pattern>();
var parts5x = new Dictionary<int, int>();
var parts5y = new Dictionary<int, int>();
parts5[1] = part51;
parts5x[1] = 33;
parts5y[1] = 106;
parts5[2] = part52;
parts5x[2] = 35;
parts5y[2] = 106;
parts5[3] = part53;
parts5x[3] = 34;
parts5y[3] = 106;
parts5[4] = part54;
parts5x[4] = 34;
parts5y[4] = 106;
part1.ReadRLE(new string[] {
"x = 130, y = 120, rule = B3/S23",
"83bo$82bo$82b3o$69bo$69b3o$72bo$71b2o7$81b2o$74b2o5bobo$74b2o7bo$83b2o",
"$47bo2bo$47b4o19bo$45b2o4b2o16bobob2o$45bo2b2o3bo15bobobobo$46b3ob3o",
"13b2obobobobo2bo$50bo15bo2bo2b2ob4o$46b3obo17b2o4bo$45bo2bob2o22bobo",
"15b2o$45b2o28b2o16bo$91bo$56b2o33b5o14b2o$56b2o38bo13bo$93b3o12bobo$",
"92bo15b2o$92b4o$53b2o35b2o3bo3b2o$53bo35bo2b3o4b2o$54b3o32b2obo$56bo",
"35bo$92b2o2$72b2ob2o$73bobo24b2o$68b2obo5bob2o20bo$67bobob2o3b2obobo9b",
"o6b3o$66bo6bobo6bo8b3o4bo$66b7o3b7o11bo$93b2o11b2o$68b3o7b3o25b2o$67bo",
"2bo3bo3bo2bo$67b2o4bobo4b2o$73bobo52bo$74bo52bobo$127bobo$128bo2$81b2o",
"$81b2o4$63b2o$63bobo19b2o$65bo6b2o5b2o5bo15b2o6b2o$65b3o3bo2bo4bobob3o",
"15bo2bo5b2o$63b2o3bo3bobo6bobo17bo2bo$3b2o57bo2b4o4bo7b2o19b2o$4bo57b",
"2obo10b2o$2bo62bob2o7bo$2b5o14b2o42bobo9b3o$7bo13bo42b2obobo9bo$4b3o",
"12bobo8b2o36b2o$3bo15b2o9b2o$3b4o$b2o3bo3b2o$o2b3o4b2o$2obo$3bo$3b2o3$",
"11b2o$12bo$9b3o4b2o$9bo5bobo$15bo$14b2o3$15b2o$14bo2bo2b2o$15b2o2bobo$",
"17b2o16b2o$17bo17bo$14b2obo2bo15b3o$14bob2obobo16bo$18bobo$15b2o2bo$",
"13b3ob2o$12bo$13b3ob2o$15bob2o2$25b2o$25b2o7b2o$34bo$32bobo$32b2o4$12b",
"2o$12b2o5$28bo$27bobo$27bobo$28bo$29b3o$31bo!"
});
part2.ReadRLE(new string[] {
"x = 47, y = 41, rule = B3/S23",
"9bo$8bobo$6b3obo$5bo4bob2o$5bobobobobo$2o4b2obobo$bo8bobo5b2o$bobo7bo",
"6b2o$2b2o3$13b2o$12bo2bo$13b2o6$5b2o$5bobo10b2o$6b2o10bobob2o$16bobob",
"2obo18b2o$4b4o3b2o3b2o24bo$3bo2bo4b2o31bo$3b2o3bo15b2o14b5o$7b2o16bo",
"13bo$25bobo12b3o$26b2o15bo$40b4o$35b2o3bo3b2o$35b2o4b3o2bo$43bob2o$43b",
"o$42b2o3$34b2o$34bo$35b3o$37bo!"
});
part3.ReadRLE(new string[] {
"x = 45, y = 32, rule = B3/S23",
"30bo$29bobo$27b3obo$26bo4bob2o$26bobobobobo$21b2o4b2obobo$22bo8bobo5b",
"2o$22bobo7bo6b2o$23b2o3$34b2o$33bo2bo$9bo24b2o$9b3o$12bo$11b2o3$3b2o",
"21b2o$3bo22bobo10b2o$2obo23b2o10bobob2o$o2b3o4b2o25bobob2obo$b2o3bo3b",
"2o13b4o3b2o3b2o$3b4o17bo2bo4b2o$3bo15b2o3b2o3bo$4b3o12bobo6b2o$7bo13bo",
"$2b5o14b2o$2bo$4bo$3b2o!"
});
part41.ReadRLE(new string[] {
"x = 124, y = 66, rule = B3/S23",
"65b2o3bo$66bo2bobo$64bo4bobo$64b5obo$68bo$64b2o3bo$64b2o4bo$69b2o$41b",
"2o6bo$32b2o7b2o6b3o$33bo18bo$33bobo15b2o$34b2o2$27b2o$28bo90b2o$28bobo",
"88bo$18bo10b2o50b2o38bo$16b3o62b2o18b2o14b5o$15bo86bo13bo$15b2o85bobo",
"12b3o$2o101b2o15bo$bo115b4o$bob2o107b2o3bo3b2o$2bo2bo106b2o4b3o2bo$3b",
"2o115bob2o$18b2o31b2o67bo$18b2o32bo66b2o$49b3o$41b2o6bo$41b2o2b2o29b2o",
"33b2o$45bobo28bobo32bo$26bo3b2o15bo30bo33b3o$25bobo3bo15b2o29b2o34bo$",
"21b2obobo3bo$21b2obo4bo$25b5obo$17b2obob2obo4bobo$17bob2obo2bob2o2bo$",
"10b2o12b2obob2o$10b2o2$79b2o$58bob2o16bobo$56b3ob2o16b2o$55bo$56b3ob2o",
"$58bobo$58bobo$59bo8bo$67bobo$68b2o12$74b2o$73bo2bo$74b2o!"
});
part43.ReadRLE(new string[] {
"x = 101, y = 49, rule = B3/S23",
"96b2o$96bo$98bo$78b2o14b5o$79bo13bo$79bobo12b3o$80b2o15bo$94b4o$89b2o",
"3bo3b2o$89b2o4b3o2bo$97bob2o$37b2o58bo$38bo57b2o$37bo$37b2o2b2o$40bobo",
"45b2o$35b4obo47bo$35bo2bob2o47b3o$91bo4$27b2o$28bo20b2o$28bobo18bo$18b",
"o10b2o16bobo$16b3o28b2o$15bo$15b2o$2o$bo$bob2o$2bo2bo$3b2o$18b2o$18b2o",
"4$27bo3b2o$26bobo3bo$25bobo3bo9b2o$21b2obobo3bo10b2o14b2o$21b2obo2b4ob",
"o24bobo$25bobo3bobo15b2o8bo$21b2ob2o2bo2bobo15bo9b2o$22bobo2b2o3bo17b",
"3o$10b2o10bobo27bo$10b2o11bo!"
});
part45.ReadRLE(new string[] {
"x = 86, y = 70, rule = B3/S23",
"81b2o$81bo$83bo$63b2o14b5o$64bo13bo$64bobo12b3o$65b2o15bo$79b4o$74b2o",
"3bo3b2o$74b2o4b3o2bo$82bob2o$82bo$81b2o2$51b2o$52bo20b2o$50bo22bo$50b",
"5o14b2o3b3o$55bo13bo6bo$52b3o12bobo$51bo15b2o$51b4o$49b2o3bo3b2o$48bo",
"2b3o4b2o$48b2obo$51bo$51b2o3$59b2o$60bo$57b3o$57bo3$44bo$43bobo$27b2o",
"15b2o2b2o$28bo19b2o$28bobo$18bo10b2o$16b3o40b2o$15bo44bo$15b2o43bobo$",
"2o59b2o$bo$bob2o$2bo2bo$3b2o77b2o$18b2o62b2o$18b2o3$50b2o$50b2o$26bo3b",
"2o$25bobo3bo$21b2obobo3bo$21b2obo4bo$25b5obo22b2o$17b2obob2obo4bobo22b",
"o$17bob2obo2bob2o2bo20b3o$10b2o12b2obob2o8b2ob2o8bo17b2o$10b2o26bobobo",
"bo26bo$36b3o3bobo23b3o$35bo4bobob3o21bo$36b3ob2obo3bo$38bo4bo2b2o$40b",
"3o$39b2o!"
});
part47.ReadRLE(new string[] {
"x = 74, y = 76, rule = B3/S23",
"69b2o$69bo$71bo$51b2o14b5o$52bo13bo$52bobo12b3o$53b2o15bo$67b4o$62b2o",
"3bo3b2o$62b2o4b3o2bo$70bob2o$70bo$69b2o3$61b2o$61bo$62b3o$64bo3$34bo$",
"34b3o$37bo$36b2o15b2o$52bobo$32b2o14b2o2bo$31bo2bo13bobob2o$31bob2o14b",
"2obo2bo$30b2o22b2o$29bo3b2o$30b3o2bo$33b2obo15b2o$32bo2bo5bo10b2o$32b",
"2o6bobo$40bobo$41bo$51b2o$52bo$35b2o12b3o$35b2o12bo$50b2o$51bo$50bo$",
"50b2o5$27b2o$28bo$28bobo$18bo10b2o$16b3o$15bo$15b2o$2o48b2o$bo48b2o$bo",
"b2o$2bo2bo$3b2o$18b2o$18b2o4$27bo3b2o$26bobo3bo$25bobo3bo$21b2obobo3bo",
"$21b2obo2b4obo5b2o$25bobo3bobo5bo$21b2ob2o2bo2bobo2b3o$22bobo2b2o3bo3b",
"o$10b2o10bobo$10b2o11bo!"
});
part51.ReadRLE(new string[] {
"x = 19, y = 23, rule = B3/S23",
"3bo$3b3o$6bo$5b2o7$15b2o$8b2o5bobo$8b2o7bo$17b2o2$4bo$3bobob2o$3bobobo",
"bo$2obobobobo2bo$o2bo2b2ob4o$2b2o4bo$8bobo$9b2o!"
});
part52.ReadRLE(new string[] {
"x = 21, y = 23, rule = B3/S23",
"bo$b3o$4bo$3b2o3$10bo$9bobo$10bo3b2ob2o$14b2obo2bo$19b2o$6b2o$6b2o4bo",
"2bo$12b4o$18bo$2bo11b5o$bobob2o7bo$bobobobo8bo$2obobobo2bo4b2o$bo2b2ob",
"4o$bo4bo$2b3obo2b2o$4b2o3b2o!"
});
part53.ReadRLE(new string[] {
"x = 18, y = 25, rule = B3/S23",
"2bo$2b3o$5bo$4b2o7$14b2o$14bobo$16bo$6b2o8b2o$6b2o4$4b2ob2o$2o3bob2o2b",
"2o$o2bobo6bo$2b2ob7o$4bo$4bob4o$5b2o2bo!",
});
part54.ReadRLE(new string[] {
"x = 22, y = 25, rule = B3/S23",
"2bo$2b3o$5bo$4b2o3$11bo$10bobo$11bo3b2ob2o$15b2obo2bo$20b2o$5bo$4bobo",
"6bo2bo$4bobo6b4o$5bo13bo$15b5o$15bo$17bo$4b2ob2o7b2o$2o3bob2o2b2o$o2bo",
"bo6bo$2b2ob7o$4bo$4bob4o$5b2o2bo!"
});
const int ld = 912;
var sd = new Dictionary<int, int>();
sd[1] = 1345;
sd[3] = 995;
sd[5] = 1005;
sd[7] = 935;
var newGuns = new Dictionary<int, Pattern>();
var newGunsCosts = new Dictionary<int, int>();
foreach (int mod in parts4.Keys)
{
foreach (int mul in parts5.Keys)
{
for (int shift = 0; shift < 1000; shift++)
{
int period = mul * ld + sd[mod] + 8 * shift;
if (!IsPrime(period))
continue;
if (period > 9999)
break;
int s4 = shift % mul;
int s23 = shift / mul;
int s3 = s23 / 2;
int s2 = s23 - s3;
if (mul * (s2 + s3) + s4 != shift)
throw new Exception();
int p1x = 0;
int p1y = 0;
int p2x = 87 + s2;
int p2y = -19 - s2;
int p3x = 9 - s3;
int p3y = -20 - s3;
int p4x = parts4x[mod] + s4;
int p4y = parts4y[mod] + s4;
int p5x = parts5x[mul];
int p5y = parts5y[mul];
int minX = Math.Min(p1x, Math.Min(p2x, Math.Min(p3x, Math.Min(p4x, p5x))));
int minY = Math.Min(p1y, Math.Min(p2y, Math.Min(p3y, Math.Min(p4y, p5y))));
p1x -= minX;
p2x -= minX;
p3x -= minX;
p4x -= minX;
p5x -= minX;
p1y -= minY;
p2y -= minY;
p3y -= minY;
p4y -= minY;
p5y -= minY;
int width = 0;
int height = 0;
width = Math.Max(width, p1x + part1.GridWidth);
width = Math.Max(width, p2x + part2.GridWidth);
width = Math.Max(width, p3x + part3.GridWidth);
width = Math.Max(width, p4x + parts4[mod].GridWidth);
width = Math.Max(width, p5x + parts5[mul].GridWidth);
height = Math.Max(height, p1y + part1.GridHeight);
height = Math.Max(height, p2y + part2.GridHeight);
height = Math.Max(height, p3y + part3.GridHeight);
height = Math.Max(height, p4y + parts4[mod].GridHeight);
height = Math.Max(height, p5y + parts5[mul].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);
gun.Stamp(part3, p3x, p3y);
gun.Stamp(parts4[mod], p4x, p4y);
gun.Stamp(parts5[mul], p5x, p5y);
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();
}
}
}
I'm not sure if my latest posts belong to "Gun Discussion Thread", "Small Four-Digit Prime Period Guns" or "Execution of Old Guns by Variable-Speed Firing Squad". Please move them to a more appropriate place if needed.