internal void Validate(ErrorLogger errors, int lineNumber, string line) { if (UWP == "???????-?") { return; } Action <string> Error = (string message) => { errors.Error(message, lineNumber, line); }; Action <bool, string> ErrorIf = (bool test, string message) => { if (test) { Error(message); } }; Action <bool, string> ErrorUnless = (bool test, string message) => { if (!test) { Error(message); } }; Func <int, string, bool> Check = (int value, string hex) => { for (int i = 0; i < hex.Length; ++i) { if (value == SecondSurvey.FromHex(hex[i])) { return(true); } } return(false); }; Func <string, bool, bool> CC = (string code, bool calc) => { if (calc) { ErrorUnless(HasCode(code), $"Missing code: {code}"); } else { ErrorUnless(!HasCode(code), $"Extraneous code: {code}"); } return(calc); }; #if VALIDATE_UWP // UWP ErrorIf(Atmosphere > 15, $"UWP: Atm>F: {Atmosphere}"); ErrorIf(Hydrographics > 10, $"UWP: Hyd>A: {Hydrographics}"); ErrorIf(PopulationExponent > 15, $"UWP: Pop>F: {PopulationExponent}"); ErrorUnless(Util.InRange(Government, PopulationExponent - 5, Math.Max(15, PopulationExponent + 5)), $"UWP: Gov={Government} out of range (Pop={PopulationExponent} + Flux)"); ErrorUnless(Util.InRange(Law, Government - 5, Math.Max(18, Government + 5)), $"UWP: Law={Law} out of range (Gov={Government} + Flux)"); int tlmod = (Starport == 'A' ? 6 : 0) + (Starport == 'B' ? 4 : 0) + (Starport == 'C' ? 2 : 0) + (Starport == 'X' ? -4 : 0) + (Size == 0 || Size == 1 ? 2 : 0) + (Size == 2 || Size == 3 || Size == 4 ? 1 : 0) + (Atmosphere <= 3 ? 1 : 0) + (Atmosphere >= 10 ? 1 : 0) + (Hydrographics == 9 ? 1 : 0) + (Hydrographics == 10 ? 2 : 0) + (Util.InRange(PopulationExponent, 1, 5) ? 1 : 0) + (PopulationExponent == 9 ? 2 : 0) + (PopulationExponent >= 10 ? 4 : 0) + (Government == 0 || Government == 5 ? 1 : 0) + (Government == 13 ? -2 : 0); ErrorUnless(Util.InRange(TechLevel, tlmod + 1, tlmod + 6), $"UWP: TL={TechLevel} out of range (mods={tlmod} + 1D)"); #endif // Planetary bool As = CC("As", Check(Size, "0") /*&& Check(Atmosphere, "0") && Check(Hydrographics, "0")*/); bool De = CC("De", Check(Atmosphere, "23456789") && Check(Hydrographics, "0")); bool Fl = CC("Fl", Check(Atmosphere, "ABC") && Check(Hydrographics, "123456789A")); bool Ga = CC("Ga", Check(Size, "678") && Check(Atmosphere, "568") && Check(Hydrographics, "567")); bool He = CC("He", Check(Size, "3456789A" /* + "BC" */) && Check(Atmosphere, "2479ABC") && Check(Hydrographics, "012")); // TODO: Add BC to T5SS spreadsheet calcs bool Ic = CC("Ic", Check(Atmosphere, "01") && Check(Hydrographics, "123456789A")); bool Oc = CC("Oc", Check(Size, "ABC") && Check(Atmosphere, "3456789") && Check(Hydrographics, "A")); bool Va = CC("Va", Check(Atmosphere, "0")); bool Wa = CC("Wa", Check(Size, "3456789") && Check(Atmosphere, "3456789") && Check(Hydrographics, "A")); // Population bool Di = CC("Di", PopulationExponent == 0 /*&& Government == 0 && Law == 0*/ && TechLevel > 0); bool Ba = CC("Ba", PopulationExponent == 0 /*&& Government == 0 && Law == 0*/ && TechLevel == 0); bool Lo = CC("Lo", Check(PopulationExponent, "123")); bool Ni = CC("Ni", Check(PopulationExponent, "456")); bool Ph = CC("Ph", Check(PopulationExponent, "8")); bool Hi = CC("Hi", Check(PopulationExponent, "9ABCDEF")); // Economic bool Pa = CC("Pa", Check(Atmosphere, "456789") && Check(Hydrographics, "45678") && Check(PopulationExponent, "48")); bool Ag = CC("Ag", Check(Atmosphere, "456789") && Check(Hydrographics, "45678") && Check(PopulationExponent, "567")); bool Na = CC("Na", Check(Atmosphere, "0123") && Check(Hydrographics, "0123") && Check(PopulationExponent, "6789ABCDEF")); bool Pi = CC("Pi", Check(Atmosphere, "012479") && Check(PopulationExponent, "78")); bool In = CC("In", Check(Atmosphere, "012479ABC") && Check(PopulationExponent, "9ABCDEF")); bool Po = CC("Po", Check(Atmosphere, "2345") && Check(Hydrographics, "0123")); bool Pr = CC("Pr", Check(Atmosphere, "68") && Check(PopulationExponent, "59")); bool Ri = CC("Ri", Check(Atmosphere, "68") && Check(PopulationExponent, "678")); // {Ix} int imp = 0; { string ix = Importance.Replace('{', ' ').Replace('}', ' ').Trim(); if ("AB".Contains(Starport)) { ++imp; } if ("DEX".Contains(Starport)) { --imp; } if (TechLevel >= 10) { ++imp; } //if (TechLevel >= 16) ++imp; // TODO: Add to T5SS spreadsheet calcs if (TechLevel <= 8) { --imp; } if (PopulationExponent <= 6) { --imp; } if (PopulationExponent >= 9) { ++imp; } if (Ag) { ++imp; } if (Ri) { ++imp; } if (In) { ++imp; } if (Bases == "NS" || Bases == "NW" || Bases == "W" || Bases == "X" || Bases == "D" || Bases == "RT" || Bases == "CK" || Bases == "KM") { ++imp; } ErrorUnless(Int32.Parse(ix) == imp, $"{{Ix}}={Importance} does not match calculated Importance={imp}"); } // (Ex) { string ex = Economic.Replace('(', ' ').Replace(')', ' ').Trim(); int resources = SecondSurvey.FromHex(ex[0]); int labor = SecondSurvey.FromHex(ex[1]); int infrastructure = SecondSurvey.FromHex(ex[2]); int efficiency = Int32.Parse(ex.Substring(3)); if (TechLevel < 8) { ErrorUnless(Util.InRange(resources, 2, 12), $"(Ex) Resources={resources} out of range for TL<8={TechLevel} (2D)"); } else { ErrorUnless(Util.InRange(resources, 2 + GasGiants + Belts, 12 + GasGiants + Belts), $"(Ex) Resources={resources} out of range for TL8+={TechLevel} (2D + GG={GasGiants} + Belts={Belts})"); } ErrorUnless(labor == Math.Max(0, PopulationExponent - 1), $"(Ex) Labor={labor} does not match Pop={PopulationExponent} - 1"); if (Ba) { ErrorUnless(infrastructure == 0, $"(Ex) Infrastructure={infrastructure} should be 0 if Ba"); } else if (Lo) { ErrorUnless(infrastructure == 1, $"(Ex) Infrastructure={infrastructure} should be 1 if Lo"); } else if (Ni) { ErrorUnless(Util.InRange(infrastructure, Math.Max(0, imp + 1), Math.Max(0, imp + 6)), $"(Ex) Infrastructure={infrastructure} out of range for Ni (Imp={imp} + 1D)"); } else { ErrorUnless(Util.InRange(infrastructure, Math.Max(0, imp + 2), Math.Max(0, imp + 12)), $"(Ex) Infrastructure={infrastructure} out of range (Imp={imp} + 2D)"); } ErrorUnless(Util.InRange(efficiency, -5, 5), $"(Ex) Efficiency={efficiency} out of range (Flux)"); } // [Cx] { string cx = Cultural.Replace('[', ' ').Replace(']', ' ').Trim(); int homogeneity = SecondSurvey.FromHex(cx[0]); int acceptance = SecondSurvey.FromHex(cx[1]); int strangeness = SecondSurvey.FromHex(cx[2]); int symbols = SecondSurvey.FromHex(cx[3]); if (PopulationExponent == 0) { if (homogeneity != 0) { Error($"[Cx] Homogeneity={homogeneity} - expected 0 for Pop 0"); } if (acceptance != 0) { Error($"[Cx] Acceptance={acceptance} - expected 0 for Pop 0"); } if (strangeness != 0) { Error($"[Cx] Strangeness={strangeness} - expected 0 for Pop 0"); } if (symbols != 0) { Error($"[Cx] Symbols={symbols} - expected 0 for Pop 0"); } } else { ErrorUnless(Util.InRange(homogeneity, Math.Max(1, PopulationExponent - 5), Math.Max(1, PopulationExponent + 5)), $"[Cx] Homogeneity={homogeneity} out of range (Pop={PopulationExponent} + Flux)"); ErrorUnless(acceptance == Math.Max(1, PopulationExponent + imp), $"[Cx] Acceptance={acceptance} not equal Pop={PopulationExponent} + Imp={imp}"); ErrorUnless(Util.InRange(strangeness, Math.Max(1, 5 - 5), Math.Max(1, 5 + 5)), $"[Cx] Strangeness={strangeness} out of range (Flux + 5)"); ErrorUnless(Util.InRange(symbols, Math.Max(1, TechLevel - 5), Math.Max(1, TechLevel + 5)), $"[Cx] Symbols={symbols} out of range (TL={TechLevel} + Flux)"); } } // Ownership if (Government == 6 && !(HasCodePrefix("O:") || HasCodePrefix("Mr") || HasCode("Re") || HasCode("Px"))) { errors.Warning("Gov 6 missing O:/Mr/Re/Px", lineNumber, line); } }
public WorldCollection() { #if DEBUG errors = new ErrorLogger(); #endif }