private void SetStage(int stage)
    {
        _stage       = stage;
        _subprogress = 0;
        for (int i = 0; i < 16; i++)
        {
            if (_colors[i] != SquareColor.White)
            {
                Scaffold.SetButtonBlack(i);
            }
        }

        if (stage == 5)
        {
            ModulePassed();
            return;
        }
        Log("On to stage {0}.", _stage);

        // Put 2–3 of the active color in that many random squares
        var availableSquares = Enumerable.Range(0, 16).Where(ix => stage == 1 || _colors[ix] != SquareColor.White).ToList().Shuffle();
        var take             = Math.Min(stage == 1 ? 3 : Rnd.Range(2, 4), availableSquares.Count);

        for (int i = 0; i < take; i++)
        {
            _colors[availableSquares[i]] = _rememberedColors[stage - 1];
        }

        // Fill the rest of the grid with the other colors
        for (int i = take; i < availableSquares.Count; i++)
        {
            var cl = Rnd.Range(1, 5);
            _colors[availableSquares[i]] = (SquareColor)(cl >= (int)_rememberedColors[stage - 1] ? cl + 1 : cl);
        }

        var relevantSquares = availableSquares.Take(take).OrderBy(sq => _ordersByStage[stage - 1][sq]).ToArray();

        Log("Stage {0}: {1} squares in the correct order are {2}.", stage, _rememberedColors[stage - 1], relevantSquares.Select(sq => coord(sq)).Join(", "));

        // Process the active squares in the correct order for this stage to compute the intended solution
        _expectedPresses = new List <int>();
        foreach (var activeSquare in relevantSquares)
        {
            if (_expectedPresses.Contains(activeSquare))    // square already became white in this stage
            {
                Log("— {0} has already become white. Skip it.", coord(activeSquare));
                continue;
            }
            var solutionSquare = activeSquare;
            do
            {
                solutionSquare = process(solutionSquare, _instructions[_rememberedPositions[stage - 1]]);
            }while (_colors[solutionSquare] == SquareColor.White || _expectedPresses.Contains(solutionSquare));
            Log("— {0} / {1} translates to {2}", coord(activeSquare), _instructions[_rememberedPositions[stage - 1]], coord(solutionSquare));
            _expectedPresses.Add(solutionSquare);
        }

        Scaffold.StartSquareColorsCoroutine(_colors, delay: true);
    }
    protected override void ButtonPressed(int index)
    {
        if (index != _modulePosition)
        {
            Log("{0} was pressed when {1} was expected. Strike and reset.", convertCoord(index, 4), convertCoord(_modulePosition, 4));
            Strike();
            SetInitialState();
        }
        else if (NextSquare(_modulePosition) == null)
        {
            ModulePassed();
        }
        else
        {
            Log("{0} pressed correctly.", convertCoord(index, 4));

            // We know this isn’t null because of the above if
            _modulePosition = NextSquare(_modulePosition).Value;

            // Make everything white _including_ the square that was pressed
            var indexes = _updateColors.Select(i => (int?)i).ToList();
            indexes.Add(index);
            foreach (var ix in indexes)
            {
                _colors[ix.Value] = SquareColor.White;
            }
            indexes.Add(null);

            var indexes2 = new List <int?>();
            for (int?i = _modulePosition; i != null; i = NextSquare(i.Value))
            {
                Scaffold.SetButtonBlack(i.Value);
                _colors[i.Value] = _usefulColors[Rnd.Range(0, _usefulColors.Length)];
                indexes2.Add(i.Value);
            }

            _updateColors.Clear();
            ProcessCurrentSquare();

            if (!_isSolved)
            {
                indexes2.Shuffle();
                indexes.AddRange(indexes2);
                Scaffold.StartSquareColorsCoroutine(_colors, indexes.ToArray());
            }
        }
    }
    protected override void ButtonPressed(int index)
    {
        if (_activeCoroutine != null)
        {
            StopCoroutine(_activeCoroutine);
        }

        if (_lastPress != -1)
        {
            Scaffold.SetButtonColor(_lastPress, _colors[_lastPress]);
        }

        if (_lastPress == -1 && _allowedPresses.Contains(index))
        {
            PlaySound(index);
            _lastPress        = index;
            _startingPosition = index;
            _allowedPresses   = CalculateNewAllowedPresses(index);

            Log("Button #{0} pressed successfully. Current color is now {1}. Next color is {2}.", index, _currentColor, _nextColor);
            _activeCoroutine = StartCoroutine(BlinkLastSquare());
        }
        else if (!_allowedPresses.Contains(index))
        {
            Log("Button #{0} ({1}) was incorrect at this time.", index, _colors[index]);
            Strike();
            SetInitialState();
        }
        else
        {
            PlaySound(index);
            _lastPress = index;

            _updateIndices = new HashSet <int>();
            LogDebug("Calling SpreadColor({0}, {1}, {2})", _currentColor, _colors[index], _startingPosition);
            SpreadColor(_currentColor, _colors[index], _startingPosition);
            if (_updateIndices.SetEquals(_lastArea))
            {
                _pressesWithoutChange++;
            }
            else
            {
                _lastArea             = _updateIndices;
                _pressesWithoutChange = 0;
            }

            _currentColor = _colors[index];

            if (_pressesWithoutChange >= 3)
            {
                var currentColor = _colors[index];
                while (currentColor == _colors[index])
                {
                    _colors[index] = _colorCandidates[Rnd.Range(0, _colorCandidates.Length)];
                }
                _pressesWithoutChange = 0;
                Scaffold.SetButtonBlack(index);
                Scaffold.Audio.PlaySoundAtTransform("colorreset", Scaffold.Buttons[index].transform);
            }

            if (_colors.All(c => c == _colors[0]))
            {
                Log("Module passed.");
                _allowedPresses  = null;
                _activeCoroutine = StartCoroutine(SetSquareColors(delay: false, solve: true));
            }
            else
            {
                _allowedPresses = CalculateNewAllowedPresses(index);

                Log("Button #{0} pressed successfully. Current color is now {1}. Next color is {2}.", index, _currentColor, _nextColor);
                _activeCoroutine = StartCoroutine(SetSquareColors(delay: false));
            }
        }
    }
Пример #4
0
    private void SetStage(bool isStart)
    {
        if (isStart)
        {
            for (int i = 0; i < 16; i++)
            {
                _colors[i] = SquareColor.White;
                Scaffold.SetButtonBlack(i);
            }
        }
        else
        {
            var sq = 0;
            for (int i = 0; i < 16; i++)
            {
                switch (_colors[i])
                {
                case SquareColor.Black:
                    break;

                case SquareColor.Red:
                case SquareColor.Green:
                case SquareColor.Blue:
                case SquareColor.Yellow:
                case SquareColor.Magenta:
                    Scaffold.SetButtonBlack(i);
                    sq++;
                    break;

                case SquareColor.White:
                    _colors[i] = SquareColor.Black;
                    break;
                }
            }
            if (sq <= 3)
            {
                ModulePassed();
                return;
            }
        }

        // Check all color combinations and find all valid pattern placements
        var order             = new[] { SquareColor.Red, SquareColor.Green, SquareColor.Blue, SquareColor.Yellow, SquareColor.Magenta };
        var validCombinations = Enumerable.Range(0, 5).SelectMany(first => Enumerable.Range(0, 5).Select(second =>
        {
            if (first == second)
            {
                return(null);
            }
            var pattern    = _table[second][first];
            var w          = pattern.GetLength(0);
            var h          = pattern.GetLength(1);
            var placements = new List <List <int> >();
            for (int i = 0; i < 16; i++)
            {
                if (i % 4 + w > 4 || i / 4 + h > 4)
                {
                    continue;
                }
                var placement = new List <int>();
                for (int y = 0; y < h; y++)
                {
                    for (int x = 0; x < w; x++)
                    {
                        if (pattern[x, y])
                        {
                            var ix = i % 4 + x + 4 * (i / 4 + y);
                            if (_colors[ix] == SquareColor.Black)
                            {
                                goto nope;
                            }
                            placement.Add(ix);
                        }
                    }
                }
                placements.Add(placement);
                nope:;
            }
            return(placements.Count == 0 ? null : new { First = order[first], Second = order[second], Placements = placements });
        })).Where(inf => inf != null).ToArray();

        if (validCombinations.Length == 0)
        {
            ModulePassed();
            return;
        }

        // Fill the still-lit squares with “codes” (numbers 0–5 that we will later map to actual colors)
        // in such a way that there’s a two-way tie for fewest number of occurrences
        int[] colorCodes = new int[16];
tryAgain:
        var counts = new int[5];

        for (int i = 0; i < 16; i++)
        {
            if (_colors[i] != SquareColor.Black)
            {
                var col = Rnd.Range(0, 5);
                colorCodes[i] = col;
                counts[col]++;
            }
            else
            {
                colorCodes[i] = -1;
            }
        }
        var minCount      = counts.Where(c => c > 0).Min();
        var minCountCodes = Enumerable.Range(0, 5).Where(code => counts[code] == minCount).OrderBy(c => Array.IndexOf(colorCodes, c)).ToArray();

        if (minCountCodes.Length != 2)
        {
            goto tryAgain;
        }

        // Pick a color combination at random
        var combination = validCombinations[Rnd.Range(0, validCombinations.Length)];

        // Create the map from color code to actual color in such a way that the chosen colors are in the correct place
        var allColors = new List <SquareColor> {
            SquareColor.Blue, SquareColor.Green, SquareColor.Magenta, SquareColor.Red, SquareColor.Yellow
        };

        allColors.Remove(combination.First);
        allColors.Remove(combination.Second);
        if (minCountCodes[0] > minCountCodes[1])
        {
            allColors.Insert(minCountCodes[1], combination.Second);
            allColors.Insert(minCountCodes[0], combination.First);
        }
        else
        {
            allColors.Insert(minCountCodes[0], combination.First);
            allColors.Insert(minCountCodes[1], combination.Second);
        }

        // Assign the colors
        for (int i = 0; i < 16; i++)
        {
            if (_colors[i] != SquareColor.Black)
            {
                _colors[i] = allColors[colorCodes[i]];
            }
        }

        if (isStart)
        {
            _firstStageColor1 = combination.First;
            _firstStageColor2 = combination.Second;
        }

        Log("{0} stage color pair is {1}/{2}", isStart ? "First" : "Next", combination.First, combination.Second);
        _permissiblePatterns = combination.Placements;
        _squaresPressedThisStage.Clear();
        Scaffold.StartSquareColorsCoroutine(_colors, delay: true);
    }
    protected override void ButtonPressed(int index)
    {
        if (_expectedPresses == null)
        {
            return;
        }

        if (!_allowedPresses.Contains(index))
        {
            Log(@"Button #{0} ({1}) was incorrect at this time.", index, _colors[index]);
            Strike();
            SetInitialState();
        }
        else
        {
            PlaySound(index);
            _expectedPresses.Remove(index);
            _colors[index] = SquareColor.White;
            Scaffold.SetButtonColor(index, SquareColor.White);
            if (_expectedPresses.Count == 0)
            {
                var whiteCount = _colors.Count(c => c == SquareColor.White);
                if (whiteCount == 16)
                {
                    _expectedPresses = null;
                    _allowedPresses  = null;
                    ModulePassed();
                }
                else
                {
                    _allowedPresses.Clear();

                    var nonWhite = Enumerable.Range(0, 16).Where(i => _colors[i] != SquareColor.White).ToArray();
                    foreach (var i in nonWhite)
                    {
                        Scaffold.SetButtonBlack(i);
                        _colors[i] = (SquareColor)Rnd.Range(1, 6);
                    }

                    // Move to next stage.
                    var nextStage = _table[whiteCount - 1][_lastStage is SquareColor ? (int)(SquareColor)_lastStage - 1 : _lastStage.Equals(true) ? 5 : 6];
                    Log("{0} lit: next stage is {1}.", whiteCount, nextStage.Equals(true) ? "Row" : nextStage.Equals(false) ? "Column" : ((SquareColor)nextStage).ToString());
                    if (nextStage.Equals(true))
                    {
                        // Row
                        var firstRow = Enumerable.Range(0, 4).First(row => Enumerable.Range(0, 4).Any(col => _colors[4 * row + col] != SquareColor.White));
                        for (int col = 0; col < 4; col++)
                        {
                            if (_colors[4 * firstRow + col] != SquareColor.White)
                            {
                                _allowedPresses.Add(4 * firstRow + col);
                                _expectedPresses.Add(4 * firstRow + col);
                            }
                        }
                    }
                    else if (nextStage.Equals(false))
                    {
                        // Column
                        var firstCol = Enumerable.Range(0, 4).First(col => Enumerable.Range(0, 4).Any(row => _colors[4 * row + col] != SquareColor.White));
                        for (int row = 0; row < 4; row++)
                        {
                            if (_colors[4 * row + firstCol] != SquareColor.White)
                            {
                                _allowedPresses.Add(4 * row + firstCol);
                                _expectedPresses.Add(4 * row + firstCol);
                            }
                        }
                    }
                    else
                    {
                        // A specific color
                        // Make sure at least one square has that color
                        var color = (SquareColor)nextStage;
                        _colors[nonWhite[Rnd.Range(0, nonWhite.Length)]] = color;
                        for (int i = 0; i < 16; i++)
                        {
                            if (_colors[i] == color)
                            {
                                _allowedPresses.Add(i);
                                _expectedPresses.Add(i);
                            }
                        }
                    }
                    _lastStage = nextStage;
                    Scaffold.StartSquareColorsCoroutine(_colors, SquaresToRecolor.NonwhiteOnly, delay: true);
                }
            }
        }
    }