namespace MultiversalDiplomacy.Model; /// /// A shared counter for handing out new timeline designations. /// public 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', ]; /// /// Convert a string timeline identifier to its serial number. /// /// Timeline identifier. /// Integer. 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; } /// /// Convert a timeline serial number to its string identifier. /// /// Integer. /// Timeline identifier. public static string IntToString(int designation) { static int downshift(int i ) => (i - (i % 26)) / 26; IEnumerable 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++); }