using System; using System.Globalization; using System.IO; using System.Text; namespace Luneraria.Core.Tests { /// /// Step-by-step trace of one combat round of a bot match, for comparing two runtimes /// (docs/port/U1.5-UNITY.md): per step and unit the discrete state (alive, target, hits, /// zone) and the raw bits of position and hit points. Two traces are diffed outside /// (tools/port/trace_diff.py) to find the first step where a decision differs. /// public static class DivergenceTrace { /// Plays rounds 1..round of a bot match; writes the trace of the last round. public static void Write(string path, int seed, string[] bunds, string profile, int round) { var match = new LuneMatch(); var options = new MatchOptions { Seed = seed, HumanSlot = -1 }; if (bunds != null) options.Bunds = new System.Collections.Generic.List(bunds); match.Setup(options); using (var writer = new StreamWriter(path, false, new UTF8Encoding(false))) { while (match.Phase != Phase.Over && match.RoundNumber <= round) { for (int slot = 0; slot < 6; slot++) LuneBot.Plan(match, slot, profile); int fought = match.RoundNumber; bool traced = fought == round; match.BeginCombat(); if (traced) { Dump(writer, match.Combat); while (!match.Combat.Finished) { match.StepCombat(); Dump(writer, match.Combat); } } match.FinishCombat(); writer.WriteLine("settled round {0} combat_time {1} phase {2}", fought, match.LastSettlement.CombatTime.ToString("R", CultureInfo.InvariantCulture), match.Phase); } } } static void Dump(StreamWriter writer, LuneCombat combat) { var line = new StringBuilder(); line.Append("step ").Append(combat.Steps).Append(" t ").Append(combat.Elapsed.ToString("R", CultureInfo.InvariantCulture)); line.Append(" finished ").Append(combat.Finished ? 1 : 0).Append(" reason ").Append(combat.EndReason); writer.WriteLine(line.ToString()); foreach (LuneUnit unit in combat.Units) { if (!unit.Alive && unit.DeathTime < combat.Elapsed - 0.001) continue; writer.WriteLine(" u {0} {1} t{2} {3} {4} alive {5} target {6} hits {7} | hp {8:X16} pos {9:X8} {10:X8}", unit.Id, unit.Kind, unit.Team, unit.Lane, unit.Zone, unit.Alive ? 1 : 0, unit.Target != null ? unit.Target.Id : -1, unit.HitCount, BitConverter.DoubleToInt64Bits(unit.Hp), BitConverter.ToInt32(BitConverter.GetBytes(unit.Position.X), 0), BitConverter.ToInt32(BitConverter.GetBytes(unit.Position.Y), 0)); } } } }