init
This commit is contained in:
0
.gitignore
vendored
Normal file
0
.gitignore
vendored
Normal file
25
InverseOfLife.Test.csproj
Normal file
25
InverseOfLife.Test.csproj
Normal file
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<RootNamespace>InverseOfLife.Test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InverseOfLife\InverseOfLife.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
InverseOfLife.Test.sln
Normal file
16
InverseOfLife.Test.sln
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InverseOfLife.Test", "InverseOfLife.Test.csproj", "{DD3D4C28-4E98-4DE8-8D06-4F4F6CEF09EB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DD3D4C28-4E98-4DE8-8D06-4F4F6CEF09EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DD3D4C28-4E98-4DE8-8D06-4F4F6CEF09EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DD3D4C28-4E98-4DE8-8D06-4F4F6CEF09EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DD3D4C28-4E98-4DE8-8D06-4F4F6CEF09EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
89
tests/BoardTests.cs
Normal file
89
tests/BoardTests.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
[TestFixture]
|
||||
public class BoardTests
|
||||
{
|
||||
[Test]
|
||||
public void BoardInitializationTest()
|
||||
{
|
||||
var board = new Board(5, 5);
|
||||
|
||||
Assert.That(board.Width, Is.EqualTo(5));
|
||||
Assert.That(board.Height, Is.EqualTo(5));
|
||||
Assert.IsNotNull(board.Lives);
|
||||
Assert.That(board.Lives.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToggleTest_AddAndRemoveCells()
|
||||
{
|
||||
var board = new Board(5, 5);
|
||||
board.Toggle(2, 2);
|
||||
Assert.That(board.Lives, Contains.Item((2, 2)));
|
||||
board.Toggle(2, 2);
|
||||
Assert.IsFalse(board.Lives.Contains((2, 2)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EvaluateTest_WithSimpleRule()
|
||||
{
|
||||
var board = new Board(5, 5);
|
||||
board.Toggle(2, 2);
|
||||
board.Toggle(3, 2);
|
||||
board.Toggle(4, 2);
|
||||
Assert.IsTrue(board.Lives.Contains((2, 2)));
|
||||
Assert.IsTrue(board.Lives.Contains((3, 2)));
|
||||
Assert.IsTrue(board.Lives.Contains((4, 2)));
|
||||
board.Evaluate();
|
||||
Assert.IsFalse(board.Lives.Contains((2, 2)));
|
||||
Assert.IsTrue(board.Lives.Contains((3, 2)));
|
||||
Assert.IsFalse(board.Lives.Contains((4, 2)));
|
||||
Assert.IsTrue(board.Lives.Contains((3, 1)));
|
||||
Assert.IsTrue(board.Lives.Contains((3, 3)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToStringTest_BasicGridRepresentation()
|
||||
{
|
||||
var board = new Board(5, 5);
|
||||
|
||||
board.Toggle(1, 1);
|
||||
board.Toggle(3, 2);
|
||||
board.Toggle(4, 4);
|
||||
|
||||
string expected =
|
||||
" \n" +
|
||||
" o \n" +
|
||||
" o \n" +
|
||||
" \n" +
|
||||
" o\n";
|
||||
|
||||
Assert.That(board.ToString(), Is.EqualTo(expected));
|
||||
Console.Write(board.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToStringTest_WithEmptyBoard()
|
||||
{
|
||||
var board = new Board(3, 3);
|
||||
|
||||
string expected =
|
||||
" \n" +
|
||||
" \n" +
|
||||
" \n";
|
||||
|
||||
Assert.That(board.ToString(), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PopulateTest_PeriodicBoundaryCondition()
|
||||
{
|
||||
var board = new Board(3, 3, true, true);
|
||||
board.Toggle(0, 0);
|
||||
var neighbourCount = new Dictionary<(int, int), int>();
|
||||
board.Populate(0, 0, neighbourCount);
|
||||
Assert.That(neighbourCount[(1, 0)], Is.EqualTo(1));
|
||||
Assert.That(neighbourCount[(2, 2)], Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
105
tests/CellTracerTests.cs
Normal file
105
tests/CellTracerTests.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
|
||||
[TestFixture]
|
||||
public class CellTracerTests
|
||||
{
|
||||
private Board board;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
board = new Board(5, 5, useTracer: true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InitializeBoard_WithTracer_ShouldHaveNoCellsOrContributions()
|
||||
{
|
||||
var initialState = board.ToString();
|
||||
|
||||
Assert.IsNotNull(board.Tracer);
|
||||
Assert.That(board.Tracer!.Contribution, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Toggle_ShouldNotAffectTracer()
|
||||
{
|
||||
board.Toggle(1, 1);
|
||||
board.Toggle(2, 2);
|
||||
|
||||
Assert.That(board.Lives, Is.EquivalentTo(new[] { (1, 1), (2, 2) }));
|
||||
Assert.That(board.Tracer!.Contribution, Is.Empty); // Tracer not affected by Toggle
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Evaluate_WithTracer_ShouldTrackNewCellContributions()
|
||||
{
|
||||
board.Toggle(1, 2, initialConfig: true);
|
||||
board.Toggle(2, 2, initialConfig: true);
|
||||
board.Toggle(3, 2, initialConfig: true);
|
||||
|
||||
board.Evaluate();
|
||||
|
||||
Assert.That(board.Lives, Is.EquivalentTo(new[] { (2, 1), (2, 2), (2, 3) }));
|
||||
|
||||
var tracer = board.Tracer!;
|
||||
Assert.That(tracer.Contribution.ContainsKey((2, 1)), Is.True);
|
||||
Assert.That(tracer.Contribution.ContainsKey((2, 3)), Is.True);
|
||||
|
||||
var contributions = tracer.Contribution[(2, 1)];
|
||||
Assert.That(contributions.Keys, Is.EquivalentTo(new[] { (1, 2), (2, 2), (3, 2) }));
|
||||
Assert.That(contributions[(1, 2)], Is.EqualTo(1.0 / 3.0));
|
||||
Assert.That(contributions[(2, 2)], Is.EqualTo(1.0 / 3.0));
|
||||
Assert.That(contributions[(3, 2)], Is.EqualTo(1.0 / 3.0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Evaluate_WithTracer_ShouldRemoveDeadCellContributions()
|
||||
{
|
||||
board.Toggle(1, 2, initialConfig: true);
|
||||
board.Toggle(2, 2, initialConfig: true);
|
||||
board.Toggle(3, 2, initialConfig: true);
|
||||
|
||||
board.Evaluate();
|
||||
|
||||
board.Evaluate();
|
||||
|
||||
Assert.That(board.Lives, Is.EquivalentTo(new[] { (2, 2), (1, 2), (3, 2) }));
|
||||
|
||||
var tracer = board.Tracer!;
|
||||
Assert.That(tracer.Contribution.ContainsKey((2, 2)), Is.True);
|
||||
Assert.That(tracer.Contribution.ContainsKey((2, 1)), Is.False);
|
||||
Assert.That(tracer.Contribution.ContainsKey((2, 3)), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BatchProcess_ShouldApplyDeferredAddAndRemoveCorrectly()
|
||||
{
|
||||
board.Toggle(1, 2, initialConfig: true);
|
||||
board.Toggle(2, 2, initialConfig: true);
|
||||
board.Toggle(3, 2, initialConfig: true);
|
||||
board.Evaluate();
|
||||
|
||||
Assert.That(board.Lives, Does.Contain((2, 1)));
|
||||
Assert.That(board.Lives, Does.Not.Contain((1, 2)));
|
||||
|
||||
Assert.That(board.Tracer!.Contribution.ContainsKey((1, 2)), Is.False);
|
||||
Assert.That(board.Tracer!.Contribution.ContainsKey((2, 1)), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Play_ShouldRunGenerationsAndUpdateTracer()
|
||||
{
|
||||
board.Toggle(1, 2, initialConfig: true);
|
||||
board.Toggle(2, 2, initialConfig: true);
|
||||
board.Toggle(3, 2, initialConfig: true);
|
||||
|
||||
board.Play(3, delay: 0);
|
||||
|
||||
Assert.That(board.Lives, Is.EquivalentTo(new[] { (2, 1), (2, 2), (2, 3) }));
|
||||
|
||||
var tracer = board.Tracer!;
|
||||
Assert.That(tracer.Contribution.ContainsKey((2, 2)), Is.True);
|
||||
}
|
||||
}
|
||||
46
tests/EvoluteTests.cs
Normal file
46
tests/EvoluteTests.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
[TestFixture]
|
||||
public class EvoluteTests
|
||||
{
|
||||
[Test]
|
||||
public void Mutate_ShouldModifyBitsBasedOnRate()
|
||||
{
|
||||
int resolution = 3;
|
||||
byte[] riboseSequence = [0b10101010, 0b11110000, 0b00001111, 0b00110011];
|
||||
var gene = new Gene(resolution, riboseSequence);
|
||||
|
||||
float mutationRate = 1.0f;
|
||||
var mutatedGene = gene.Mutate(0, mutationRate);
|
||||
|
||||
Assert.That(mutatedGene.RiboseSequence, Is.Not.EqualTo(riboseSequence));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Mutate_WithZeroRate_ShouldNotChangeRiboseSequence()
|
||||
{
|
||||
int resolution = 3;
|
||||
byte[] riboseSequence = [0b10101010, 0b11110000, 0b00001111, 0b00110011];
|
||||
var gene = new Gene(resolution, riboseSequence);
|
||||
|
||||
float mutationRate = 0.0f;
|
||||
var mutatedGene = gene.Mutate(0, mutationRate);
|
||||
|
||||
Assert.That(mutatedGene.RiboseSequence, Is.EqualTo(riboseSequence));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Mutate_WithSpecificRiboseIndex_ShouldOnlyAffectSpecifiedIndex()
|
||||
{
|
||||
int resolution = 3;
|
||||
byte[] riboseSequence = [0b10101010, 0b11110000, 0b00001111, 0b00001111];
|
||||
var gene = new Gene(resolution, riboseSequence);
|
||||
|
||||
float mutationRate = 0.5f;
|
||||
int riboseIndex = 1;
|
||||
var mutatedGene = gene.Mutate(riboseIndex, mutationRate);
|
||||
|
||||
Assert.That(mutatedGene.RiboseSequence[0], Is.EqualTo(riboseSequence[0]));
|
||||
}
|
||||
}
|
||||
124
tests/GeneEncodeDecodeTests.cs
Normal file
124
tests/GeneEncodeDecodeTests.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
[TestFixture]
|
||||
public class GeneEncodeDecodeTests
|
||||
{
|
||||
[Test]
|
||||
public void EncodeAndDecode_ShouldHandleResolution1Correctly()
|
||||
{
|
||||
int resolution = 1;
|
||||
int width = 8;
|
||||
int height = 8;
|
||||
var board = new Board(width, height);
|
||||
board.Toggle(0, 0);
|
||||
board.Toggle(7, 7);
|
||||
board.Toggle(3, 5);
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((0, 0)), "Cell (0, 0) should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((7, 7)), "Cell (7, 7) should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((3, 5)), "Cell (3, 5) should be alive.");
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(board.Lives), "Restored board should match the original board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodeAndDecode_ShouldHandleResolution2Correctly()
|
||||
{
|
||||
int resolution = 2;
|
||||
int width = 4;
|
||||
int height = 4;
|
||||
var board = new Board(width, height);
|
||||
board.Toggle(0, 0);
|
||||
board.Toggle(3, 3);
|
||||
board.Toggle(2, 1);
|
||||
board.Toggle(1, 2);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((0, 0)), "Cell (0, 0) should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((3, 3)), "Cell (3, 3) should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((2, 1)), "Cell (2, 1) should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((1, 2)), "Cell (1, 2) should be alive.");
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(board.Lives), "Restored board should match the original board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodeAndDecode_ShouldHandleEmptyBoardResolution1()
|
||||
{
|
||||
int resolution = 1;
|
||||
int width = 8;
|
||||
int height = 8;
|
||||
var board = new Board(width, height);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsEmpty(restoredBoard.Lives, "Restored board should be empty.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodeAndDecode_ShouldHandleEmptyBoardResolution2()
|
||||
{
|
||||
int resolution = 2;
|
||||
int width = 4;
|
||||
int height = 4;
|
||||
var board = new Board(width, height);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsEmpty(restoredBoard.Lives, "Restored board should be empty.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodeAndDecode_ShouldHandleFullBoardResolution1()
|
||||
{
|
||||
int resolution = 1;
|
||||
int width = 8;
|
||||
int height = 8;
|
||||
var board = new Board(width, height);
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
board.Toggle(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
foreach (byte b in gene.RiboseSequence)
|
||||
{
|
||||
Console.Write($"{b} ");
|
||||
Console.WriteLine();
|
||||
}
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
Console.WriteLine("-");
|
||||
Console.WriteLine(restoredBoard.ToString());
|
||||
Console.WriteLine("=");
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(board.Lives), "Restored board should match the original full board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodeAndDecode_ShouldHandleFullBoardResolution2()
|
||||
{
|
||||
int resolution = 2;
|
||||
int width = 4;
|
||||
int height = 4;
|
||||
var board = new Board(width, height);
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
board.Toggle(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
Console.WriteLine(restoredBoard.ToString());
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(board.Lives), "Restored board should match the original full board.");
|
||||
}
|
||||
}
|
||||
45
tests/GeneIndexerTest.cs
Normal file
45
tests/GeneIndexerTest.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
|
||||
[TestFixture]
|
||||
public class GeneIndexerTests
|
||||
{
|
||||
[Test]
|
||||
public void Indexer_GranularityPositive_ReadWriteBytes()
|
||||
{
|
||||
var riboseSequence = new byte[] { 0b10101010, 0b11110000, 0b00001111, 0b11001100 };
|
||||
var gene = new Gene(3, riboseSequence);
|
||||
|
||||
byte[] expected = [0b00001111, 0b11001100];
|
||||
Assert.That(gene[1], Is.EqualTo(expected));
|
||||
|
||||
gene[1] = [0b01010101, 0b10101010];
|
||||
Assert.That(gene[1], Is.EqualTo(new byte[] { 0b01010101, 0b10101010 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_GranularityNegative_ReadWriteBits()
|
||||
{
|
||||
var riboseSequence = new byte[] { 0b10101010, 0b11110000 };
|
||||
var gene = new Gene(1, riboseSequence);
|
||||
|
||||
byte[] expected = [0b00000001];
|
||||
Assert.That(gene[7], Is.EqualTo(expected));
|
||||
|
||||
gene[7] = [0b00000000];
|
||||
Assert.That(gene[7], Is.EqualTo(new byte[] { 0b00000000 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_GranularityExceed_ThrowsException()
|
||||
{
|
||||
var riboseSequence = new byte[] { 0b10101010, 0b11110000 };
|
||||
var gene = new Gene(3, riboseSequence);
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
gene[0] = [0b10101010, 0b11110000, 0b00001111];
|
||||
});
|
||||
}
|
||||
}
|
||||
140
tests/GeneTests.cs
Normal file
140
tests/GeneTests.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using NUnit.Framework;
|
||||
namespace InverseOfLife.Test;
|
||||
|
||||
[TestFixture]
|
||||
public class GeneTests
|
||||
{
|
||||
[Test]
|
||||
public void Gene_Constructor_FromBoard_CorrectEncoding()
|
||||
{
|
||||
int resolution = 4;
|
||||
var board = new Board(8, 8);
|
||||
board.Toggle(1, 1);
|
||||
board.Toggle(5, 5);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
|
||||
int encodedBits = gene.RiboseSequence.Sum(b => CountSetBits(b));
|
||||
Assert.That(encodedBits, Is.EqualTo(2), "Encoded bits should match the number of live cells.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gene_Constructor_FromSequence_CorrectRestoration()
|
||||
{
|
||||
int resolution = 4;
|
||||
var expectedBoard = new Board(8, 8);
|
||||
expectedBoard.Toggle(1, 1);
|
||||
expectedBoard.Toggle(5, 5);
|
||||
var gene = new Gene(resolution, expectedBoard);
|
||||
|
||||
var restoredBoard = gene.Restore(8,8);
|
||||
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(expectedBoard.Lives), "Restored board should match the original board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gene_Constructor_EmptyBoard_RestoreEmptyBoard()
|
||||
{
|
||||
int resolution = 4;
|
||||
var board = new Board(8, 8);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(8,8);
|
||||
|
||||
Assert.IsEmpty(restoredBoard.Lives, "Restored board should be empty for an empty input board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gene_Restore_LargerBoard()
|
||||
{
|
||||
int resolution = 4;
|
||||
var board = new Board(16, 16);
|
||||
board.Toggle(2, 2);
|
||||
board.Toggle(10, 10);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(16,16);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((2, 2)), "Cell (2, 2) should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((10, 10)), "Cell (10, 10) should be alive.");
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(board.Lives), "Restored board should match the original board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gene_Restore_BoundaryCells()
|
||||
{
|
||||
|
||||
int resolution = 4;
|
||||
var board = new Board(8, 8);
|
||||
board.Toggle(0, 0);
|
||||
board.Toggle(7, 7);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(8,8);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((0, 0)), "Top-left corner cell should be alive.");
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((7, 7)), "Bottom-right corner cell should be alive.");
|
||||
Assert.That(restoredBoard.Lives, Is.EquivalentTo(board.Lives), "Restored board should match the original board.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gene_Restore_NonMultipleWidth()
|
||||
{
|
||||
int resolution = 4;
|
||||
int width = 10;
|
||||
int height = 8;
|
||||
var board = new Board(width, height);
|
||||
board.Toggle(9, 1);
|
||||
board.Toggle(1, 7);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((9, 1)));
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((1, 7)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gene_Restore_NonMultipleHeight()
|
||||
{
|
||||
int resolution = 4;
|
||||
int width = 8;
|
||||
int height = 9;
|
||||
var board = new Board(width, height);
|
||||
board.Toggle(7, 8);
|
||||
board.Toggle(0, 0);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((7, 8)));
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((0, 0)));
|
||||
}
|
||||
[Test]
|
||||
public void Gene_Restore_NonMultipleWidthAndHeight()
|
||||
{
|
||||
int resolution = 4;
|
||||
int width = 10;
|
||||
int height = 9;
|
||||
var board = new Board(width, height);
|
||||
board.Toggle(9, 8);
|
||||
board.Toggle(0, 0);
|
||||
|
||||
var gene = new Gene(resolution, board);
|
||||
var restoredBoard = gene.Restore(width, height);
|
||||
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((9, 8)));
|
||||
Assert.IsTrue(restoredBoard.Lives.Contains((0, 0)));
|
||||
}
|
||||
|
||||
private int CountSetBits(byte b)
|
||||
{
|
||||
int count = 0;
|
||||
while (b > 0)
|
||||
{
|
||||
count += b & 1;
|
||||
b >>= 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
176
tests/ScoreTests.cs
Normal file
176
tests/ScoreTests.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
|
||||
[TestFixture]
|
||||
public class ScoreTests
|
||||
{
|
||||
[Test]
|
||||
public void Score_AllCellsMatch_ReturnsOne()
|
||||
{
|
||||
var board1 = new Board(3, 3);
|
||||
var board2 = new Board(3, 3);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(2, 2);
|
||||
|
||||
board2.Toggle(0, 0);
|
||||
board2.Toggle(1, 1);
|
||||
board2.Toggle(2, 2);
|
||||
|
||||
double score = Summarizer.Score(board1, board2);
|
||||
Assert.That(score, Is.EqualTo(1.0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Score_NoMatchingCells_ReturnsZero()
|
||||
{
|
||||
var board1 = new Board(3, 3);
|
||||
var board2 = new Board(3, 3);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(2, 2);
|
||||
|
||||
board2.Toggle(0, 1);
|
||||
board2.Toggle(1, 2);
|
||||
board2.Toggle(2, 0);
|
||||
|
||||
double score = Summarizer.Score(board1, board2);
|
||||
Assert.That(score, Is.EqualTo(1d / 3d));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Score_PartialMatch_ReturnsCorrectValue()
|
||||
{
|
||||
var board1 = new Board(3, 3);
|
||||
var board2 = new Board(3, 3);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(2, 2);
|
||||
|
||||
board2.Toggle(0, 0);
|
||||
board2.Toggle(1, 2);
|
||||
board2.Toggle(2, 1);
|
||||
|
||||
double score = Summarizer.Score(board1, board2);
|
||||
|
||||
double tp = 1;
|
||||
double tn = 3 * 3 - 5;
|
||||
double total = 9;
|
||||
|
||||
Assert.That(score, Is.EqualTo((tp + tn) / total).Within(1e-8));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScoreBySubGrid_AllCellsMatch_ReturnsOneForAllSubGrids()
|
||||
{
|
||||
var board1 = new Board(4, 4);
|
||||
var board2 = new Board(4, 4);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(2, 2);
|
||||
board1.Toggle(3, 3);
|
||||
|
||||
board2.Toggle(0, 0);
|
||||
board2.Toggle(1, 1);
|
||||
board2.Toggle(2, 2);
|
||||
board2.Toggle(3, 3);
|
||||
|
||||
var scores = Summarizer.ScoreBySubGrid(board1, board2, 2);
|
||||
|
||||
Assert.That(scores[0], Is.EqualTo(1.0));
|
||||
Assert.That(scores[1], Is.EqualTo(1.0));
|
||||
Assert.That(scores[2], Is.EqualTo(1.0));
|
||||
Assert.That(scores[3], Is.EqualTo(1.0));
|
||||
}
|
||||
/// <summary>
|
||||
/// xx xx 02 03
|
||||
/// xx xx 12 13
|
||||
/// 20 21 xx xx
|
||||
/// 30 31 xx xx
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ScoreBySubGrid_NoMatchingCells_ReturnsZeroForAllSubGrids()
|
||||
{
|
||||
var board1 = new Board(4, 4);
|
||||
var board2 = new Board(4, 4);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(2, 2);
|
||||
board1.Toggle(3, 3);
|
||||
|
||||
board2.Toggle(0, 1);
|
||||
board2.Toggle(1, 0);
|
||||
board2.Toggle(2, 3);
|
||||
board2.Toggle(3, 2);
|
||||
|
||||
var scores = Summarizer.ScoreBySubGrid(board1, board2, 2);
|
||||
|
||||
Assert.That(scores[0], Is.EqualTo(0.0));
|
||||
Assert.That(scores[1], Is.EqualTo(1.0));
|
||||
Assert.That(scores[2], Is.EqualTo(1.0));
|
||||
Assert.That(scores[3], Is.EqualTo(0.0));
|
||||
}
|
||||
/// <summary>
|
||||
/// oo 01 02 03
|
||||
/// 10 xx xx 13
|
||||
/// xx 21 xx 23
|
||||
/// 30 31 32 oo
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ScoreBySubGrid_PartialMatch_ReturnsCorrectScores()
|
||||
{
|
||||
var board1 = new Board(4, 4);
|
||||
var board2 = new Board(4, 4);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(2, 2);
|
||||
board1.Toggle(3, 3);
|
||||
|
||||
board2.Toggle(0, 0);
|
||||
board2.Toggle(1, 2);
|
||||
board2.Toggle(3, 3);
|
||||
board2.Toggle(2, 0);
|
||||
|
||||
var scores = Summarizer.ScoreBySubGrid(board1, board2, 2);
|
||||
|
||||
Assert.That(scores[0], Is.EqualTo(0.75d));
|
||||
Assert.That(scores[1], Is.EqualTo(0.75d));
|
||||
Assert.That(scores[2], Is.EqualTo(0.75d));
|
||||
Assert.That(scores[3], Is.EqualTo(0.75d));
|
||||
}
|
||||
/// <summary>
|
||||
/// oo 01 02 03 04 05
|
||||
/// 10 oo 12 13 14 15
|
||||
/// 20 21 22 23 24 25
|
||||
/// 30 31 32 33 34 35
|
||||
/// 40 41 42 43 oo 45
|
||||
/// 50 51 52 53 54 55
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ScoreBySubGrid_DifferentResolutions_CorrectSubGridCount()
|
||||
{
|
||||
var board1 = new Board(6, 6);
|
||||
var board2 = new Board(6, 6);
|
||||
|
||||
board1.Toggle(0, 0);
|
||||
board1.Toggle(1, 1);
|
||||
board1.Toggle(4, 4);
|
||||
|
||||
board2.Toggle(0, 0);
|
||||
board2.Toggle(1, 1);
|
||||
board2.Toggle(4, 4);
|
||||
|
||||
var scores2X2 = Summarizer.ScoreBySubGrid(board1, board2, 2);
|
||||
var scores3X3 = Summarizer.ScoreBySubGrid(board1, board2, 3);
|
||||
|
||||
Assert.That(scores2X2.Count, Is.EqualTo(9));
|
||||
Assert.That(scores3X3.Count, Is.EqualTo(4));
|
||||
}
|
||||
}
|
||||
36
tests/WeightTests.cs
Normal file
36
tests/WeightTests.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InverseOfLife.Test;
|
||||
[TestFixture]
|
||||
public class WeightTests
|
||||
{
|
||||
[Test]
|
||||
public void GetWeight_GeneralTest()
|
||||
{
|
||||
Board boardX = new Board(4, 4, useTracer: true);
|
||||
Board boardY = new Board(4, 4);
|
||||
boardX.Toggle(0, 1, true);
|
||||
boardX.Toggle(1, 1, true);
|
||||
boardX.Toggle(2, 1, true);
|
||||
Console.WriteLine(boardX.ToString());
|
||||
boardX.Evaluate();
|
||||
|
||||
boardY.Toggle(1, 2);
|
||||
boardY.Toggle(1, 3);
|
||||
|
||||
var t = Summarizer.GetWeight(boardX, boardY, 2);
|
||||
Assert.That(t.Length, Is.EqualTo(4));
|
||||
// Assert.That(t[0], Is.EqualTo(0));
|
||||
|
||||
Console.WriteLine(t[0]);
|
||||
Console.WriteLine(t[1]);
|
||||
Console.WriteLine(t[2]);
|
||||
Console.WriteLine(t[3]);
|
||||
|
||||
Console.WriteLine(boardX.ToString());
|
||||
Assert.That(t[1], Is.GreaterThan(0));
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user