I optimized guns with prime periods of ~1k..2k by generating modifications to gun_841 (mod 8 = 1), gun_883 (mod 8 = 3), gun_853 (mod 8 = 5) and gun_863 (mod 8 = 7) families with larger amount of snarks.
Code: Select all
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
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 static readonly Pattern GliderTop1;
public static readonly Pattern GliderTop2;
public static readonly Pattern GliderBottom1;
public static readonly Pattern GliderBottom2;
public static readonly Pattern GliderLeft1;
public static readonly Pattern GliderLeft2;
public static readonly Pattern GliderRight1;
public static readonly Pattern GliderRight2;
static Pattern()
{
GliderTop1 = ReadRLE("x = 3, y = 3", "3o$2bo$bo!");
GliderTop2 = ReadRLE("x = 3, y = 3", "3o$o$bo!");
GliderBottom1 = ReadRLE("x = 3, y = 3", "bo$2bo$3o!");
GliderBottom2 = ReadRLE("x = 3, y = 3", "bo$o$3o!");
GliderLeft1 = ReadRLE("x = 3, y = 3", "2o$obo$o!");
GliderLeft2 = ReadRLE("x = 3, y = 3", "o$obo$2o!");
GliderRight1 = ReadRLE("x = 3, y = 3", "2bo$obo$b2o!");
GliderRight2 = ReadRLE("x = 3, y = 3", "b2o$obo$2bo!");
}
public Pattern(int width, int height)
{
Width = width;
Height = height;
WordWidth = (Width + 63) / 64;
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 / 64;
int shift = x % 64;
return (cells[div + y * WordWidth] >> shift & 1UL) == 1UL;
}
set
{
int div = x / 64;
int shift = x % 64;
cells[div + y * WordWidth] &= ~(1UL << shift);
cells[div + y * WordWidth] |= (value ? 1UL : 0UL) << shift;
}
}
private static void HalfAdder(ulong a, ulong b, out ulong carry, out ulong sum)
{
sum = a ^ b;
carry = a & b;
}
private static void FullAdder(ulong a, ulong b, ulong c, out ulong carry, out ulong sum)
{
ulong temp = a ^ b;
sum = temp ^ c;
carry = a & b | temp & c;
}
public Pattern Advance()
{
ulong[] n1 = new ulong[WordCount];
ulong[] n2 = new ulong[WordCount];
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < WordWidth; x++)
{
ulong w = cells[x + y * WordWidth];
n1[x + y * WordWidth] |= w >> 1;
n2[x + y * WordWidth] |= w << 1;
if (x != 0)
n1[x - 1 + y * WordWidth] |= w << 63;
else
{
int shift = (Width + 63) % 64;
n1[WordWidth - 1 + y * WordWidth] |= (w & 1UL) << shift;
}
if (x != WordWidth - 1)
n2[x + 1 + y * WordWidth] |= w >> 63;
else
{
int shift1 = 64 - Width % 64;
ulong mask = 0xFFFFFFFFFFFFFFFFUL >> shift1;
n2[x + y * WordWidth] &= mask;
int shift2 = (Width - 1) % 64;
n2[y * WordWidth] |= w >> shift2;
}
}
}
var result = new Pattern(Width, Height);
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 j, k, l, m, n, o;
FullAdder(n1[im1], n1[i], n1[ip1], out m, out j);
FullAdder(n2[im1], n2[i], n2[ip1], out n, out k);
HalfAdder(cells[im1], cells[ip1], out o, out l);
ulong x, y, z, w;
FullAdder(j, k, l, out y, out w);
FullAdder(m, n, o, out x, out z);
result.cells[i] = (cells[i] | w) & (y ^ z) & ~x;
}
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(int expectedPeriod)
{
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 < expectedPeriod * 3; 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);
int period = tick - gliderTick;
if (period == lastPeriod)
{
if (period == expectedPeriod)
return new Pattern(Width, Height, latestGenerations[0], 3, 3);
else
return null;
}
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 static Pattern ReadRLE(string fileName)
{
return ReadRLE(File.ReadAllLines(fileName));
}
public override int GetHashCode()
{
ulong hash = (ulong)(Width << 16 | Height);
for (int i = 0; i < cells.Length; i++)
hash = hash ^ cells[i];
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 -= Height;
}
}
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 Port
{
public int PosX;
public int PosY;
public bool DirX;
public bool DirY;
}
class Reflector
{
public Pattern Pattern;
public Port InPort;
public Port OutPort;
public int Delay;
}
class Weld
{
public Reflector Reflector1;
public Reflector Reflector2;
public int Distance;
public Pattern Result;
public int OffsetX;
public int OffsetY;
}
public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] x, int[] y)
{
if (x.Length != y.Length)
{
return false;
}
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i])
{
return false;
}
}
return true;
}
public int GetHashCode(int[] obj)
{
int result = 17;
for (int i = 0; i < obj.Length; i++)
{
unchecked
{
result = result * 23 + obj[i];
}
}
return result;
}
}
class Program
{
Component initGlider;
List<Weld> welds;
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;
}
Pattern Build(Reflector[] reflectors, int[] offsets, ref int period)
{
var loopComponents = new List<Component>();
loopComponents.Add(initGlider);
int x = 0;
int y = 0;
period = 0;
bool welded = false;
for (int i = 0; i < reflectors.Length; i++)
{
Reflector r1 = reflectors[i];
Reflector r2 = reflectors[(i + 1) % reflectors.Length];
Weld weld = null;
foreach (var w in welds)
if (w.Reflector1 == r1 && w.Reflector2 == r2 && w.Distance == offsets[i])
{
weld = w;
break;
}
period += r1.Delay;
period += 4 * offsets[i];
if (!welded && weld != null)
{
welded = true;
loopComponents.Add(new Component(x + weld.OffsetX, y + weld.OffsetY, weld.Result));
}
else if (welded)
{
welded = false;
}
else
{
loopComponents.Add(new Component(x, y, r1.Pattern));
}
x += r1.OutPort.PosX - r2.InPort.PosX + (r1.OutPort.DirX ? 1 : -1) * offsets[i];
y += r1.OutPort.PosY - r2.InPort.PosY + (r1.OutPort.DirY ? 1 : -1) * offsets[i];
}
if (x != 0 || y != 0)
return null;
return Combine(loopComponents.ToArray());
}
Program()
{
Reflector rf = new Reflector
{
Pattern = 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!"),
InPort = new Port { PosX = 13, PosY = 38, DirX = false, DirY = false },
OutPort = new Port { PosX = 25, PosY = 14, DirX = true, DirY = true },
Delay = 157
};
Reflector rfr = new Reflector
{
Pattern = Pattern.ReadRLE(
"x = 33, y = 54, rule = B3/S23",
"19bo$17b3o$16bo$15bobo$15bobo$16bo5$2o$2o4$20b2o$20bobo$22bo$13b2o7b2o",
"$13b2o2$3bob2o$b3ob2o$o$b3ob2o$3b2o2bo$6bobo$2bob2obobo16bo$2b2obo2bo",
"15b3o$5bo17bo$5b2o16b2o$3b2o2bobo$2bo2bo2b2o$3b2o8$10b2o19b2o$10b2o19b",
"2o3$9b2o$10bo$7b3o$7bo2$24b2o$24bo$25b3o$27bo!"),
InPort = new Port { PosX = 13, PosY = 54 - 38 - 3, DirX = false, DirY = !false },
OutPort = new Port { PosX = 25, PosY = 54 - 14 - 3, DirX = true, DirY = !true },
Delay = 157
};
Reflector rl = new Reflector
{
Pattern = 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",
"2ob2o3$33bo$31b3o$30bo$30b2o$bo$b3o$4bo$3bo$3b2o$b2o2bo$o2b3o$bo23bo$",
"2b4o6b2o3b2o5bobo$4bo7b2o3b2o6bo$6bo$5b2o!"),
InPort = new Port { PosX = 20, PosY = 13, DirX = true, DirY = true },
OutPort = new Port { PosX = 13, PosY = 38, DirX = false, DirY = false },
Delay = 164
};
Reflector rm1 = new Reflector
{
Pattern = Pattern.ReadRLE(
"x = 19, y = 23, rule = B3/S23",
"15bo$13b3o$12bo$12b2o7$2b2o$bobo5b2o$bo7b2o$2o2$14bo$10b2obobo$9bobobo",
"bo$6bo2bobobobob2o$6b4ob2o2bo2bo$10bo4b2o$8bobo$8b2o!"),
InPort = new Port { PosX = 9, PosY = 6, DirX = true, DirY = true },
OutPort = new Port { PosX = 14, PosY = 8, DirX = true, DirY = false },
Delay = 24
};
Reflector rm2 = new Reflector
{
Pattern = 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!"),
InPort = new Port { PosX = 9, PosY = 14, DirX = true, DirY = false },
OutPort = new Port { PosX = 14, PosY = 12, DirX = true, DirY = true },
Delay = 24
};
Reflector rm3 = new Reflector
{
Pattern = Pattern.ReadRLE(
"x = 19, y = 23, rule = B3/S23",
"9b2o$8bobo$2b2o4bo$o2bo2b2ob4o$2obobobobo2bo$3bobobobo$3bobob2o$4bo2$",
"17b2o$8b2o7bo$8b2o5bobo$15b2o7$5b2o$6bo$3b3o$3bo!"),
InPort = new Port { PosX = 7, PosY = 14, DirX = false, DirY = false },
OutPort = new Port { PosX = 2, PosY = 12, DirX = false, DirY = true },
Delay = 24
};
Reflector rm4 = new Reflector
{
Pattern = 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!"),
InPort = new Port { PosX = 7, PosY = 6, DirX = false, DirY = true },
OutPort = new Port { PosX = 2, PosY = 8, DirX = false, DirY = false },
Delay = 24
};
welds = new List<Weld>();
welds.Add(new Weld
{
Reflector1 = rm2,
Reflector2 = rl,
Distance = 9,
Result = Pattern.ReadRLE(
"x = 39, y = 59, rule = B3/S23",
"8b2o$8bobo$10bo4b2o$6b4ob2o2bo2bo$6bo2bobobobob2o$9bobobobo$10b2obobo$",
"14bo$19bo$2o17b3o$bo7b2o11bo$bobo5b2o10bobo$2b2o17bobo$22bo5$37b2o$12b",
"2o23b2o$12bo$13b3o$15bo$15bob2o$13b2obobo$13bo2bo$15b2o7b2o$24b2o2$32b",
"2obo$32b2ob3o$38bo$32b2ob3o$31bo2b2o$30bobo$12bo16bobob3o$12b3o15bo2bo",
"2bo$15bo17bobobo$14b2o16b2o2bobo$29bobo2bobobo$29b2o2b2ob2o3$36bo$34b",
"3o$33bo$33b2o$4bo$4b3o$7bo$6bo$6b2o$4b2o2bo$3bo2b3o$4bo23bo$5b4o6b2o3b",
"2o5bobo$7bo7b2o3b2o6bo$9bo$8b2o!"),
OffsetX = 0,
OffsetY = 0
});
welds.Add(new Weld
{
Reflector1 = rm4,
Reflector2 = rf,
Distance = 9,
Result = Pattern.ReadRLE(
"x = 39, y = 62, 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$22bo2bo$20bobob",
"2o$20b2obo$23bo$23b3o$26bo$2o23b2o$2o5$16bo$15bobo17b2o$15bobo10b2o5bo",
"bo$16bo11b2o7bo$17b3o17b2o$19bo$24bo$23bobob2o$23bobobobo$20b2obobobob",
"o2bo$20bo2bo2b2ob4o$22b2o4bo$28bobo$29b2o!"),
OffsetX = -20,
OffsetY = -39
});
welds.Add(new Weld
{
Reflector1 = rm3,
Reflector2 = rfr,
Distance = 9,
Result = Pattern.ReadRLE(
"x = 39, y = 62, rule = B3/S23",
"29b2o$28bobo$22b2o4bo$20bo2bo2b2ob4o$20b2obobobobo2bo$23bobobobo$23bob",
"ob2o$24bo$19bo$17b3o17b2o$16bo11b2o7bo$15bobo10b2o5bobo$15bobo17b2o$",
"16bo5$2o$2o23b2o$26bo$23b3o$23bo$20b2obo$20bobob2o$22bo2bo$13b2o7b2o$",
"13b2o2$3bob2o$b3ob2o$o$b3ob2o$3b2o2bo$6bobo$2bob2obobo16bo$2b2obo2bo",
"15b3o$5bo17bo$5b2o16b2o$3b2o2bobo$2bo2bo2b2o$3b2o8$10b2o19b2o$10b2o19b",
"2o3$9b2o$10bo$7b3o$7bo2$24b2o$24bo$25b3o$27bo!"),
OffsetX = -20,
OffsetY = 0
});
//var reflectors = new Reflector[] { rf, rm1, rm2, rl, rm3, rm4 };
var reflectors = new Reflector[] { rfr, rm2, rm1, rm2, rl, rm3, rm4, rm3 };
//var reflectors = new Reflector[] { rf, rm2, rm1, rm2, rm1, rm2, rm1, rl, rm4, rm3, rm4, rm3, rm4, rm3 };
//var reflectors = new Reflector[] { rf, rm2, rm1, rm2, rm1, rm2, rlf, rm3, rm4, rm3, rm4, rm3 };
var firstReflector = reflectors[0];
initGlider = new Component(firstReflector.InPort.PosX, firstReflector.InPort.PosY, null);
if (firstReflector.InPort.DirX == false && firstReflector.InPort.DirY == false)
initGlider.Pattern = Pattern.GliderTop2;
else if (firstReflector.InPort.DirX == false && firstReflector.InPort.DirY == true)
initGlider.Pattern = Pattern.GliderBottom2;
int period = 0;
Pattern pattern = null;
var rnd = new Random();
int[] seedOffsets = null;
if (true)
{
seedOffsets = new int[reflectors.Length];
for (; ; )
{
for (int j = 0; j < seedOffsets.Length; j++)
{
if (j == reflectors.Length / 2 - 1 || j == reflectors.Length - 1)
seedOffsets[j] = rnd.Next(9, 12);
else
seedOffsets[j] = rnd.Next(15, 35);
}
pattern = Build(reflectors, seedOffsets, ref period);
if (pattern != null)
{
Console.Write('.');
pattern = pattern.Normalize(period);
if (pattern != null)
break;
}
}
Console.WriteLine();
}
else
{
seedOffsets = new int[] { 23, 26, 20, 9, 34, 14, 26, 9 };
pattern = Build(reflectors, seedOffsets, ref period).Normalize(period);
}
int area = pattern.Width * pattern.Height;
var visited = new HashSet<int[]>(new IntArrayEqualityComparer());
var bestArea = new Dictionary<int, int>();
var bestResults = new Dictionary<int, List<int[]>>();
visited.Add(seedOffsets);
bestArea.Add(period, area);
bestResults.Add(period, new List<int[]> { seedOffsets });
var costsS = new WebClient().DownloadString(
"https://catagolue.hatsya.com/textcensus/b3s23/synthesis-costs/gun");
var costs = ParseCosts(costsS);
for (int generation = 0; ; generation++)
{
var temp = bestResults.ElementAt(rnd.Next(bestResults.Count)).Value;
int[] newOffsets = temp[rnd.Next(temp.Count)].ToArray();
for (int j = 0; j < newOffsets.Length; j++)
{
if (j != 5 && j != 11)
newOffsets[j] += rnd.Next(-2, 3);
else
{
newOffsets[j] += rnd.Next(-1, 2);
if (newOffsets[j] < 9)
newOffsets[j] = 9;
}
}
if (visited.Contains(newOffsets))
continue;
visited.Add(newOffsets);
pattern = Build(reflectors, newOffsets, ref period);
if (pattern != null && period < 1500)
{
Pattern norm = pattern.Normalize(period);
if (norm != null)
{
pattern = norm;
area = pattern.Width * pattern.Height;
if (bestResults.ContainsKey(period))
{
if (area < bestArea[period])
{
bestArea[period] = area;
bestResults[period] = new List<int[]> { newOffsets };
if (costs.ContainsKey(period) && costs[period] > area)
pattern.WriteRLE($"gun_{period}.rle", $"Area: {area}");
}
else if (area == bestArea[period])
bestResults[period].Add(newOffsets);
}
else
{
bestArea.Add(period, area);
bestResults.Add(period, new List<int[]> { newOffsets });
if (costs.ContainsKey(period) && costs[period] > area)
pattern.WriteRLE($"gun_{period}.rle", $"Area: {area}");
}
}
}
if (generation % 500 == 0)
{
Console.WriteLine($"Generation: {generation}");
foreach (var p in bestArea.Keys.OrderBy(x => x))
{
area = bestArea[p];
if (!costs.ContainsKey(p))
Console.ForegroundColor = ConsoleColor.Gray;
else if (costs[p] < area)
Console.ForegroundColor = ConsoleColor.Red;
else if (costs[p] == area)
Console.ForegroundColor = ConsoleColor.Yellow;
else
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"p: {p}, a: {area}, o: {string.Join(",", bestResults[p][0])}");
Console.ForegroundColor = ConsoleColor.Gray;
}
Console.WriteLine();
}
}
}
static void Main()
{
new Program();
}
}
}