It's fine to move it to more appropriate place.
How fast your script simulate 10x10 torus soups?iddi01 wrote: ↑June 3rd, 2024, 8:27 amUsing my methuselah searcher, i got 249 generations on 10x10 torus:
Mine is getting approximately 8000 soups/sec on single core of i5-4690.
After ~1.5 million soups lifespan of 490 was achieved, after 4.4 million, lifespan of 491:
Code: Select all
x = 10, y = 10, rule = B3/S23:T10,10
7bo$2o4b2obo$o$2o3bo$bo$b3obo2bo$bobobo$4b2o3bo$2obobo$bo4bo2bo!Code: Select all
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace TorusLife
{
class Pattern : IEquatable<Pattern>
{
public const int GridWidth = 10;
public const int GridHeight = 10;
int[,] cells;
public Pattern()
{
cells = new int[GridWidth, GridHeight];
}
public Pattern(Pattern source)
{
cells = new int[GridWidth, GridHeight];
for (int y = 0; y < GridHeight; y++)
for (int x = 0; x < GridWidth; x++)
cells[x, y] = source.cells[x, y];
}
public Pattern Generate()
{
var result = new Pattern();
for (int y = 0; y < GridHeight; y++)
{
int ym1 = y - 1;
int yp1 = y + 1;
if (ym1 < 0)
ym1 = GridHeight - 1;
else if (ym1 >= GridHeight)
ym1 = 0;
if (yp1 < 0)
yp1 = GridHeight - 1;
else if (yp1 >= GridHeight)
yp1 = 0;
for (int x = 0; x < GridWidth; x++)
{
int xm1 = x - 1;
int xp1 = x + 1;
if (xm1 < 0)
xm1 = GridWidth - 1;
else if (xm1 >= GridWidth)
xm1 = 0;
if (xp1 < 0)
xp1 = GridWidth - 1;
else if (xp1 >= GridWidth)
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) ? 1 : 0;
else
result.cells[x, y] = neighbours == 3 ? 1 : 0;
}
}
return result;
}
public void Randomize(Random rnd)
{
for (int y = 0; y < GridHeight; y++)
for (int x = 0; x < GridWidth; x++)
cells[x, y] = rnd.Next(100) < 35 ? 1 : 0;
}
public void Measure(out int lifespan, out int period)
{
Pattern pattern = this;
var patterns = new Dictionary<Pattern, int>();
patterns.Add(this, 0);
for (int i = 0; ; i++)
{
pattern = pattern.Generate();
int patternIndex;
if (patterns.TryGetValue(pattern, out patternIndex))
{
period = patterns.Count - patternIndex;
lifespan = i - period + 1;
return;
}
patterns.Add(pattern, i + 1);
}
}
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:T{GridWidth},{GridHeight}");
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"))
{
if (line.Split(':')[1] != $"T{GridWidth},{GridHeight}")
throw new Exception();
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));
}
public override int GetHashCode()
{
int hash = 0;
int shift = 0;
for (int y = 0; y < GridHeight; y++)
for (int x = 0; x < GridWidth; x++)
{
hash = hash ^ cells[x, y] << shift;
shift = (shift + 1) & 31;
}
return hash;
}
public bool Equals(Pattern other)
{
for (int y = 0; y < GridHeight; y++)
for (int x = 0; x < GridWidth; 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 += GridWidth;
else if (x >= GridWidth)
x -= GridWidth;
if (y < 0)
y += GridHeight;
else if (y >= GridHeight)
y -= GridWidth;
}
}
class Program
{
Program()
{
Random rnd = new Random();
int period;
int lifespan;
int totalMax = 0;
int countMax = 0;
int bestLifespan = 0;
int bestLifespanLocal = 0;
for (int i = 0; ; i++)
{
Pattern pattern = new Pattern();
pattern.Randomize(rnd);
pattern.Measure(out lifespan, out period);
if (i % 100000 == 0 && i != 0)
{
totalMax += bestLifespanLocal;
countMax++;
int avgMax = totalMax / countMax;
Console.WriteLine($"Iteration: {i,6}, lifespan: {bestLifespan,4} | {bestLifespanLocal,4} | {avgMax,4}");
bestLifespanLocal = 0;
}
if (lifespan > bestLifespan)
{
bestLifespan = lifespan;
pattern.WriteRLE(
$"{Pattern.GridWidth}x{Pattern.GridHeight}_{lifespan}.rle",
$"lifespan: {lifespan}, period: {period}");
}
if (lifespan > bestLifespanLocal)
bestLifespanLocal = lifespan;
}
}
static void Main(string[] args)
{
new Program();
}
}
}