public void EnableGroundedCell()
        {
            var componentTrackingMatrix = new CorrectComponentTrackingMatrix(new Matrix("000|000|000", "010|000|000", "000|000|000").Voxels);

            componentTrackingMatrix[1, 0, 1] = true;
            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeFalse();
        }
        public void TrackComponents6()
        {
            var componentTrackingMatrix = new CorrectComponentTrackingMatrix(new Matrix("000|101|001", "110|101|000", "111|011|101").Voxels);

            componentTrackingMatrix[0, 1, 2] = true;
            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeFalse();
        }
        public void TrackComponents3()
        {
            var componentTrackingMatrix = new CorrectComponentTrackingMatrix(new Matrix("000|101|000", "000|000|000", "000|000|000").Voxels);

            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeTrue();
            componentTrackingMatrix[1, 1, 0] = true;
            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeTrue();
            componentTrackingMatrix[1, 0, 0] = true;
            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeFalse();
            componentTrackingMatrix[1, 0, 0] = false;
            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeTrue();
        }
        public IEnumerable <ICommand> Solve()
        {
            buildingMatrix = new CorrectComponentTrackingMatrix(new bool[N, N, N]);
            var(transformedTargetMatrix, stickPositions) = TransformMatrix(targetMatrix);
            var(cloneCommands, initialBots) =
                fast
                ? Clone2(new Grid(grid.CountX, 2, minX, minZ, maxX, maxZ))
                : Clone(2 * grid.CountX, new Grid(grid.CountX, 2, minX, minZ, maxX, maxZ));
            foreach (var command in cloneCommands)
            {
                yield return(command);
            }

            var botQueues = new List <Queue <ICommand> >();

            for (var i = 0; i < initialBots.Count; i++)
            {
                botQueues.Add(new Queue <ICommand>());
            }

            var botsToGenerateCommands = initialBots.ToList();
            var botCount = botsToGenerateCommands.Count;

            for (var y = 0; y <= maxY; y++)
            {
                for (var botId = 0; botId < botCount / 2; botId++)
                {
                    var nearId = botId;
                    var farId  = botId + botCount / 2;
                    foreach (var(nearCommand, farCommand) in FillLayer(transformedTargetMatrix, botsToGenerateCommands[nearId], botsToGenerateCommands[farId]))
                    {
                        var nearBeforeTransform = grid.GetCellId(botsToGenerateCommands[nearId]);
                        var farBeforeTransform  = grid.GetCellId(botsToGenerateCommands[farId]);
                        botQueues[nearId].Enqueue(nearCommand);
                        botQueues[farId].Enqueue(farCommand);
                        if (nearCommand is SMove sMove)
                        {
                            botsToGenerateCommands[nearId] += sMove.Shift;
                        }
                        if (nearCommand is LMove lMove)
                        {
                            botsToGenerateCommands[nearId] += lMove.firstShift.Shift + lMove.secondShift.Shift;
                        }
                        if (farCommand is SMove sMove1)
                        {
                            botsToGenerateCommands[farId] += sMove1.Shift;
                        }
                        if (farCommand is LMove lMove1)
                        {
                            botsToGenerateCommands[farId] += lMove1.firstShift.Shift + lMove1.secondShift.Shift;
                        }
                        if (!nearBeforeTransform.Equals(grid.GetCellId(botsToGenerateCommands[nearId])))
                        {
                            throw new Exception("Wrong zone");
                        }
                        if (!farBeforeTransform.Equals(grid.GetCellId(botsToGenerateCommands[farId])))
                        {
                            throw new Exception("Wrong zone");
                        }
                    }
                }
            }
            for (var botId = 0; botId < botCount / 2; botId++)
            {
                foreach (var command in RemoveSticks(stickPositions, botsToGenerateCommands[botId]))
                {
                    botQueues[botId].Enqueue(command);
                    if (command is SMove sMove)
                    {
                        botsToGenerateCommands[botId] += sMove.Shift;
                    }
                    if (command is LMove lMove)
                    {
                        botsToGenerateCommands[botId] += lMove.firstShift.Shift + lMove.secondShift.Shift;
                    }
                }
            }

            var  botsToEvaluate = initialBots.ToList();
            bool isHighEnergy   = false;
            bool firstHigh      = false;

            while (botQueues.Any(x => x.Count > 0))
            {
                var commands = new List <ICommand>();
                if (isHighEnergy && !firstHigh && !buildingMatrix.HasNonGroundedVoxels)
                {
                    commands     = new ICommand[] { new Flip() }.Concat(Enumerable.Repeat <ICommand>(new Wait(), botsToEvaluate.Count - 1)).ToList();
                    isHighEnergy = false;
                    foreach (var command in commands)
                    {
                        yield return(command);
                    }
                    continue;
                }
                bool[] shouldWait = new bool[botCount];
                firstHigh = false;

                for (var i = 0; i < botQueues.Count; i++)
                {
                    if (botQueues[i].Count == 0)
                    {
                        continue;
                    }
                    if (botQueues[i].Peek() is Fill fillCommand)
                    {
                        var fillPosition = botsToEvaluate[i] + fillCommand.Shift;
                        if (!CanFill(buildingMatrix.Voxels, fillPosition) && !isHighEnergy)
                        {
                            shouldWait[i] = true;
                            shouldWait[GetPartnerId(i)] = true;
                        }
                    }
                    else if (botQueues[i].Peek() is GFill gFillCommand)
                    {
                        var filledCells = new List <Vec>();
                        foreach (var cell in Cuboid.FromPoints(botsToEvaluate[i] + gFillCommand.NearShift, botsToEvaluate[i] + gFillCommand.NearShift + gFillCommand.FarShift).AllPoints())
                        {
                            if (!buildingMatrix[cell])
                            {
                                filledCells.Add(cell);
                            }
                            buildingMatrix[cell] = true;
                        }
                        if (buildingMatrix.HasNonGroundedVoxels && !isHighEnergy)
                        {
                            foreach (var filledCell in filledCells)
                            {
                                buildingMatrix[filledCell] = false;
                            }
                            shouldWait[i] = true;
                            shouldWait[GetPartnerId(i)] = true;
                        }
                    }
                    else if (botQueues[i].Peek() is Voidd voidCommand)
                    {
                        var voidPosition = botsToEvaluate[i] + voidCommand.Shift;

                        if (!buildingMatrix.CanVoidCell(voidPosition) && !isHighEnergy)
                        {
                            shouldWait[i] = true;
                            shouldWait[GetPartnerId(i)] = true;
                        }
                    }
                }

                for (var i = 0; i < botQueues.Count; i++)
                {
                    if (botQueues[i].Count == 0 || shouldWait[i])
                    {
                        commands.Add(new Wait());
                        continue;
                    }
                    if (botQueues[i].Peek() is Fill fillCommand)
                    {
                        var fillPosition = botsToEvaluate[i] + fillCommand.Shift;
                        buildingMatrix[fillPosition] = true;
                        commands.Add(botQueues[i].Dequeue());
                    }
                    else if (botQueues[i].Peek() is GFill gFillCommand)
                    {
                        foreach (var cell in Cuboid.FromPoints(botsToEvaluate[i] + gFillCommand.NearShift, botsToEvaluate[i] + gFillCommand.NearShift + gFillCommand.FarShift).AllPoints())
                        {
                            buildingMatrix[cell] = true;
                        }
                        commands.Add(botQueues[i].Dequeue());
                    }
                    else if (botQueues[i].Peek() is Voidd voidCommand)
                    {
                        var voidPosition = botsToEvaluate[i] + voidCommand.Shift;
                        buildingMatrix[voidPosition] = false;
                        commands.Add(botQueues[i].Dequeue());
                    }
                    else
                    {
                        commands.Add(botQueues[i].Dequeue());
                    }
                }
                if (commands.All(x => x is Wait))
                {
                    firstHigh   = isHighEnergy = true;
                    commands[0] = new Flip();
                }
                for (var i = 0; i < commands.Count; i++)
                {
                    if (commands[i] is SMove sMove)
                    {
                        botsToEvaluate[i] += sMove.Shift;
                    }
                    if (commands[i] is LMove lMove)
                    {
                        botsToEvaluate[i] += lMove.firstShift.Shift + lMove.secondShift.Shift;
                    }
                    yield return(commands[i]);
                }
            }
            foreach (var command in fast ? GoHome2(botsToEvaluate) : GoHome(botsToEvaluate))
            {
                yield return(command);
            }
        }
        public void HasNotGrounded(params string[] matrix)
        {
            var componentTrackingMatrix = new CorrectComponentTrackingMatrix(new Matrix(matrix).Voxels);

            componentTrackingMatrix.HasNonGroundedVoxels.Should().BeTrue();
        }