public static void Rules(Rule Rules)
 {
     //This shouldn't be reached? I saw it in Morse-A-Maze's code
     if (_rng != null && _rng.Seed == Rules.rng.Seed)
     {
         return;
     }
     _rng = Rules.rng;
     if (_rng.Seed != 1)
     {
         _rng.ShuffleFisherYates(coordX);
         _rng.ShuffleFisherYates(coordY);
         _rng.ShuffleFisherYates(ManualTable);
     }
     AddToOptions(Rules);
     //ManualTable is a double array, which ShuffleFisherYates does not work on
     //As such, the ManualTable must be recreated using for statements
     Rule.ManualTable = new int[6, 6];
     for (int i = 0; i < 6; i++)
     {
         for (int j = 0; j < 6; j++)
         {
             Rule.ManualTable[i, j] = ManualTable[6 * i + j];
         }
     }
 }
Esempio n. 2
0
    void Start()
    {
        rnd = RuleSeed.GetRNG();

        var ixs = Enumerable.Range(0, allConditions.Count).ToList();

        rnd.ShuffleFisherYates(ixs);

        for (int i = 0; i < 4; i++)
        {
            leftSwitch.Add(new Switch {
                Explanation = allConditions[ixs.First()].Explanation, Cond = allConditions[ixs.First()].Cond, SwitchValue = rnd.Next(1, 5)
            });
            ixs.RemoveAt(0);
            rightSwitch.Add(new Switch {
                Explanation = allConditions[ixs.First()].Explanation, Cond = allConditions[ixs.First()].Cond, SwitchValue = rnd.Next(1, 5)
            });
            ixs.RemoveAt(0);
        }

        leftSwitch.Add(new Switch {
            Explanation = "Otherwise", Cond = button => true, SwitchValue = rnd.Next(1, 5)
        });
        rightSwitch.Add(new Switch {
            Explanation = "Otherwise", Cond = button => true, SwitchValue = rnd.Next(1, 5)
        });

        MixButtons();
        StartCoroutine(Game());
    }
Esempio n. 3
0
    private void Awake()
    {
        moduleId         = moduleIdCounter++;
        colorblindActive = colorblind.ColorblindModeActive;

        for (var i = 0; i < buttonLights.Length; i++)
        {
            buttonLights[i].enabled = false;
        }

        rnd = RuleSeedable.GetRNG();
        Debug.LogFormat("[Simon Scrambles #{0}] Using rule seed: {1}", moduleId, rnd.Seed);

        if (rnd.Seed != 1)
        {
            var nowColors = rnd.ShuffleFisherYates(Enumerable.Range(0, 4).ToArray());

            for (var i = 0; i < colorTable.GetLength(0); i++)
            {
                for (var j = 0; j < colorTable.GetLength(1); j++)
                {
                    colorTable[i, j] = nowColors[j];
                }

                nowColors = rnd.ShuffleFisherYates(nowColors);
            }
        }

        foreach (KMSelectable key in buttons)
        {
            key.OnInteract += delegate() {
                KeyPressed(key);

                return(false);
            };
        }

        module.OnActivate += OnActivate;
    }
Esempio n. 4
0
    void Setup()
    {
        stage  = -1;
        center = Random.Range(1, 10);
        if (!alreadyInitialized)
        {
            rnd.ShuffleFisherYates(gridDigits);
        }
        var counter = 0;

        for (int i = 0; i < grid.Length; i++)
        {
            for (int j = 0; j < grid[i].Length; j++)
            {
                grid[i][j] = gridDigits[counter];
                if (gridDigits[counter] == center)
                {
                    y = i;
                    x = j;
                }
                counter++;
            }
        }
        if (!alreadyInitialized)
        {
            for (int i = 0; i < lookUp.Length; i++)
            {
                for (int j = 0; j < lookUp[i].Length; j++)
                {
                    lookUp[i][j] = rnd.Next(1, 5);
                }
            }
        }

        alreadyInitialized = true;
        Debug.LogFormat(@"[Navinums #{0}] Center Display is: {1}.", moduleId, center);
        Debug.LogFormat(@"[Navinums #{0}] Using the following grid:", moduleId);
        for (int i = 0; i < grid.Length; i++)
        {
            Debug.LogFormat(@"[Navinums #{0}] {1}", moduleId, grid[i].Join(", "));
        }
        Debug.LogFormat(@"[Navinums #{0}] Using the following lookups:", moduleId);
        for (int i = 0; i < lookUp.Length; i++)
        {
            Debug.LogFormat(@"[Navinums #{0}] {1}: {2}", moduleId, i + 1, lookUp[i].Join(", "));
        }
        GenerateStage();
    }
Esempio n. 5
0
 void HandleRuleSeed()
 {
     string[] currentQuotes = allPossibleQuotes.ToArray();
     if (ruleSeedCore != null)
     {
         var randomizer = ruleSeedCore.GetRNG();
         randomizer.ShuffleFisherYates(currentQuotes);
         RSReversePriorityLabeled   = randomizer.Next(0, 2) != 1;
         RSReversePriorityUnlabeled = randomizer.Next(0, 2) != 1;
         QuickLog(string.Format("Ruleseed successfully generated with a seed of {0}.", randomizer.Seed));
         if (randomizer.Seed == 1)
         {
             relabeledStageOrder = new[] { 0, 1, 2, 3, -1 }
         }
         ;
         else
         {
             relabeledStageOrder = new[] { 0, 2, 3, 4, -1 };
         }
     }
     else
     {
         QuickLog("Ruleseed handler does not exist. Using default instructions.");
         var randomizer = new MonoRandom(1);
         randomizer.ShuffleFisherYates(currentQuotes);
         RSReversePriorityLabeled   = randomizer.Next(0, 2) != 1;
         RSReversePriorityUnlabeled = randomizer.Next(0, 2) != 1;
         relabeledStageOrder        = new[] { 0, 1, 2, 3, -1 };
     }
     shuffledQuotes = currentQuotes.ToArray();
     Debug.LogFormat("<Labeled Priorities Plus #{0}> All phrases from top to bottom:", modID);
     for (int x = 0; x < shuffledQuotes.Length; x++)
     {
         Debug.LogFormat("<Labeled Priorities Plus #{0}> {2}: \"{1}\"", modID, shuffledQuotes[x].Replace("\n", " "), x + 1);
     }
     Debug.LogFormat("<Labeled Priorities Plus #{0}> Phrase priority when disarming Labeled Priorities: {1}", modID, RSReversePriorityLabeled ? "low to high" : "high to low");
     Debug.LogFormat("<Labeled Priorities Plus #{0}> Phrase priority when disarming Unlabeled Priorities: {1}", modID, RSReversePriorityUnlabeled ? "low to high" : "high to low");
 }
Esempio n. 6
0
        public static RuleSet GetRules(int ruleSeed)
        {
            var random = new MonoRandom(ruleSeed);

            var displayRules = new Dictionary <string, int>(StringComparer.CurrentCultureIgnoreCase);
            var buttonRules  = new Dictionary <string, string[]>(StringComparer.CurrentCultureIgnoreCase);

            foreach (var word in displayTexts)
            {
                displayRules[word] = random.Next(6);
            }

            for (int i = 0; i < buttonTexts.Length; ++i)
            {
                for (int j = 0; j < buttonTexts[i].Length; ++j)
                {
                    var array = (string[])buttonTexts[i].Clone();
                    random.ShuffleFisherYates(array);
                    buttonRules[buttonTexts[i][j]] = array;
                }
            }

            return(new RuleSet(displayRules, buttonRules));
        }
    protected override void DoStart(MonoRandom rnd)
    {
        // RULE SEED
        if (rnd.Seed != _lastGeneratedRuleSeed || _lastGeneratedFlags == null)
        {
            _lastGeneratedTextures = new Texture2D[40];
            _lastGeneratedRuleSeed = rnd.Seed;
            _lastGeneratedFlags    = GenerateFlags(rnd);

            _table = new int[2 * 10 * _numSlots];
            for (var i = 0; i < 2 * _numSlots; i++)
            {
                var nums = Enumerable.Range(0, 10).ToArray();
                rnd.ShuffleFisherYates(nums);
                Array.Copy(nums, 0, _table, 10 * i, 10);
            }
            DebugLog("Generated table for rule seed {0}: {1}", rnd.Seed, _table.Join(", "));
        }
        // END OF RULE SEED


        _leftMaterial  = LeftFlag.sharedMaterial = LeftFlag2.sharedMaterial = new Material(FlagMaterial);
        _rightMaterial = RightFlag.sharedMaterial = RightFlag2.sharedMaterial = new Material(FlagMaterial);

        var iter      = 0;
        var flagInfos = new HashSet <FlagInfo>();

tryAgain:
        iter++;
        flagInfos.Clear();
        var hasDummy = false;

        while (flagInfos.Count < _numSlots)
        {
            var fi = FlagInfo.Generate(hasDummy);
            if (fi.IsDummy)
            {
                hasDummy = true;
            }
            flagInfos.Add(fi);
        }
        if (!hasDummy)
        {
            goto tryAgain;
        }

        _flagInfos = flagInfos.ToArray().Shuffle();

        var values = new List <int>();

        for (var i = 0; i < _numSlots; i++)
        {
            var fi  = _flagInfos[i];
            var val = 0;
            if (fi.IsDummy)
            {
                if (fi.LeftMaritime >= 26)
                {
                    val += fi.LeftMaritime - 26;
                }
                if (fi.RightMaritime >= 26)
                {
                    val += fi.RightMaritime - 26;
                }
            }
            else if (fi.LeftMaritime < fi.Semaphore)
            {
                val += _table[20 * i + 10 - (fi.Semaphore - fi.LeftMaritime)];
                val += _table[20 * i + 9 + (fi.RightMaritime - fi.Semaphore)];
            }
            else
            {
                val += _table[20 * i + 10 - (fi.Semaphore - fi.RightMaritime)];
                val += _table[20 * i + 9 + (fi.LeftMaritime - fi.Semaphore)];
            }
            values.Add(val);
        }

        _solution = (values.Sum() + _numSlots - 1) % _numSlots;   // −1 to compensate for the player’s 1-based counting
        if (_flagInfos[_solution].IsDummy)
        {
            goto tryAgain;
        }

        var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        for (var i = 0; i < _numSlots; i++)
        {
            Log("Position {0}: Left Maritime = {1}, Right Maritime = {2}, Semaphore = {3} (+{4}){5}", i + 1, alphabet[_flagInfos[i].LeftMaritime], alphabet[_flagInfos[i].RightMaritime], alphabet[_flagInfos[i].Semaphore],
                values[i], i == _solution ? " (SOLUTION)" : _flagInfos[i].IsDummy ? " (DUMMY)" : "");
        }

        setPos(0, true);
        LeftButton.OnInteract  += ButtonPress(LeftButton, -1);
        RightButton.OnInteract += ButtonPress(RightButton, 1);
        StartCoroutine(CheckTP());
    }
    protected override void DoStart(MonoRandom rnd)
    {
        // RULE SEED
        if (rnd.Seed != _lastGeneratedRuleSeed || _lastGeneratedFlags == null)
        {
            _lastGeneratedSprites  = new Sprite[40];
            _lastGeneratedRuleSeed = rnd.Seed;
            _lastGeneratedFlags    = GenerateFlags(rnd);

            if (rnd.Seed == 1)
            {
                _lastGeneratedCallsigns = _seed1Callsigns;
            }
            else
            {
                // Randomize callsigns
                var names    = rnd.ShuffleFisherYates(_allCallsigns.ToArray()).Take(315).OrderBy(x => x).ToArray();
                var bearings = rnd.ShuffleFisherYates(Enumerable.Range(0, 360).ToArray());
                _lastGeneratedCallsigns = bearings.Take(315).Select((bearing, ix) => new Callsign {
                    Name = names[ix], Bearing = bearing
                }).ToArray();
            }
        }
        // END OF RULE SEED



        FlagDisplay1.sprite = null;
        FlagDisplay2.sprite = null;

        _callsign = _lastGeneratedCallsigns[Rnd.Range(0, _lastGeneratedCallsigns.Length)];

        var finalBearing  = Rnd.Range(0, 360);
        var flagsOnModule = new List <Sprite>();

        for (int i = 0; i < _callsign.Name.Length; i++)
        {
            var pos = i == 0 ? -1 : _callsign.Name.LastIndexOf(_callsign.Name[i], i - 1);
            if (pos != -1)  // repeater flag
            {
                flagsOnModule.Add(GetFlagSprite(pos + 36));
            }
            else if (_callsign.Name[i] >= '0' && _callsign.Name[i] <= '9')
            {
                flagsOnModule.Add(GetFlagSprite(_callsign.Name[i] - '0' + 26));
            }
            else
            {
                flagsOnModule.Add(GetFlagSprite(_callsign.Name[i] - 'A'));
            }
        }

        _bearingOnModule = (finalBearing - _callsign.Bearing + 360) % 360;
        var bearingOnModuleStr = _bearingOnModule.ToString();

        for (int i = 0; i < bearingOnModuleStr.Length; i++)
        {
            var pos = i == 0 ? -1 : bearingOnModuleStr.LastIndexOf(bearingOnModuleStr[i], i - 1);
            if (pos != -1)  // repeater flag
            {
                flagsOnModule.Add(GetFlagSprite(pos + 36));
            }
            else
            {
                flagsOnModule.Add(GetFlagSprite(bearingOnModuleStr[i] - '0' + 26));
            }
        }

        _flagsOnModule = flagsOnModule.ToArray();
        _curCompass    = Rnd.Range(0, 16);

        _compassSolution = 0;
        var arr = new[] { 12, 34, 57, 79, 102, 124, 147, 169, 192, 214, 237, 259, 282, 304, 327, 349 };

        for (int i = 0; i < arr.Length; i++)
        {
            if (finalBearing < arr[i])
            {
                _compassSolution = i;
                break;
            }
        }

        StartCoroutine(ShowFlags());
        StartCoroutine(AlignCompass());
        Compass.OnInteract = CompassClicked;

        Log("Callsign in flags: {0}", _callsign.Name);
        Log("Bearing in flags: {0}", _bearingOnModule);
        Log("Bearing from callsign: {0}", _callsign.Bearing);
        Log("Final bearing: {0}", (_bearingOnModule + _callsign.Bearing) % 360);
        Log("Solution: {0}", _compassDirections[_compassSolution]);
    }
Esempio n. 9
0
    protected override void GenerateRules(MonoRandom rnd)
    {
tryAgain:
        var usedShapesPerState = new Dictionary <string, List <Shape> >();

        // STEP 1: Generate the main maze and assign a shape to each opened border
        _openBorders = new Dictionary <string, Shape>();
        var openBorder = new Func <string, bool>(borderId =>
        {
            var m = Regex.Match(borderId, "^(..)-(..)$");
            if (!m.Success)
            {
                Log("There is a bug in the rule seed generator. Please contact Timwi about this.", _moduleID);
                throw new InvalidOperationException(string.Format(@"There is a bug in the rule seed generator: “{0}” is not a valid border.", borderId));
            }
            var state           = m.Groups[1].Value;
            var otherState      = m.Groups[2].Value;
            var availableShapes = _shapes.ToList();
            foreach (var st in new[] { state, otherState })
            {
                if (usedShapesPerState.ContainsKey(st))
                {
                    foreach (var shape in usedShapesPerState[st])
                    {
                        availableShapes.Remove(shape);
                    }
                }
            }
            if (availableShapes.Count == 0)
            {
                return(false);
            }

            // If either state has a counterpart with a clashing abbreviation, and has no shape in common with it yet, try to accommodate that
            var clashIx = _clashes.IndexOf(cl => cl.Contains(state) || cl.Contains(otherState));
            if (clashIx != -1)
            {
                var st          = _clashes[clashIx].Contains(state) ? state : otherState;
                var counterpart = _clashes[clashIx].First(cl => cl != st);
                if (usedShapesPerState.ContainsKey(counterpart) && (!usedShapesPerState.ContainsKey(st) || !usedShapesPerState[st].Any(sh => usedShapesPerState[counterpart].Contains(sh))))
                {
                    var preferential = availableShapes.Where(sh => usedShapesPerState[counterpart].Contains(sh)).ToList();
                    if (preferential.Count > 0)
                    {
                        availableShapes = preferential;
                    }
                }
            }

            var chosenShape        = availableShapes[rnd.Next(0, availableShapes.Count)];
            _openBorders[borderId] = chosenShape;
            foreach (var st in new[] { state, otherState })
            {
                usedShapesPerState.AddSafe(st, chosenShape);
            }
            return(true);
        });

        var startState = _states[rnd.Next(0, _states.Length)];
        var visited    = new HashSet <string> {
            startState
        };
        var queue = new Queue <string>();

        queue.Enqueue(startState);
        while (queue.Count > 0)
        {
            var state = queue.Dequeue();
            foreach (var otherState in rnd.ShuffleFisherYates(_states.ToArray()))
            {
                if (!visited.Contains(otherState))
                {
                    foreach (var borderId in new[] { otherState + "-" + state, state + "-" + otherState })
                    {
                        if (_stateBorders.Contains(borderId))
                        {
                            queue.Enqueue(otherState);
                            visited.Add(otherState);
                            if (!openBorder(borderId))
                            {
                                goto tryAgain;
                            }
                        }
                    }
                }
            }
        }

        // STEP 2: Open three more random borders
        var allBorders   = rnd.ShuffleFisherYates(_stateBorders.ToList());
        var ix           = 0;
        var extraBorders = 0;

        while (extraBorders < 3)
        {
            if (ix >= allBorders.Count)
            {
                LogDebug("Rule seed generator: ran into the case with no extra borders. Retrying");
                goto tryAgain;
            }
            if (!_openBorders.ContainsKey(allBorders[ix]) && openBorder(allBorders[ix]))
            {
                extraBorders++;
            }
            ix++;
        }

        // Make sure that states with clashing abbreviations have an exit with the same symbol.
        // The openBorder() function tries to provide this, but it cannot guarantee it.
        for (var i = 0; i < _clashes.Length; i++)
        {
            var exitShapes = _clashes[i].Select(state => usedShapesPerState[state]).ToArray();
            if (exitShapes[0].All(sh => !exitShapes[1].Contains(sh)) || exitShapes[1].All(sh => !exitShapes[0].Contains(sh)))
            {
                goto tryAgain;
            }
        }

        LogDebug(_openBorders.Select(kvp => string.Format("{0} = {1}", kvp.Key, kvp.Value)).Join("\n"));
    }
Esempio n. 10
0
        public Map(string serialNumber, string[] litIndicators, string[] unlitIndicators, int moduleId, MonoRandom rnd)
        {
            var    mazes = new List <MapNode[, ]>();
            string rowPhrase, colPhrase;

            Debug.LogFormat("[3D Maze #{0}] Using rule seed: {1}", moduleId, rnd.Seed);
            if (rnd.Seed == 1)
            {
                string[] labels;
                string[] n_walls;
                string[] w_walls;

                for (var mapIndex = 0; mapIndex < 10; mapIndex++)
                {
                    var rawMapData = new MapNode[WIDTH, WIDTH];
                    switch (mapIndex)
                    {
                    // ABC
                    case 0:
                        labels = new string[] {
                            "     A  ",
                            " *A    B",
                            "A  B C  ",
                            " C  *  B",
                            "    A   ",
                            " B C  B ",
                            "* C     ",
                            "    A C "
                        };
                        n_walls = new string[] {
                            "11000110",
                            "00001000",
                            "01011100",
                            "00100011",
                            "10011001",
                            "00000100",
                            "00110010",
                            "11000001"
                        };
                        w_walls = new string[] {
                            "10101001",
                            "10100100",
                            "00010001",
                            "01010110",
                            "01010001",
                            "01100100",
                            "01001101",
                            "00101100"
                        };
                        break;

                    // ABD
                    case 1:
                        labels = new string[] {
                            "A  B  A*",
                            "  D     ",
                            "     D B",
                            " A B    ",
                            "  *   A ",
                            "D   A   ",
                            "  B  D  ",
                            " D  *  B"
                        };
                        n_walls = new string[] {
                            "10100011",
                            "01100100",
                            "00011010",
                            "00100000",
                            "11100110",
                            "00010100",
                            "10100001",
                            "00011000"
                        };
                        w_walls = new string[] {
                            "10000010",
                            "11000100",
                            "00010001",
                            "01000100",
                            "10010001",
                            "00010100",
                            "01000101",
                            "00010100"
                        };
                        break;

                    // ABH
                    case 2:
                        labels = new string[] {
                            "B    A H",
                            "* H     ",
                            "B   B   ",
                            "    * HA",
                            " A H    ",
                            "    A B ",
                            " B   *  ",
                            "A  H    "
                        };
                        n_walls = new string[] {
                            "11101011",
                            "01011000",
                            "10001101",
                            "01010000",
                            "00001000",
                            "00110100",
                            "00101110",
                            "01100000"
                        };
                        w_walls = new string[] {
                            "10010000",
                            "01000001",
                            "00110011",
                            "11010101",
                            "11010010",
                            "11100000",
                            "00010101",
                            "00000001"
                        };
                        break;

                    // ACD
                    case 3:
                        labels = new string[] {
                            "D       ",
                            "  C D* C",
                            " *   C  ",
                            " A      ",
                            "D  C D  ",
                            "  A  * A",
                            "   A  D ",
                            "A    C  "
                        };
                        n_walls = new string[] {
                            "10111011",
                            "01100110",
                            "00000111",
                            "01000000",
                            "11101110",
                            "01100100",
                            "00010110",
                            "01101100"
                        };
                        w_walls = new string[] {
                            "00001000",
                            "11001100",
                            "01110010",
                            "10011001",
                            "10001001",
                            "01100101",
                            "01010000",
                            "10000010"
                        };
                        break;

                    // ACH
                    case 4:
                        labels = new string[] {
                            "H C   A ",
                            "*   H   ",
                            "      *C",
                            " A   H  ",
                            "C H C A ",
                            " *     A",
                            "   C H  ",
                            "  A     "
                        };
                        n_walls = new string[] {
                            "00111100",
                            "11010000",
                            "01100110",
                            "00000000",
                            "01000100",
                            "00000001",
                            "11100010",
                            "01011011"
                        };
                        w_walls = new string[] {
                            "10000110",
                            "10010001",
                            "01010101",
                            "10000001",
                            "11000000",
                            "01010101",
                            "10010000",
                            "01000010"
                        };
                        break;

                    // ADH
                    case 5:
                        labels = new string[] {
                            "D D  *  ",
                            "    H  A",
                            " *H   A ",
                            "A  D    ",
                            "    HD  ",
                            "* H    A",
                            "D       ",
                            "   A H  "
                        };
                        n_walls = new string[] {
                            "01110101",
                            "00001110",
                            "00000111",
                            "01001100",
                            "00110101",
                            "11100000",
                            "01100000",
                            "11001000"
                        };
                        w_walls = new string[] {
                            "10100100",
                            "11110000",
                            "11011000",
                            "01110000",
                            "10000101",
                            "10001110",
                            "00011111",
                            "10000101"
                        };
                        break;

                    // BCD
                    case 6:
                        labels = new string[] {
                            "     B  ",
                            "C D   * ",
                            " * B  C ",
                            " C    B ",
                            "    C  D",
                            "B    D  ",
                            " C  * D ",
                            "D  B    "
                        };
                        n_walls = new string[] {
                            "01011110",
                            "01101011",
                            "01100100",
                            "10000111",
                            "10110011",
                            "10011001",
                            "01100010",
                            "10111001"
                        };
                        w_walls = new string[] {
                            "10010000",
                            "00001010",
                            "11101000",
                            "00001000",
                            "00100010",
                            "00010001",
                            "00000110",
                            "00100001"
                        };
                        break;

                    // BCH
                    case 7:
                        labels = new string[] {
                            "C   H   ",
                            "  C    H",
                            "  * B   ",
                            "B  H*   ",
                            " H   B C",
                            "   *    ",
                            "  B C   ",
                            " C   H B"
                        };
                        n_walls = new string[] {
                            "10110011",
                            "01010111",
                            "10101100",
                            "00000110",
                            "01111110",
                            "00100010",
                            "10010100",
                            "00000110"
                        };
                        w_walls = new string[] {
                            "10000100",
                            "01001000",
                            "01111001",
                            "10001000",
                            "10001000",
                            "01101101",
                            "01101001",
                            "00010010"
                        };
                        break;

                    // BDH
                    case 8:
                        labels = new string[] {
                            "  D B  H",
                            "   *  D ",
                            "  H *  B",
                            "D    B  ",
                            "    D  H",
                            "  B     ",
                            "   H  H*",
                            "D    B  "
                        };
                        n_walls = new string[] {
                            "00100001",
                            "00010001",
                            "11011000",
                            "11011011",
                            "00010011",
                            "10000000",
                            "01101100",
                            "01001111"
                        };
                        w_walls = new string[] {
                            "01101000",
                            "11010111",
                            "00000110",
                            "00100000",
                            "00110100",
                            "10001110",
                            "11000000",
                            "00011010"
                        };
                        break;

                    // CDH
                    default:
                        labels = new string[] {
                            "  H  D  ",
                            "    C*  ",
                            "   H   D",
                            "H    D  ",
                            "  C     ",
                            "C  D C H",
                            "*D  H * ",
                            "       C"
                        };
                        n_walls = new string[] {
                            "01011010",
                            "00100100",
                            "00000000",
                            "01000010",
                            "01000010",
                            "01100110",
                            "01011010",
                            "10100101"
                        };
                        w_walls = new string[] {
                            "11001001",
                            "11110111",
                            "00100010",
                            "00011100",
                            "10011100",
                            "10001000",
                            "11000001",
                            "00101010"
                        };
                        break;
                    }

                    for (int y = 0; y < WIDTH; y++)
                    {
                        for (int x = 0; x < WIDTH; x++)
                        {
                            rawMapData[x, y] = new MapNode(labels[y][x], n_walls[y][x] == '1', w_walls[y][x] == '1');
                        }
                    }
                    mazes.Add(rawMapData);
                }

                rowPhrase = "MAZEGAMER";
                colPhrase = "HELPIMLOST";
            }
            else
            {
                // RULE SEEDED CODE starts here
                var mazeLabels = "ABC,ABD,ABH,ACD,ACH,ADH,BCD,BCH,BDH,CDH".Split(',');
                foreach (var labels in mazeLabels)
                {
                    var mapData = new MapNode[WIDTH, WIDTH];
                    for (var x = 0; x < WIDTH; x++)
                    {
                        for (var y = 0; y < WIDTH; y++)
                        {
                            mapData[x, y] = new MapNode(' ', true, true);
                        }
                    }
                    var todo    = Enumerable.Range(0, WIDTH * WIDTH).Select(i => new Coordinate(i % WIDTH, i / WIDTH)).ToList();
                    var visited = new List <Coordinate>();
                    var done    = new List <Coordinate>();

                    // Choose a random square to start from
                    var startIx = rnd.Next(0, todo.Count);
                    visited.Add(todo[startIx]);
                    todo.RemoveAt(startIx);

                    // Generate a maze
                    while (todo.Count > 0)
                    {
                        var cellIx = rnd.Next(0, visited.Count);
                        var cell   = visited[cellIx];

                        var validWalls = Enumerable.Range(0, 4).Select(dir => new { Dir = dir, Cell = Neighbor(cell, dir) }).Where(c => todo.Contains(c.Cell)).ToArray();
                        if (validWalls.Length == 0)
                        {
                            visited.RemoveAt(cellIx);
                            done.Add(cell);
                            continue;
                        }

                        var wallIx = rnd.Next(0, validWalls.Length);
                        var wall   = validWalls[wallIx];
                        switch (wall.Dir)
                        {
                        case NORTH: mapData[cell.X, cell.Y].n_wall = false; break;

                        case WEST: mapData[cell.X, cell.Y].w_wall = false; break;

                        case SOUTH: mapData[wall.Cell.X, wall.Cell.Y].n_wall = false; break;

                        default: mapData[wall.Cell.X, wall.Cell.Y].w_wall = false; break;
                        }
                        todo.Remove(wall.Cell);
                        visited.Add(wall.Cell);
                    }

                    // Remove 20–35% of the remaining walls to make the maze more spacious
                    var remainingWalls = new List <int>();
                    for (var x = 0; x < WIDTH; x++)
                    {
                        for (var y = 0; y < WIDTH; y++)
                        {
                            if (mapData[x, y].n_wall)
                            {
                                remainingWalls.Add((WIDTH * y + x) * 2);
                            }
                            if (mapData[x, y].w_wall)
                            {
                                remainingWalls.Add((WIDTH * y + x) * 2 + 1);
                            }
                        }
                    }
                    var percentage  = (rnd.NextDouble() * .15) + .2;
                    var removeWalls = (int)(remainingWalls.Count * percentage);
                    while (removeWalls > 0)
                    {
                        var wallIx = rnd.Next(0, remainingWalls.Count);
                        var wall   = remainingWalls[wallIx];
                        remainingWalls.RemoveAt(wallIx);
                        var x = (wall / 2) % WIDTH;
                        var y = (wall / 2) / WIDTH;

                        if (wall % 2 == 1)
                        {
                            // Make sure not to remove a wall that would leave an entire row devoid of walls
                            if (Enumerable.Range(0, WIDTH).Count(xx => mapData[xx, y].w_wall) == 1)
                            {
                                continue;
                            }
                            mapData[x, y].w_wall = false;
                        }
                        else
                        {
                            // Make sure not to remove a wall that would leave an entire column devoid of walls
                            if (Enumerable.Range(0, WIDTH).Count(yy => mapData[x, yy].n_wall) == 1)
                            {
                                continue;
                            }
                            mapData[x, y].n_wall = false;
                        }
                        removeWalls--;
                    }

                    // Select 33 random cells for the labels (letters and cardinals)
                    done.AddRange(visited);
                    rnd.ShuffleFisherYates(done);
                    // Add the labels (5 of each letter)
                    for (var letterIx = 0; letterIx < labels.Length; letterIx++)
                    {
                        for (var i = 0; i < 5; i++)
                        {
                            mapData[done[5 * letterIx + i].X, done[5 * letterIx + i].Y].label = labels[letterIx];
                        }
                    }
                    // Add the 3 asterisks
                    for (var i = 0; i < 3; i++)
                    {
                        mapData[done[30 + i].X, done[30 + i].Y].label = '*';
                    }

                    mazes.Add(mapData);
                }

                var phrases = new List <string>
                {
                    "MAZE GAMER",
                    "MAZE TRAVELER",
                    "MAZE CORRIDOR",
                    "MAZE SOJOURNER",
                    "MAZE VOYAGER",
                    "HELP IM LOST",
                    "WINDING MAZE",
                    "TWISTY PASSAGES",
                    "ADVENTURING",
                    "FIND THE EXIT",
                    "WHERES THE EXIT",
                    "GO TO THE EXIT",
                    "FIND THE WALL",
                    "UPON DISCOVERY",
                    "ON A JOURNEY",
                    "SOS WHERE AM I",
                    "SHOW ME AROUND",
                    "I NEED ASSISTANCE",
                    "LABYRINTHIAN",
                    "PATH FINDER",
                    "CARDINAL DIRECTION",
                    "WHAT IS THIS PLACE",
                    "GO IN CIRCLES",
                    "DEAD END",
                    "TURN AROUND"
                };
                var ix = rnd.Next(0, phrases.Count);
                rowPhrase = phrases[ix];
                phrases.RemoveAt(ix);
                colPhrase = phrases[rnd.Next(0, phrases.Count)];
                Debug.LogFormat("<3D Maze #{0}> Row phrase: {1}", moduleId, rowPhrase);
                Debug.LogFormat("<3D Maze #{0}> Column phrase: {1}", moduleId, colPhrase);
            }

            // Calculate the goal position from the edgework
            var firstDigit = serialNumber.Where(ch => ch >= '0' && ch <= '9').First();
            var lastDigit  = serialNumber.Where(ch => ch >= '0' && ch <= '9').Last();
            var rowMsg     = firstDigit.ToString();
            var numUnlit   = 0;

            foreach (string unlit in unlitIndicators)
            {
                // MAZE GAMER
                if (unlit.Intersect(rowPhrase).Any())
                {
                    numUnlit++;
                    rowMsg += " + " + unlit;
                }
            }
            if (numUnlit == 0)
            {
                rowMsg = "no unlit indicators";
            }

            var colMsg = lastDigit.ToString();
            var numLit = 0;

            foreach (string lit in litIndicators)
            {
                // HELP I'M LOST
                if (lit.Intersect(colPhrase).Any())
                {
                    numLit++;
                    colMsg += " + " + lit;
                }
            }
            if (numLit == 0)
            {
                colMsg = "no lit indicators";
            }

            sol_x = (lastDigit + numLit) % WIDTH;
            sol_y = (firstDigit + numUnlit) % WIDTH;

            mapData = mazes[Random.Range(0, 10)];
            end_dir = Random.Range(0, 4);
            var decoy_dir = Random.Range(0, 3);

            if (decoy_dir >= end_dir)
            {
                decoy_dir++;
            }

            Debug.LogFormat("[3D Maze #{0}] Selected map: {1}", moduleId, join("", Enumerable.Range(0, WIDTH * WIDTH).Select(ix => mapData[ix % WIDTH, ix / WIDTH].label).Where("ABCDH".Contains).Distinct().OrderBy(c => c)));
            Debug.LogFormat("[3D Maze #{0}] Column: {1} ({2}), Row: {3} ({4}), Cardinal: {5}", moduleId, sol_x, colMsg, sol_y, rowMsg, new[] { "North", "East", "South", "West" }[end_dir]);

            // Replace the asterisks in the map with the true cardinal direction
            for (var x = 0; x < WIDTH; x++)
            {
                for (var y = 0; y < WIDTH; y++)
                {
                    if (mapData[x, y].label == '*')
                    {
                        mapData[x, y].label = dirToChar(end_dir);
                    }
                }
            }

            // Add three decoy cardinal directions
            for (int i = 0; i < 3; i++)
            {
                int x = Random.Range(0, WIDTH);
                int y = Random.Range(0, WIDTH);
                while (mapData[x, y].label != ' ')
                {
                    x = Random.Range(0, WIDTH);
                    y = Random.Range(0, WIDTH);
                }
                mapData[x, y].label = dirToChar(decoy_dir);
            }

            pl_x   = Random.Range(0, WIDTH);
            pl_y   = Random.Range(0, WIDTH);
            pl_dir = Random.Range(0, 4);

            while (!getEdge(sol_x, sol_y, end_dir, 0, 0, end_dir))
            {
                sol_x = bound(sol_x + xMod(1, 0, end_dir), WIDTH);
                sol_y = bound(sol_y + yMod(1, 0, end_dir), WIDTH);
            }

            win_x1 = sol_x;
            win_y1 = sol_y;

            win_x2 = bound(sol_x + xMod(1, 0, end_dir), WIDTH);
            win_y2 = bound(sol_y + yMod(1, 0, end_dir), WIDTH);
        }
Esempio n. 11
0
    void Start()
    {
        moduleId = moduleIdCounter++;

        rng = RuleSeed.GetRNG();
        DebugLog("Using rule seed: {0}", rng.Seed);
        GenerateMazes();

        //check what the serial ends with and make an integer for it
        LastDigit = BombInfo.GetSerialNumberNumbers().Last();

        if (rng.Seed != 1)
        {
            for (var i = 0; i < 20; i++)
            {
                colorTable[i / 5, i % 5] = rng.Next(1, 5);
            }
        }

        int SumNS = 4;
        int SumEW = 4;

        int[] COLORKEYS = new int[5];

        for (int i = 0; i < 4; i++)
        {
            buttonColors[i] = UnityEngine.Random.Range(0, 5);
            var colorNum = buttonColors[i];

            int value = colorTable[i, colorNum];
            DebugLog("{0} Key is {1}, making it's value {2}", buttonNames[i], colorNames[colorNum], value);

            COLORKEYS[colorNum]++; // Adds the current color

            if (i % 2 == 0)
            {
                SumNS += value;                         // North and South are both on even indexes
            }
            else
            {
                SumEW += value;              // East and West are both on odd indexes
            }
        }

        SumNS = SumNS % 5;
        SumEW = SumEW % 5;

        // Look for mazebased modules
        string[] MazeModules = new[] { "Mouse In The Maze", "3D Maze", "Hexamaze", "Morse-A-Maze", /*"Blind Maze",*/ "Polyhedral Maze", "Maze", "USA Maze", "Maze Scrambler", "Boolean Maze", "The Crystal Maze", "Factory Maze", "Module Maze" };
        int      MazeBased   = BombInfo.GetModuleNames().Intersect(MazeModules).Count();

        DebugLog("There are {0} compatible maze-type modules on the bomb, not including Blind Maze.", MazeBased);

        int MazeRule = 7;

        int[] rulesCount         = { COLORKEYS[0], BombInfo.GetBatteryCount(), COLORKEYS[4], COLORKEYS[0], MazeBased, BombInfo.GetPorts().Distinct().Count(), COLORKEYS[1], COLORKEYS[2], COLORKEYS[3], BombInfo.GetBatteryCount(KMBI.KnownBatteryType.AA), BombInfo.GetBatteryCount(KMBI.KnownBatteryType.D), BombInfo.GetBatteryHolderCount(), BombInfo.GetPortCount(), BombInfo.GetPortPlateCount(), BombInfo.GetIndicators().Count(), BombInfo.GetOnIndicators().Count(), BombInfo.GetOffIndicators().Count() };
        int[] conditionCount     = { 2, 5, 1, 1, 1 };
        int   conditionIndicator = 3;

        int[]  mazeRotation = { 1, 1, 2, 1, 2, 1 };
        bool[] clockwise    = { true, true, true, false, true, false };
        bool[] calculate    = { false, true, false, false, true, true };

        Action <int> rules = (x) => {
            if (clockwise[x])
            {
                startRot = MazeRot = mazeRotation[x];
            }
            else
            {
                startRot = MazeRot = 4 - mazeRotation[x];
            }

            if (calculate[x])
            {
                startRot = 0;
            }

            MazeRule = x + 1;
        };

        if (rng.Seed != 1)
        {
            rulesCount         = rng.ShuffleFisherYates(rulesCount).Take(6).ToArray();
            conditionIndicator = rng.Next(11);

            for (var i = 0; i < 6; i++)
            {
                if (i < 5)
                {
                    conditionCount[i] = rng.Next(1, 5);
                }

                mazeRotation[i] = rng.Next(1, 4);
                clockwise[i]    = (rng.Next(2) == 1) ? true : false;
                calculate[i]    = (rng.Next(2) == 1) ? true : false;
            }
        }

        //Determine rotation
        if (rulesCount[0] >= conditionCount[0])
        {
            rules(0);
        }
        else if (rulesCount[1] >= conditionCount[1])
        {
            rules(1);
        }
        else if (BombInfo.GetIndicators().Contains(((KMBI.KnownIndicatorLabel)conditionIndicator).ToString()))
        {
            rules(2);
        }
        else if (rulesCount[2] == 0 && rulesCount[3] >= conditionCount[2])
        {
            rules(3);
        }
        else if (rulesCount[4] >= conditionCount[3])
        {
            rules(4);
        }
        else if (rulesCount[5] <= conditionCount[4])
        {
            rules(5);
        }
        else
        {
            startRot = MazeRot = 0;
            MazeRule = 7;
        }

        var ruleClockwise = "clockwise";

        if (MazeRule != 7)
        {
            ruleClockwise = (clockwise[MazeRule - 1]) ? "clockwise" : "counter-clockwise";
        }

        DebugLog("Maze Rotation is {0} degrees {1} because of rule {2}", MazeRule == 7 ? 0 : mazeRotation[MazeRule - 1] * 90, ruleClockwise, MazeRule);

        KMSelectable[] directions = new[] { North, East, South, West };
        ButtonInfo[]   buttonInfo = new[]
        {
            new ButtonInfo(0, -1, "U"),
            new ButtonInfo(1, 0, "R"),
            new ButtonInfo(0, 1, "D"),
            new ButtonInfo(-1, 0, "L")
        };

        for (int i = 0; i < 4; i++)
        {
            directions[i].OnInteract += GetInteractHandler(directions[i], buttonInfo[mod(-MazeRot + i, 4)]);
        }

        Reset.OnInteract += GetInteractHandler(Reset, new ButtonInfo(0, 0, null, true));

        //Determine Starting Position
        switch (startRot)
        {
        case 0:
            CurX = SumNS;
            CurY = SumEW;
            break;

        case 1:
            CurX = SumEW;
            CurY = 4 - SumNS;
            break;

        case 2:
            CurX = 4 - SumNS;
            CurY = 4 - SumEW;
            break;

        case 3:
            CurX = 4 - SumEW;
            CurY = SumNS;
            break;
        }
        UpdatePosition();

        StartX = CurX;
        StartY = CurY;

        DebugLog("Starting location is: ({0}, {1}).", SumNS + 1, SumEW + 1);

        if (MazeRot != startRot)
        {
            DebugLog("Location is determined before rotation. Starting location on rotated maze is ({0}, {1}).", RotX, RotY);
        }
        else if (MazeRule != 7)
        {
            DebugLog("Location is determined after rotation.");
        }
        prevColor = curColor.ToArray();
        var nextColor = buttonColors.Select(x => colors[x]).ToArray();

        BombModule.OnActivate += delegate() { StartCoroutine(ShowColor(prevColor, nextColor)); };
    }
    void OnActivate()
    {
        MonoRandom rng = GetComponent <KMRuleSeedable>().GetRNG();

        // If we are using the default seed, only pick the original items
        if (rng.Seed == 1)
        {
            Prices   = Prices.Take(34).ToArray();
            PricesLB = PricesLB.Take(12).ToArray();
        }
        else
        {
            Prices   = rng.ShuffleFisherYates(Prices).Take(34).ToArray();
            PricesLB = rng.ShuffleFisherYates(PricesLB).Take(12).ToArray();

            foreach (Item item in Prices)
            {
                item.Price += rng.Next(-10, 11) * 0.01m;
            }

            foreach (Item item in PricesLB)
            {
                item.Price += rng.Next(-10, 11) * 0.01m;
            }

            SundayValue           = rng.Next(50, 301) / 100m;
            MondayPercent         = rng.Next(10, 100) / 100m;
            TuesdayExcludedDigit  = rng.Next(-1, 3);
            WednesdayLargeOrSmall = rng.Next(0, 2) == 1;
            WednesdayViceVersa    = rng.Next(0, 2) == 1;
            ThursdayOddItems      = rng.Next(0, 2) == 1;
            ThursdayPercent       = rng.Next(25, 76) / 100m;
            FridayPercent         = rng.Next(50, 201) / 100m;
            SaturdayPercent       = rng.Next(50, 201) / 100m;
        }

        DOW = DateTime.Now.DayOfWeek.ToString();

        DebugMsg("Sale is based on " + DOW + ".");

        List <string> Possible = new List <string>(Prices.Select(item => item.Name));

        for (int i = 0; i < 4; i++)
        {
            var item = Possible[Random.Range(0, Possible.Count)];
            Items.Add(item);
            Possible.Remove(item);
            decimal dollars = ApplySale(item, 0, Items.Count);
            Total += dollars;
        }

        Possible = new List <string>(PricesLB.Select(item => item.Name));
        for (int i = 0; i < 2; i++)
        {
            var item = Possible[Random.Range(0, Possible.Count)];
            var lb   = Random.Range(1, 4) * 0.5m;
            Items.Add(lb + "lb " + item);
            Possible.Remove(item);
            decimal dollars = ApplySale(item, lb, Items.Count);
            Total += dollars;
        }

        Paid = decimal.Round(Total + (decimal)Random.Range(-(float)Total / 2, (float)Total / 2));
        if (Total > Paid)
        {
            Display = Paid;
            DebugMsg("Customer underpaid with $" + Paid.ToString());
            Paid = decimal.Round(Total + (decimal)Random.Range(0f, (float)Total / 2)) + 1m;
        }
        else
        {
            Display = Paid;
        }

        BuildReceipt();

        UpdateDisplay();

        foreach (GameObject button in Amounts)
        {
            GameObject   Button           = button;
            KMSelectable ButtonSelectable = button.GetComponent <KMSelectable>();
            ButtonSelectable.OnInteract += () =>
            {
                if (!waiting)
                {
                    ButtonPress(ButtonSelectable);
                    string text = GetTextMesh(Button).text;
                    if (text.Length > 2)
                    {
                        BombAudio.PlaySoundAtTransform("coin_drop" + Random.Range(1, 3), transform);
                    }
                    else
                    {
                        BombAudio.PlaySoundAtTransform("count_bill" + Random.Range(1, 6), transform);
                    }

                    Change += decimal.Parse("0" + text);
                    UpdateDisplay();
                }
                else
                {
                    BombAudio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.CapacitorPop, transform);
                }

                return(false);
            };
        }

        MoveLeft.OnInteract += () =>
        {
            ButtonPress(MoveLeft);

            DisplayPos--;
            UpdateDisplay();

            return(false);
        };

        MoveRight.OnInteract += () =>
        {
            ButtonPress(MoveRight);

            DisplayPos++;
            UpdateDisplay();

            return(false);
        };

        Submit.OnInteract += () =>
        {
            if (!waiting)
            {
                ButtonPress(Submit);

                if (Total > Display)
                {
                    if (Change == 0)
                    {
                        StartCoroutine(WaitForCustomer());
                    }
                    else
                    {
                        DebugMsg("Change was submitted when the customer should have been alerted.");
                        BombModule.HandleStrike();
                    }
                }
                else
                {
                    DebugMsg("Change entered: $" + Change.ToString("N2"));
                    if (Change == Paid - Total && !solved)
                    {
                        solved  = true;
                        waiting = true;

                        PriceText.GetComponent <TextMesh>().color = Color.green;
                        BombAudio.PlaySoundAtTransform("module_solved", transform);
                        StartCoroutine(Wait(3f, () =>
                        {
                            DebugMsg("Module solved!");
                            BombModule.HandlePass();

                            return(true);
                        }));
                    }
                    else
                    {
                        PriceText.GetComponent <TextMesh>().color = Color.red;
                        StartCoroutine(Wait(1.5f, () =>
                        {
                            UpdateDisplay();
                            return(true);
                        }));
                        BombModule.HandleStrike();
                    }
                }

                Change = 0m;
            }
            else
            {
                BombAudio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.CapacitorPop, transform);
            }

            return(false);
        };

        Clear.OnInteract += () =>
        {
            if (!waiting)
            {
                ButtonPress(Clear);
                Change = 0m;
                UpdateDisplay();
            }
            else
            {
                BombAudio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.CapacitorPop, transform);
            }

            return(false);
        };
    }
Esempio n. 13
0
        public static GeneratedMaze Generate(MonoRandom rnd)
        {
            // PART 1: GENERATE MAZE (walls)
            var walls = Ut.NewArray(3 * sw * sw, ix =>
            {
                var r = (ix / 3) % sw - Size;
                var q = (ix / 3) / sw - Size;
                var h = new Hex(q, r);
                return(h.Distance < Size || h.GetNeighbor(ix % 3).Distance < Size);
            });
            var allWalls = (bool[])walls.Clone();

            var stack  = new Stack <Hex>();
            var curHex = new Hex(0, 0);

            stack.Push(curHex);
            var taken = new HashSet <Hex> {
                curHex
            };

            // Step 1.1: generate a single giant maze
            while (true)
            {
                var neighbors = curHex.Neighbors;
                var availableNeighborIndices = neighbors.SelectIndexWhere(n => !taken.Contains(n) && n.Distance < Size).ToArray();
                if (availableNeighborIndices.Length == 0)
                {
                    if (stack.Count == 0)
                    {
                        break;
                    }
                    curHex = stack.Pop();
                    continue;
                }
                var dir = availableNeighborIndices[rnd.Next(0, availableNeighborIndices.Length)];
                walls[wallIndex(curHex, dir)] = false;
                stack.Push(curHex);
                curHex = neighbors[dir];
                taken.Add(curHex);
            }

            // Step 1.2: Go through all submazes and make sure they’re all connected and all have at least one exit on each side
            // This is parallelizable and uses multiple threads
            var allSubmazes = Hex.LargeHexagon(Size - SubmazeSize + 1).Select(h => (Hex?)h).ToArray();
            Hex?lastHex1 = null, lastHex2 = null;

            while (true)
            {
                var candidateCounts = new Dictionary <int, int>();

                for (var smIx = 0; smIx < allSubmazes.Length; smIx++)
                {
                    if (allSubmazes[smIx] == null)
                    {
                        continue;
                    }

                    var centerHex = allSubmazes[smIx].Value;

                    // We do not need to examine this submaze if the wall we last removed isn’t even in it
                    if (lastHex1 != null && (lastHex1.Value - centerHex).Distance > SubmazeSize &&
                        lastHex2 != null && (lastHex2.Value - centerHex).Distance > SubmazeSize)
                    {
                        continue;
                    }

                    var validity = DetermineSubmazeValidity(centerHex, walls);
                    if (validity.IsValid)
                    {
                        allSubmazes[smIx] = null;
                        continue;
                    }

                    // Find out which walls might benefit from removing
                    foreach (var fh in validity.Filled)
                    {
                        var neighbors = fh.Neighbors;
                        for (var dir = 0; dir < neighbors.Length; dir++)
                        {
                            var th     = neighbors[dir];
                            var offset = th - centerHex;
                            if ((offset.Distance < SubmazeSize && walls[wallIndex(fh, dir)] && !validity.Filled.Contains(th)) ||
                                (offset.Distance == SubmazeSize && offset.GetEdges(SubmazeSize).Any(e => !validity.EdgesReachable[e])))
                            {
                                candidateCounts.IncSafe(wallIndex(fh, dir));
                            }
                        }
                    }
                }

                if (candidateCounts.Count == 0)
                {
                    break;
                }

                // Remove one wall out of the “most wanted”
                var topScore   = 0;
                var topScorers = new List <int>();
                foreach (var kvp in candidateCounts)
                {
                    if (kvp.Value > topScore)
                    {
                        topScore = kvp.Value;
                        topScorers.Clear();
                        topScorers.Add(kvp.Key);
                    }
                    else if (kvp.Value == topScore)
                    {
                        topScorers.Add(kvp.Key);
                    }
                }
                topScorers.Sort();
                var randomWall = topScorers[rnd.Next(0, topScorers.Count)];
                walls[randomWall] = false;

                var rcdir = randomWall % 3;
                lastHex1 = new Hex((randomWall / 3) / sw - Size, (randomWall / 3) % sw - Size);
                lastHex2 = lastHex1.Value.GetNeighbor(rcdir);
            }

            // Step 1.3: Put as many walls back in as possible
            var missingWalls = Enumerable.Range(0, allWalls.Length).Where(ix => allWalls[ix] && !walls[ix]).ToList();

            while (missingWalls.Count > 0)
            {
                var randomMissingWallIndex = rnd.Next(0, missingWalls.Count);
                var randomMissingWall      = missingWalls[randomMissingWallIndex];
                missingWalls.RemoveAt(randomMissingWallIndex);
                walls[randomMissingWall] = true;

                var affectedHex1 = new Hex((randomMissingWall / 3) / sw - Size, (randomMissingWall / 3) % sw - Size);
                var affectedHex2 = affectedHex1.GetNeighbor(randomMissingWall % 3);

                foreach (var centerHex in rnd.ShuffleFisherYates(Hex.LargeHexagon(Size - SubmazeSize + 1).ToList()))
                {
                    // We do not need to examine this submaze if the wall we put in isn’t even in it
                    if (((affectedHex1 - centerHex).Distance <= SubmazeSize ||
                         (affectedHex2 - centerHex).Distance <= SubmazeSize) &&
                        !DetermineSubmazeValidity(centerHex, walls).IsValid)
                    {
                        // This wall cannot be added, take it back out.
                        walls[randomMissingWall] = false;
                        break;
                    }
                }
            }

            // PART 2: GENERATE MARKINGS
tryAgain:
            var markings = new Marking[sw * sw];
            // List Circle and Hexagon twice so that triangles don’t completely dominate the distribution
            var allowedMarkings = new[] { Marking.Circle, Marking.Circle, Marking.Hexagon, Marking.Hexagon, Marking.TriangleDown, Marking.TriangleLeft, Marking.TriangleRight, Marking.TriangleUp };

            // Step 2.1: Put random markings in until there are no more ambiguities
            while (!areMarkingsUnique(markings))
            {
                var availableHexes = Hex.LargeHexagon(Size)
                                     .Where(h => markings[markingIndex(h)] == Marking.None &&
                                            h.Neighbors.SelectMany(n1 => n1.Neighbors)
                                            .All(n2 => n2.Distance >= Size || markings[markingIndex(n2)] == Marking.None))
                                     .ToArray();
                if (availableHexes.Length == 0)
                {
                    goto tryAgain;
                }
                var randomHex = availableHexes[rnd.Next(0, availableHexes.Length)];
                markings[markingIndex(randomHex)] = allowedMarkings[rnd.Next(0, allowedMarkings.Length)];
            }

            // Step 2.2: Find markings to remove again
            var removableMarkings = markings.SelectIndexWhere(m => m != Marking.None).ToList();

            while (removableMarkings.Count > 0)
            {
                var tryRemoveIndex = rnd.Next(0, removableMarkings.Count);
                var tryRemove      = removableMarkings[tryRemoveIndex];
                removableMarkings.RemoveAt(tryRemoveIndex);
                var prevMarking = markings[tryRemove];
                markings[tryRemove] = Marking.None;
                if (!areMarkingsUnique(markings))
                {
                    // No longer unique — put it back in
                    markings[tryRemove] = prevMarking;
                }
            }

            return(new GeneratedMaze(walls, markings));
        }
    void Start()
    {
        moduleId = moduleIdCounter++;

        //Gets the rule seed RNG methods
        RNG = RuleSeedable.GetRNG();
        var charList = Enumerable.Range('A', 26).Select(x => (char)x).ToArray();

        //Generates the cipher table
        for (var c = 0; c < 26; c++)
        {
            charTable[c] = new char[26];
            charList     = RNG.ShuffleFisherYates(charList);

            for (var d = 0; d < 26; d++)
            {
                charTable[c][d] = charList[d];
            }
        }

        //Initialize start word
        var startWord = StartWordMesh.text = wordList.Pick();

        Debug.LogFormat(@"[Cryptic Password #{0}] Starting word is: {1}", moduleId, startWord);

        //Initialize key word
        var keyWord = KeyWordMesh.text = charList.Shuffle().Take(Random.Range(3, 7)).Join("");

        Debug.LogFormat(@"[Cryptic Password #{0}] Key word is: {1}", moduleId, keyWord);

        //If the first letter of the start word is a vowel, reverse the key word
        if ("AEIOU".Contains(startWord[0]))
        {
            keyWord = keyWord.Reverse();
            Debug.LogFormat(@"[Cryptic Password #{0}] Start word's first letter is a vowel. Key word is reversed.", moduleId);
        }

        //If the last letter of the start word is a vowel, swap the rows and columns of the cipher
        bool lastLetterVowel = "AEIOU".Contains(startWord[5]);

        if (lastLetterVowel)
        {
            Debug.LogFormat(@"[Cryptic Password #{0}] Start word's last letter is a vowel. Rows and columns of cipher are swapped.", moduleId);
        }

        //Determine solution
        for (var c = 0; c < 6; c++)
        {
            //Calculates the solution based on the table cipher
            if (lastLetterVowel)
            {
                solutionWord += charTable[startWord[c] - 'A'][keyWord[c % keyWord.Length] - 'A'];
            }
            else
            {
                solutionWord += charTable[keyWord[c % keyWord.Length] - 'A'][startWord[c] - 'A'];
            }

            //Initialize letters
            displayLetters[c] = new List <char> {
                //Add the correct character to the display letters
                solutionWord[c]
            };

            //Add filler letters to the display letters
            displayLetters[c].AddRange(charList.Except(displayLetters[c]).ToArray().Shuffle().Take(4));

            //Set display indices
            displayIndices[c] = Random.Range(0, 5);
        }

        Debug.LogFormat(@"[Cryptic Password #{0}] Solution is: {1}", moduleId, solutionWord);

        //Set the displays to the proper letter
        for (var c = 0; c < 6; c++)
        {
            DisplaytextMesh[c].text = displayLetters[c][displayIndices[c]].ToString();
        }

        //Set delegates for the up and down buttons
        for (var c = 0; c < 12; c++)
        {
            var d = c;

            if (c < 6)
            {
                Buttons[c].OnInteract += delegate() {
                    ChangeLetter(d, true);

                    return(false);
                };
            }
            else
            {
                Buttons[c].OnInteract += delegate() {
                    ChangeLetter(d - 6, false);

                    return(false);
                };
            }
        }

        //Set delegate for submit button
        SubmitButton.OnInteract += delegate() {
            CheckSubmission();

            return(false);
        };
    }
Esempio n. 15
0
    protected override void GenerateRules(MonoRandom rnd)
    {
        if (rnd.Seed == 1)
        {
            _outShapes   = _seed1_outShapes;
            _openBorders = _seed1_openBorders;
            _outOpen     = _seed1_outOpen;
            return;
        }

        _outShapes   = new Dictionary <string, Shape>();
        _openBorders = new Dictionary <string, Shape>();

tryAgain:
        var usedShapesPerState = new Dictionary <string, List <Shape> >();

        // STEP 1: Decide which states have an “out” (connection to Alaska/Hawaii) and assign them shapes
        var availableOutStates = rnd.ShuffleFisherYates(_outStates.ToArray());

        for (var i = 0; i < 8; i++)
        {
            _outShapes[availableOutStates[i]] = _shapes[i];
            usedShapesPerState.AddSafe(availableOutStates[i], _shapes[i]);
        }

        // STEP 2: Generate the main maze and assign a shape to each opened border
        _openBorders = new Dictionary <string, Shape>();
        var openBorder = new Func <string, bool>(borderId =>
        {
            var m = Regex.Match(borderId, "^(..)-(..)$");
            if (!m.Success)
            {
                Log("There is a bug in the rule seed generator. Please contact the developer about this.", _moduleID);
                throw new InvalidOperationException(string.Format(@"There is a bug in the rule seed generator: “{0}” is not a valid border.", borderId));
            }
            var state           = m.Groups[1].Value;
            var otherState      = m.Groups[2].Value;
            var availableShapes = _shapes.ToList();
            foreach (var st in new[] { state, otherState })
            {
                if (usedShapesPerState.ContainsKey(st))
                {
                    foreach (var shape in usedShapesPerState[st])
                    {
                        availableShapes.Remove(shape);
                    }
                }
            }
            if (availableShapes.Count == 0)
            {
                return(false);
            }
            var chosenShape        = availableShapes[rnd.Next(0, availableShapes.Count)];
            _openBorders[borderId] = chosenShape;
            foreach (var st in new[] { state, otherState })
            {
                usedShapesPerState.AddSafe(st, chosenShape);
            }
            return(true);
        });

        var startState = _states[rnd.Next(0, _states.Length)];
        var visited    = new HashSet <string> {
            startState
        };
        var queue = new Queue <string>();

        queue.Enqueue(startState);
        while (queue.Count > 0)
        {
            var state = queue.Dequeue();
            foreach (var otherState in rnd.ShuffleFisherYates(_states.ToArray()))
            {
                if (!visited.Contains(otherState))
                {
                    foreach (var borderId in new[] { otherState + "-" + state, state + "-" + otherState })
                    {
                        if (_stateBorders.Contains(borderId))
                        {
                            queue.Enqueue(otherState);
                            visited.Add(otherState);
                            if (!openBorder(borderId))
                            {
                                goto tryAgain;
                            }
                        }
                    }
                }
            }
        }

        // STEP 3: Open three more random borders
        var allBorders   = rnd.ShuffleFisherYates(_stateBorders.ToList());
        var ix           = 0;
        var extraBorders = 0;

        while (extraBorders < 3)
        {
            if (ix >= allBorders.Count)
            {
                LogDebug(@"Rule seed generator: ran into the case with no extra borders. Retrying");
                goto tryAgain;
            }
            if (!_openBorders.ContainsKey(allBorders[ix]) && openBorder(allBorders[ix]))
            {
                extraBorders++;
            }
            ix++;
        }

        // Day-of-week table
        // To ensure that every row and every column has unique symbols,
        // let’s use the same trick that I used in Elder Futhark and just use the top-left corner
        var rowShuffle    = rnd.ShuffleFisherYates(Enumerable.Range(0, 8).ToArray());
        var columnShuffle = rnd.ShuffleFisherYates(Enumerable.Range(0, 8).ToArray());

        _outOpen = new Shape[_outlying.Length][];
        for (var outIx = 0; outIx < _outlying.Length; outIx++)
        {
            _outOpen[outIx] = new Shape[7];
            for (var dow = 0; dow < 7; dow++)
            {
                _outOpen[outIx][dow] = _shapes[(columnShuffle[dow] + rowShuffle[outIx]) % 8];
            }
        }

        LogDebug("Open borders: {1}", _moduleID, _openBorders.Select(kvp => string.Format("{0} = {1}", kvp.Key, kvp.Value)).Join("; "));
        LogDebug("Out-connections: {1}", _moduleID, _outShapes.Select(kvp => string.Format("{0} = {1}", kvp.Key, kvp.Value)).Join("; "));
        for (var outIx = 0; outIx < _outlying.Length; outIx++)
        {
            LogDebug("Out times for {1}: {2}", _moduleID, _outlying[outIx], _outOpen[outIx].Join(", "));
        }
    }
Esempio n. 16
0
    void Start()
    {
        moduleId = moduleIdCounter++;
        rnd      = RuleSeedable.GetRNG();
        Debug.LogFormat(@"[Colorful Insanity #{0}] Using rule seed: {1}", moduleId, rnd.Seed);
        nowPatterns = rnd.ShuffleFisherYates(nowPatterns);

        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                nowColors[i, j] = new[] {
                    colorLetters[rnd.Next(10)],
                    colorLetters[rnd.Next(10)],
                    colorLetters[rnd.Next(10)]
                }.Distinct().Join("");
            }
        }

        for (int i = 0; i < specialButtons.Length; i++)
        {
            specialButtons[i] = (i == 0) ? Random.Range(0, ModuleButtons.Length) : ChooseUnique(specialButtons.Take(i).ToArray(), ModuleButtons.Length);
        }

        SetPatterns(specialButtons[0], GetPatterns());
        SetPatterns(specialButtons[1], new[] {
            chosenPatterns[specialButtons[0]],
            chosenColors[0, specialButtons[0]],
            chosenColors[1, specialButtons[0]]
        });

        var checkPatterns = new int[3];

        do
        {
            checkPatterns = GetPatterns();
        } while (new[] {
            chosenPatterns[specialButtons[0]],
            chosenColors[0, specialButtons[0]],
            chosenColors[1, specialButtons[0]]
        }.SequenceEqual(checkPatterns) || new[] {
            chosenPatterns[specialButtons[0]],
            chosenColors[1, specialButtons[0]],
            chosenColors[0, specialButtons[0]]
        }.SequenceEqual(checkPatterns));

        SetPatterns(specialButtons[2], checkPatterns);
        SetPatterns(specialButtons[3], new[] {
            chosenPatterns[specialButtons[2]],
            chosenColors[1, specialButtons[2]],
            chosenColors[0, specialButtons[2]]
        });

        Debug.LogFormat(@"[Colorful Insanity #{0}] 1st pair is in: {1}", moduleId, specialButtons.Skip(2).Select(x => x.ToCoord(7)).Join(", "));
        Debug.LogFormat(@"[Colorful Insanity #{0}] 2nd pair is in: {1}", moduleId, specialButtons.Take(2).Select(x => x.ToCoord(7)).Join(", "));

        checkSame[] getSame =
        {
            ((w,                      x,                  y, z) => Enumerable.Range(0, y).Any(a => (new[] {
                w[a],
                x[0,                  a],
                x[1,                  a]
            }.SequenceEqual(z) || new[] {
                w[a],
                x[1,                  a],
                x[0,                  a]
            }.SequenceEqual(z)))),
            ((w,                      x,                  y, z) => Enumerable.Range(0, y).Any(a => (new[] {
                w[specialButtons[a]],
                x[0,                  specialButtons[a]],
                x[1,                  specialButtons[a]]
            }.SequenceEqual(z) || new[] {
                w[specialButtons[a]],
                x[1,                  specialButtons[a]],
                x[0,                  specialButtons[a]]
            }.SequenceEqual(z))))
        };

        for (int i = 0; i < ModuleButtons.Length; i++)
        {
            if (!specialButtons.Contains(i))
            {
                do
                {
                    checkPatterns = GetPatterns();
                } while (getSame[0](chosenPatterns, chosenColors, i, checkPatterns) || getSame[1](chosenPatterns, chosenColors, specialButtons.Length, checkPatterns));

                SetPatterns(i, checkPatterns);
            }

            AssignPattern(i);
            int j = i;
            ModuleButtons[i].OnInteract += delegate() {
                OnButtonPress(j);

                return(false);
            };
        }

        var patternPos = Array.IndexOf(nowPatterns, chosenPatterns[specialButtons[2]]);

        correctPatterns = GetNearPatterns(patternPos);
        Debug.LogFormat(@"[Colorful Insanity #{0}] In the table, 1st pair's pattern is on: {1}", moduleId, patternPos.ToCoord(5));
        Debug.LogFormat(@"[Colorful Insanity #{0}] In the table, correct patterns are on: {1}", moduleId, correctPatterns.Select(x => Array.IndexOf(nowPatterns, x).ToCoord(5)).Join(", "));
        correctColors = nowColors[chosenColors[0, specialButtons[0]], chosenColors[1, specialButtons[0]]];
        string[] colorNames = { "", "Red", "Orange", "Yellow", "Green", "Cyan", "Azure", "Blue", "Magenta", "Purple" };
        Debug.LogFormat(@"[Colorful Insanity #{0}] Correct colors are: {1}", moduleId, (!correctColors.Equals("")) ? correctColors.Select(x => colorNames[Array.IndexOf(colorLetters, x.ToString())]).Join(", ") : "Any");

        for (int i = 0; i < ModuleButtons.Length; i++)
        {
            if (correctPatterns.Contains(chosenPatterns[i]) && (correctColors.Equals("") || Enumerable.Range(0, 2).Any(x => Enumerable.Range(0, correctColors.Length).Select(y => Array.IndexOf(colorLetters, correctColors[y].ToString()) - 1).ToArray().Contains(chosenColors[x, i]))))
            {
                correctTotal.Add(i);
            }
        }

        if (correctTotal.Count == 0)
        {
            correctTotal.AddRange(specialButtons);
            Debug.LogFormat(@"[Colorful Insanity #{0}] None of the buttons match. Buttons to press are the initial pairs.", moduleId);
        }
        else
        {
            Debug.LogFormat(@"[Colorful Insanity #{0}] Buttons to press are on: {1}", moduleId, correctTotal.Select(x => x.ToCoord(7)).Join(", "));
        }
    }
Esempio n. 17
0
    private List <Flag> generateFlags(int count, FlagDesign[] designs, MonoRandom rnd, string[] flagNames)
    {
        // Each design can be used different numbers of times
        var designIxsAvailable = new List <int>();

        for (var i = 0; i < designs.Length; i++)
        {
            var allowed =
                designs.Length == 4 ? 1 :
                designs[i].NumColors == 4 ? 1 :
                designs[i].NumColors == 2 && designs[i].ReverseAllowed ? 4 : 3;
            for (var j = 0; j < allowed; j++)
            {
                designIxsAvailable.Add(i);
            }
        }

        // Assign designs at random
        var flags             = new List <Flag>();
        var colorCombinations = new Dictionary <int, List <int[]> >();
        var availableColorIxs = Enumerable.Range(0, _colorGroups.Length).ToList();

        for (var i = 0; i < count; i++)
        {
            var ix       = rnd.Next(0, designIxsAvailable.Count);
            var designIx = designIxsAvailable[ix];
            designIxsAvailable.RemoveAt(ix);

            ColorInfo[] flagColors;

            if (designs[designIx].NumColors == 4)
            {
                // 4-color designs are allowed to have blue+black and/or yellow+white, but only in a specific order.
                flagColors = new ColorInfo[4];
                var fcIx = 0;
                rnd.ShuffleFisherYates(availableColorIxs);
                var ixIx = 0;
                while (fcIx < 4)
                {
                    for (var j = 0; j < _colorGroups[availableColorIxs[ixIx]].Length && fcIx < 4; j++)
                    {
                        flagColors[fcIx] = _colorGroups[availableColorIxs[ixIx]][j];
                        fcIx++;
                        if (fcIx % 2 == 0)
                        {
                            break;
                        }
                    }
                    ixIx++;
                }
            }
            else
            {
                // Find a random color combination that hasn’t been used yet.
                // Use only one color per group so we don’t get black+blue or yellow+white on the same flag.
                int[] colorIxs;
                do
                {
                    rnd.ShuffleFisherYates(availableColorIxs);
                    colorIxs = availableColorIxs.Take(designs[designIx].NumColors).ToArray();
                }while (colorCombinations.ContainsKey(designIx) && colorCombinations[designIx].Any(cc => cc.SequenceEqual(colorIxs) || (!designs[designIx].ReverseAllowed && cc.Reverse().SequenceEqual(colorIxs))));
                if (!colorCombinations.ContainsKey(designIx))
                {
                    colorCombinations[designIx] = new List <int[]>();
                }
                colorCombinations[designIx].Add(colorIxs);

                do
                {
                    flagColors = colorIxs.Select(cix => _colorGroups[cix][rnd.Next(0, _colorGroups[cix].Length)]).ToArray();
                }
                // Special case: don’t allow entirely black-and-white flags
                while (designs[designIx].NumColors == 2 && ((flagColors[0].Name == "black" && flagColors[1].Name == "white") || (flagColors[0].Name == "white" && flagColors[1].Name == "black")));
            }
            var cutout = designs[designIx].CutoutAllowed && (rnd.Next(0, 10) == 0);
            DebugLog("Flag {0} is {1}{2}", flagNames[i], string.Format(designs[designIx].NameFmt, flagColors.Select(cc => (object)cc.Name).ToArray()), cutout ? " with cutout" : "");
            flags.Add(new Flag(designs[designIx], flagColors, cutout: cutout));
        }
        return(flags);
    }
Esempio n. 18
0
    void HandleRuleSeedSupport()
    {
        trueStates = new bool[16, 4];
        if (ruleSeedCore == null)         // Check if there is a KMRuleSeedable script attached to this module
        {
            usedCharacters = hexDigits;
            Debug.LogWarningFormat("[Logical Operators #{0}]: Rule seed handler for Logical Operators do not exist, generating default settings...", modID);
            for (int x = 0; x < trueStates.GetLength(0); x++)
            {
                /* Reference thought, each hexdecimal has binary digits which can be used for logic operations
                 * 9: corresponds to 1001
                 * 8: corresponds to 1000
                 * 7: corresponds to 0111
                 * etc.
                 * These values are formatted as the following for the inputs: 11, 10, 01, 00
                 * 1 refers to the top bit on the module, 0 refers to the bottom bit on the module.
                 */

                for (int y = 0; y < trueStates.GetLength(1); y++)
                {
                    trueStates[x, trueStates.GetLength(1) - 1 - y] = x / powersOf2[y] % 2 == 1;
                }
                Debug.LogFormat("<Logical Operators #{0}>: Character '{1}' with states: {2}", modID,
                                usedCharacters[x],
                                new bool[] { trueStates[x, 0], trueStates[x, 1], trueStates[x, 2], trueStates[x, 3] }.Select(a => a ? "T" : "F").Join(""));
            }
            return;
        }
        // Section if KMRuleSeedable exists
        int[] binaryConvertedDigits = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
        baseIdxDisplayLetters = possibleCharacters.Select(a => possibleCharacters.IndexOf(a)).ToArray();
        MonoRandom nextRNG = ruleSeedCore.GetRNG();

        if (nextRNG.Seed != 1)
        {
            binaryConvertedDigits = nextRNG.ShuffleFisherYates(binaryConvertedDigits);
            usedCharacters        = nextRNG.ShuffleFisherYates(baseIdxDisplayLetters).Take(16).Select(a => possibleCharacters[a]).Join("");
        }
        else
        {
            usedCharacters = hexDigits;
        }
        Debug.LogFormat("[Logical Operators #{0}]: Rule seed handler for Logical Operators detected with rule seed {1}.", modID, nextRNG.Seed);
        // Assign each valid character on the list with a given value
        for (int x = 0; x < trueStates.GetLength(0); x++)
        {
            /* Reference thought, each hexdecimal has binary digits which can be used for logic operations
             * 9: corresponds to 1001
             * 8: corresponds to 1000
             * 7: corresponds to 0111
             * etc.
             * These values are formatted as the following for the inputs: 11, 10, 01, 00
             * 1 refers to the top bit on the module, 0 refers to the bottom bit on the module.
             */

            for (int y = 0; y < trueStates.GetLength(1); y++)
            {
                trueStates[x, trueStates.GetLength(1) - 1 - y] = binaryConvertedDigits[x] / powersOf2[y] % 2 == 1;
            }
            // Note, this is required for checking for any discrpencies with the manual provided.
            Debug.LogFormat("<Logical Operators #{0}>: Character '{1}' with states: {2}", modID,
                            usedCharacters[x],
                            new bool[] { trueStates[x, 0], trueStates[x, 1], trueStates[x, 2], trueStates[x, 3] }.Select(a => a ? "T" : "F").Join(""));
        }
    }