Refactor timeline factory to generate string ids
The strings are immediately shimmed back to ints for now
This commit is contained in:
parent
40254b0fca
commit
780ae8b948
@ -5,16 +5,6 @@ namespace MultiversalDiplomacy.Model;
|
||||
/// </summary>
|
||||
public class Season
|
||||
{
|
||||
/// <summary>
|
||||
/// A shared counter for handing out new timeline numbers.
|
||||
/// </summary>
|
||||
private class TimelineFactory
|
||||
{
|
||||
private int nextTimeline = 0;
|
||||
|
||||
public int NextTimeline() => nextTimeline++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The first turn number.
|
||||
/// </summary>
|
||||
@ -83,7 +73,7 @@ public class Season
|
||||
return new Season(
|
||||
past: null,
|
||||
turn: FIRST_TURN,
|
||||
timeline: factory.NextTimeline(),
|
||||
timeline: TimelineFactory.StringToInt(factory.NextTimeline()),
|
||||
factory: factory);
|
||||
}
|
||||
|
||||
@ -97,7 +87,7 @@ public class Season
|
||||
/// Create a season immediately after this one in a new timeline.
|
||||
/// </summary>
|
||||
public Season MakeFork()
|
||||
=> new Season(this, this.Turn + 1, this.Timelines.NextTimeline(), this.Timelines);
|
||||
=> new Season(this, this.Turn + 1, TimelineFactory.StringToInt(Timelines.NextTimeline()), this.Timelines);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first season in this season's timeline. The first season is the
|
||||
|
50
MultiversalDiplomacy/Model/TimelineFactory.cs
Normal file
50
MultiversalDiplomacy/Model/TimelineFactory.cs
Normal file
@ -0,0 +1,50 @@
|
||||
namespace MultiversalDiplomacy.Model;
|
||||
|
||||
/// <summary>
|
||||
/// A shared counter for handing out new timeline designations.
|
||||
/// </summary>
|
||||
internal class TimelineFactory
|
||||
{
|
||||
private static readonly char[] Letters = [
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z',
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string timeline identifier to its serial number.
|
||||
/// </summary>
|
||||
/// <param name="timeline">Timeline identifier.</param>
|
||||
/// <returns>Integer.</returns>
|
||||
public static int StringToInt(string timeline)
|
||||
{
|
||||
int result = Array.IndexOf(Letters, timeline[0]);
|
||||
for (int i = 1; i < timeline.Length; i++) {
|
||||
// The result is incremented by one because timeline designations are not a true base26 system.
|
||||
// The "ones digit" maps a-z 0-25, but the "tens digit" maps a to 1, so "10" (26) is "aa" and not "a0"
|
||||
result = (result + 1) * 26;
|
||||
result += Array.IndexOf(Letters, timeline[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a timeline serial number to its string identifier.
|
||||
/// </summary>
|
||||
/// <param name="designation">Integer.</param>
|
||||
/// <returns>Timeline identifier.</returns>
|
||||
public static string IntToString(int designation) {
|
||||
static int downshift(int i ) => (i - (i % 26)) / 26;
|
||||
IEnumerable<char> result = [Letters[designation % 26]];
|
||||
for (int remainder = downshift(designation); remainder > 0; remainder = downshift(remainder) - 1) {
|
||||
// We subtract 1 after downshifting for the same reason we add 1 above after upshifting.
|
||||
//
|
||||
result = result.Prepend(Letters[(remainder % 26 + 25) % 26]);
|
||||
}
|
||||
return new string(result.ToArray());
|
||||
}
|
||||
|
||||
private int nextTimeline = 0;
|
||||
|
||||
public string NextTimeline() => IntToString(nextTimeline++);
|
||||
}
|
@ -7,4 +7,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>MultiversalDiplomacyTests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
38
MultiversalDiplomacyTests/Model/TimelineFactoryTest.cs
Normal file
38
MultiversalDiplomacyTests/Model/TimelineFactoryTest.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using MultiversalDiplomacy.Model;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace MultiversalDiplomacyTests.Model;
|
||||
|
||||
public class TimelineFactoryTest
|
||||
{
|
||||
[TestCase(0, "a")]
|
||||
[TestCase(1, "b")]
|
||||
[TestCase(25, "z")]
|
||||
[TestCase(26, "aa")]
|
||||
[TestCase(27, "ab")]
|
||||
[TestCase(51, "az")]
|
||||
[TestCase(52, "ba")]
|
||||
[TestCase(53, "bb")]
|
||||
[TestCase(77, "bz")]
|
||||
[TestCase(78, "ca")]
|
||||
public void RoundTripTimelineDesignations(int number, string designation)
|
||||
{
|
||||
Assert.That(TimelineFactory.IntToString(number), Is.EqualTo(designation), "Incorrect string");
|
||||
Assert.That(TimelineFactory.StringToInt(designation), Is.EqualTo(number), "Incorrect number");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NoSharedFactoryState()
|
||||
{
|
||||
TimelineFactory one = new();
|
||||
TimelineFactory two = new();
|
||||
|
||||
Assert.That(one.NextTimeline(), Is.EqualTo("a"));
|
||||
Assert.That(one.NextTimeline(), Is.EqualTo("b"));
|
||||
Assert.That(one.NextTimeline(), Is.EqualTo("c"));
|
||||
|
||||
Assert.That(two.NextTimeline(), Is.EqualTo("a"));
|
||||
Assert.That(two.NextTimeline(), Is.EqualTo("b"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user