public IEnumerable <ICommand> MakeTrace(bool noHalt = false) { var idleSteps = 0; while (true) { var idle = true; botPositions.Clear(); interferedCells.Clear(); foreach (var bot in bots) { botPositions.Add(bot.Coord, bot); interferedCells.Add(bot.Coord); } var newBots = new List <Bot>(); int numDeadBots = 0; var changedCoords = new List <TCoord>(); int numPlannedFusions = bots.Count(b => b.FusionSTarget != null); idleBots = 0; foreach (var b in bots) { b.Acted = false; b.MustDie = false; b.ActedFusionPTarget = null; b.ActedFusionSTarget = null; --b.FissionTimeout; if (b.IdleTooLong) { ++idleBots; } } if (Trace) { Console.WriteLine($"-----"); } if ((availablePositions.Count == 0) && (bots.Count == 1) && bots[0].Coord.IsAtStart()) { if (!noHalt) { yield return(new Halt()); } yield break; } if (availablePositions.Count != 0) { currentDepth = availablePositions.Select(Depth).Max(); } availableAtThisLevel = availablePositions.Count(p => Depth(p) == currentDepth); foreach (var bot in bots) { if ((bot.Target == null) || !CanMove(bot) || (bot.FillTarget != null && Depth(bot.FillTarget.Value) != currentDepth)) { if (Trace) { //Console.WriteLine($"!{bot.IdleTime}"); } ChooseNewTarget(bot, newBots, ref numPlannedFusions); if (bot.Target != null && !CanMove(bot)) { throw new Exception("Something bad happened"); } } if ((bot.Target != null) && CanMove(bot)) { var pc = bot.Coord; var cmd = MoveBot(bot, newBots, ref numDeadBots, changedCoords); if (cmd is Wait) { ++bot.IdleTime; } else { idle = false; bot.IdleTime = 0; } yield return(cmd); if (Trace) { Console.WriteLine($"{bot.Id} move {pc} -> {bot.Coord} ({!bot.MustDie}, {numDeadBots})"); } } else { if (Trace) { Console.WriteLine($"{bot.Id} waits at {bot.Coord} ({model[bot.Coord]}/{state.M(bot.Coord)}/{Depth(bot.Coord)}"); } ++bot.IdleTime; yield return(new Wait()); } bot.Acted = true; } if (idle) { // we are stuck. Just produce some garbage trace if (++idleSteps >= 3) { Console.WriteLine($"STUCK {numFilled}/{model.NumFilled}"); if (Trace) { foreach (var b in bots) { ChooseNewTarget(b, newBots, ref numPlannedFusions); Console.WriteLine($"{b.Id}: {b.Coord}, T: {b.Target}"); } Console.WriteLine($"Cur depth: {currentDepth}"); foreach (var c in availablePositions.Where(c => Depth(c) == currentDepth)) { Console.WriteLine($" A: {c}"); } } yield break; throw new Exception("STUCK"); } } else { idleSteps = 0; } if (newBots.Count > 0) { // Console.WriteLine("HEY"); bots.AddRange(newBots); bots = bots.OrderBy(bot => bot.Id).ToList(); } if (numDeadBots != 0) { bots = bots.Where(bot => !bot.MustDie).ToList(); foreach (var b in bots) { var seeds = string.Join(",", b.Seeds); if (Trace) { Console.WriteLine($"{b.Id}: {b.Coord}, S: {seeds}"); } } } foreach (var c in changedCoords) { if (mode == Mode.Assembly) { state.Matrix[c.X, c.Y, c.Z] = 1; foreach (var n in c.ManhattenNeighbours()) { if (n.IsValid(model.R) && model[n] != 0 && !addedPositions.Contains(n)) { addedPositions.Add(n); availablePositions.Add(n); } } } else { if (Trace) { foreach (var cc in availablePositions) { if (state.M(cc) == 0) { throw new Exception("WTF"); } } } state.Matrix[c.X, c.Y, c.Z] = 0; foreach (var n in c.ManhattenNeighbours()) { if (n.IsValid(model.R) && state.M(n) != 0 && !addedPositions.Contains(n)) { addedPositions.Add(n); availablePositions.Add(n); } } if (Trace) { foreach (var cc in availablePositions) { if (state.M(cc) == 0) { throw new Exception("WTF"); } } } } } if (Trace) { if (availablePositions.Count != 0) { currentDepth = availablePositions.Select(Depth).Max(); } Console.WriteLine( $" {numFilled} / {model.NumFilled}. {availablePositions.Count(p => Depth(p) == currentDepth)} for {bots.Count} bots"); } if (changedCoords.Count != 0) { numFilled += changedCoords.Count; /* * foreach (var c in availablePositions.Where(c => Depth(c) == currentDepth)) * { * Console.WriteLine($" A: {c}"); * } */ } } }
private bool IsFree(TCoord coord, int maxDepth) => (state.M(coord) == 0) && // depth[coord.X, coord.Y, coord.Z] < maxDepth && !interferedCells.Contains(coord);