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>
|
/// </summary>
|
||||||
public class Season
|
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>
|
/// <summary>
|
||||||
/// The first turn number.
|
/// The first turn number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -83,7 +73,7 @@ public class Season
|
||||||
return new Season(
|
return new Season(
|
||||||
past: null,
|
past: null,
|
||||||
turn: FIRST_TURN,
|
turn: FIRST_TURN,
|
||||||
timeline: factory.NextTimeline(),
|
timeline: TimelineFactory.StringToInt(factory.NextTimeline()),
|
||||||
factory: factory);
|
factory: factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +87,7 @@ public class Season
|
||||||
/// Create a season immediately after this one in a new timeline.
|
/// Create a season immediately after this one in a new timeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Season MakeFork()
|
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>
|
/// <summary>
|
||||||
/// Returns the first season in this season's timeline. The first season is the
|
/// Returns the first season in this season's timeline. The first season is the
|
||||||
|
|
|
@ -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>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
|
<_Parameter1>MultiversalDiplomacyTests</_Parameter1>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -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