Example #1
0
        public IEnumerable <ICommand> Solve()
        {
            for (int i = 0; i < N - 1; i++)
            {
                for (int k = 0; k < i; k++)
                {
                    yield return(new Wait());
                }
                yield return(new Fission(new NearDifference(new Vec(0, 0, 1)), N - i - 2));
            }
            pos     = new Vec[N];
            regions = new Region[N];
            for (int i = 0; i < N; i++)
            {
                pos[i]     = new Vec(0, 0, i);
                regions[i] = Region.ForShift(new Vec(i % Nx * BlockSizeX, 0, i / Nx * BlockSizeZ), new Vec(BlockSizeX - 1, R - 1, BlockSizeZ - 1));
            }

            for (int i = N - 1; i >= 0; i--)
            {
                var volatiles = pos.ToHashSet();
                var target    = regions[i].Start;
                var commands  = new PathFinder(state, pos[i], target, volatiles, null).TryFindPath();
                if (commands == null)
                {
                    throw new InvalidOperationException($"Failed to find path from {pos[i]} to {target}");
                }
                foreach (var command in commands)
                {
                    for (int k = 0; k < i; k++)
                    {
                        yield return(new Wait());
                    }
                    yield return(command);

                    for (int k = i + 1; k < N; k++)
                    {
                        yield return(new Wait());
                    }
                }
                pos[i] = target;
            }

            var enumerators = new IEnumerator <ICommand> [N];

            while (true)
            {
                for (int bot = 0; bot < N; bot++)
                {
                    if (enumerators[bot] == null)
                    {
                        enumerators[bot] = SolveSingle(bot).GetEnumerator();
                    }
                }

                var tickCommands = new ICommand[N];
                for (int bot = 0; bot < N; bot++)
                {
                    if (enumerators[bot].MoveNext())
                    {
                        tickCommands[bot] = enumerators[bot].Current;
                    }
                    else
                    {
                        enumerators[bot].Dispose();
                        enumerators[bot] = null;
                    }
                }

                if (tickCommands.All(c => c == null))
                {
                    break;
                }

                foreach (var tickCommand in tickCommands)
                {
                    yield return(tickCommand ?? new Wait());
                }
            }

            for (int bot = N - 1; bot >= 1; bot--)
            {
                var             parentPos = pos[bot - 1];
                List <ICommand> commands  = null;
                foreach (var near in parentPos.GetNears().OrderBy(n => n.MDistTo(pos[bot])))
                {
                    if (near.IsInCuboid(R) && !state.Get(near))
                    {
                        var pathFinder = new PathFinder(state, pos[bot], near, null, null);
                        commands = pathFinder.TryFindPath();
                        if (commands != null)
                        {
                            pos[bot] = near;
                            break;
                        }
                    }
                }
                if (commands == null)
                {
                    throw new InvalidOperationException($"Couldn't find path for fusion from {pos[bot]} to near of {parentPos}");
                }
                foreach (var command in commands)
                {
                    for (int k = 0; k < bot; k++)
                    {
                        yield return(new Wait());
                    }
                    yield return(command);
                }
                for (int k = 0; k < bot - 1; k++)
                {
                    yield return(new Wait());
                }
                yield return(new FusionP(new NearDifference(pos[bot] - parentPos)));

                yield return(new FusionS(new NearDifference(parentPos - pos[bot])));
            }

            var cmds = new List <ICommand>();

            Move(0, Vec.Zero, cmds);
            foreach (var command in cmds)
            {
                yield return(command);
            }
            yield return(new Halt());
        }