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));
}
}
}
}