// initial (or after reset) puzzle shuffle
 // this method can also perform a "precomputed" shuffle using an argument string
 IEnumerator ShufflePuzzle(string shuffleString = "")
 {
     GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzleBusy, this, true);
     PuzzleButtonController.PuzzleButtonArgs buttonArgs = new PuzzleButtonController.PuzzleButtonArgs
     {
         id   = new Vector2Int(0, 0),
         fast = 0.5f
     };
     if (string.IsNullOrEmpty(shuffleString))
     {
         // random mode shuffle
         // do not allow the assembled state after the puzzle initialization
         puzzleComplete = true;
         int width  = descriptor.init.width;
         int height = descriptor.init.height;
         while (puzzleComplete)
         {
             int rotationsCount = (int)((Random.value + 0.7f) * width * height);
             for (int i = 0; i < rotationsCount; i++)
             {
                 buttonArgs.id.x = (int)(Random.value * (width - 1));
                 buttonArgs.id.y = (int)(Random.value * (height - 1));
                 // do not save puzzle status while shuffling
                 RotateButton(buttonArgs, false);
                 while (!buttonRotated)
                 {
                     yield return(null);
                 }
             }
         }
     }
     else
     {
         // forced mode shuffle
         string[] parts      = shuffleString.Split('.');
         int      partsCount = parts.Length;
         //Debug.Log("Initial shuffle string: " + partsCount.ToString() + " parts");
         for (int i = 0; i < partsCount; i += 2)
         {
             buttonArgs.id.x = int.Parse(parts[i]);
             buttonArgs.id.y = int.Parse(parts[i + 1]);
             // do not save puzzle status while shuffling
             RotateButton(buttonArgs, false);
             while (!buttonRotated)
             {
                 yield return(null);
             }
         }
     }
     // ok, now it's time to save
     SaveAll();
     GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzleHasShuffled, this);
     GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzleBusy, this, false);
     startVictoryScreen = true;
 }
 void OnPuzzleButtonPressed(object sender, InstantMessageArgs args)
 {
     if (!puzzleBusy)
     {
         GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzleBusy, this, true);
         Vector2Int buttonId = (Vector2Int)args.arg;
         PuzzleButtonController.PuzzleButtonArgs buttonArgs = new PuzzleButtonController.PuzzleButtonArgs
         {
             id   = buttonId,
             fast = 1
         };
         RotateButton(buttonArgs);
         StartCoroutine(WaitForButtonPress());
     }
 }
        IEnumerator PerformAutoStep()
        {
            // wait for a frame to ensure a clean steady puzzle state
            yield return(null);

            //Debug.Log("Starting autostep");
            Vector2Int lastGood, nextGood;

            CheckPuzzleStateComplete(false, out lastGood, out nextGood);
            TileStatus tileStatus = tileNeighbours[nextGood.x, nextGood.y];

            byte[] solution = AutoStepSolutions.GetSolution(
                descriptor.init.height,
                descriptor.init.width,
                tileStatus.id.y * descriptor.init.width + tileStatus.id.x,
                nextGood.y,
                nextGood.x,
                tileStatus.angle
                );
            if (solution != null)
            {
                //Debug.Log("Running autostep for " + nextGood.ToString() + " to " + lastGood.ToString());
                descriptor.state.AutocompleteUsed = true;
                PuzzleButtonController.PuzzleButtonArgs buttonArgs = new PuzzleButtonController.PuzzleButtonArgs
                {
                    id   = new Vector2Int(0, 0),
                    fast = 0.5f
                };
                for (int i = 0; i < solution.Length && !puzzleComplete; i++)
                {
                    buttonArgs.id.y = (solution[i] >> 4) & 0xf;
                    buttonArgs.id.x = solution[i] & 0xf;
                    //Debug.Log(">> Step " + i.ToString() + ": rotating button " + buttonArgs.id.ToString());
                    RotateButton(buttonArgs, false);
                    while (!buttonRotated)
                    {
                        yield return(null);
                    }
                }
                //Debug.Log("Saving state");
                SaveAll();
                // tight vibe sound
                autostepJingle.pitchFactor = autostepPitchRange.Random;
                GlobalManager.MAudio.PlaySFX(autostepJingle);
                //Debug.Log("Notifying of autostep");
            }
            GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzleAutostepUsed, this);
        }
        void RotateButton(PuzzleButtonController.PuzzleButtonArgs buttonArgs, bool saveAfterRotation = true)
        {
            // stop flashing every tile
            List <TileFlashArgs> flashList = new List <TileFlashArgs>();

            for (int y = 0; y < descriptor.init.height; y++)
            {
                for (int x = 0; x < descriptor.init.width; x++)
                {
                    TileFlashArgs flashArgs = new TileFlashArgs
                    {
                        id   = new Vector2Int(x, y),
                        type = FlashType.None
                    };
                    flashList.Add(flashArgs);
                }
            }
            GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzleFlashTile, this, flashList);

            // prepare an array of neighbour tiles
            Vector2Int buttonId = buttonArgs.id;

            Vector2Int[] tileIds = new Vector2Int[4];
            int          i       = 0;

            for (int y = 0; y < 2; y++)
            {
                for (int x = 0; x < 2; x++, i++)
                {
                    tileIds[i] = new Vector2Int
                    {
                        x = tileNeighbours[buttonId.x + x, buttonId.y + y].id.x,
                        y = tileNeighbours[buttonId.x + x, buttonId.y + y].id.y
                    };
                }
            }

            //Debug.Log("Attaching tiles to button " + buttonId.ToString());
            builder.AttachTilesToButton(buttonId, tileIds);
            //Debug.Log("Calculating rotation");
            RotateTilesWith(buttonId, saveAfterRotation);
            buttonRotated = false;
            //Debug.Log("Performing rotation");
            builder.RotateButtonWithTiles(buttonArgs);
        }
 public void RotateButtonWithTiles(PuzzleButtonController.PuzzleButtonArgs buttonArgs)
 {
     //Debug.Log("Commanding a button to have a rotation");
     GlobalManager.MInstantMessage.DeliverMessage(InstantMessageType.PuzzlePressButton, this, buttonArgs);
 }