public static Rune[][] MakeSets(IList <Rune> runes, Predicate <Rune> evens, Predicate <Rune> odds, RuneSet[] reqsets = null)
        {
            Rune[][] runesSlot = new Rune[6][];

            Predicate <Rune> set = r => true;

            if (reqsets != null)
            {
                int reqCount = 0;
                foreach (RuneSet s in reqsets)
                {
                    reqCount += Rune.SetRequired(s);
                }

                if (reqCount == 6)
                {
                    set = r => reqsets.Any(s => s == r.Set);
                }
            }

            runesSlot[0] = runes.Where(r => r.Slot == 1 && !r.Locked && odds.Invoke(r) && set.Invoke(r)).ToArray();
            runesSlot[1] = runes.Where(r => r.Slot == 2 && !r.Locked && evens.Invoke(r) && set.Invoke(r)).ToArray();
            runesSlot[2] = runes.Where(r => r.Slot == 3 && !r.Locked && odds.Invoke(r) && set.Invoke(r)).ToArray();
            runesSlot[3] = runes.Where(r => r.Slot == 4 && !r.Locked && evens.Invoke(r) && set.Invoke(r)).ToArray();
            runesSlot[4] = runes.Where(r => r.Slot == 5 && !r.Locked && odds.Invoke(r) && set.Invoke(r)).ToArray();
            runesSlot[5] = runes.Where(r => r.Slot == 6 && !r.Locked && evens.Invoke(r) && set.Invoke(r)).ToArray();

            return(runesSlot);
        }
        public static Rune[][] MakeSets(IList <Rune> runes, Attr slot2, Attr slot4, Attr slot6, Predicate <Rune> odds, RuneSet[] reqsets = null)
        {
            Rune[][] runesSlot = new Rune[6][];

            Predicate <Rune> set = r => true;

            if (reqsets != null)
            {
                int reqCount = 0;
                foreach (RuneSet s in reqsets)
                {
                    reqCount += Rune.SetRequired(s);
                }

                if (reqCount == 6)
                {
                    set = r => reqsets.Any(s => s == r.Set);
                }
            }

            var unlocked = runes.Where(r => !r.Locked).ToArray();
            var sets     = unlocked.Where(r => set.Invoke(r)).ToArray();
            var odd      = sets.Where(r => odds.Invoke(r)).ToArray();

            runesSlot[0] = odd.Where(r => r.Slot == 1).ToArray();
            runesSlot[1] = sets.Where(r => r.Slot == 2 && (r.MainType == slot2 || slot2 == Attr.Null)).ToArray();
            runesSlot[2] = odd.Where(r => r.Slot == 3).ToArray();
            runesSlot[3] = sets.Where(r => r.Slot == 4 && (r.MainType == slot4 || slot4 == Attr.Null)).ToArray();
            runesSlot[4] = odd.Where(r => r.Slot == 5).ToArray();
            runesSlot[5] = sets.Where(r => r.Slot == 6 && (r.MainType == slot6 || slot6 == Attr.Null)).ToArray();

            foreach (Rune[] rs in runesSlot.Where(r => r.Length == 0))
            {
                Console.WriteLine("No runes for slot " + (runesSlot.ToList().IndexOf(rs) + 1) + ":(");
            }

            return(runesSlot);
        }
Example #3
0
        /// <summary>
        /// Generates builds based on the instances variables.
        /// </summary>
        /// <param name="top">If non-zero, runs until N builds are generated</param>
        /// <param name="time">If non-zero, runs for N seconds</param>
        /// <param name="printTo">Periodically gives progress% and if it failed</param>
        /// <param name="progTo">Periodically gives the progress% as a double</param>
        /// <param name="dumpBads">If true, will only track new builds if they score higher than an other found builds</param>
        public void GenBuilds(int top = 0, int time = 0, Action <string> printTo = null, Action <double> progTo = null, bool dumpBads = false, bool saveStats = false)
        {
            if (runes.Any(r => r == null))
            {
                return;
            }
            try
            {
                Best = null;
                SynchronizedCollection <Monster> tests = new SynchronizedCollection <Monster>();
                long count = 0;
                long total = runes[0].Count();
                total *= runes[1].Count();
                total *= runes[2].Count();
                total *= runes[3].Count();
                total *= runes[4].Count();
                total *= runes[5].Count();
                long complete = total;

                if (total == 0)
                {
                    if (printTo != null)
                    {
                        printTo.Invoke("0 perms");
                    }
                    Console.WriteLine("Zero permuations");
                    return;
                }
                if (!AllowBroken && BuildSets.Count == 1 && Rune.SetRequired(BuildSets[0]) == 4)
                {
                    if (printTo != null)
                    {
                        printTo.Invoke("Bad sets");
                    }
                    Console.WriteLine("Cannot use 4 set with no broken");
                    return;
                }

                bool hasSort = false;
                foreach (string stat in statNames)
                {
                    if (Sort[stat] != 0)
                    {
                        hasSort = true;
                        break;
                    }
                }
                foreach (string extra in extraNames)
                {
                    if (Sort.ExtraGet(extra) != 0)
                    {
                        hasSort = true;
                        break;
                    }
                }
                if (top == 0 && !hasSort)
                {
                    if (printTo != null)
                    {
                        printTo.Invoke("No sort");
                    }
                    Console.WriteLine("No method of determining best");
                    return;
                }

                DateTime begin = DateTime.Now;
                DateTime timer = DateTime.Now;

                Console.WriteLine(count + "/" + total + "  " + string.Format("{0:P2}", (count + complete - total) / (double)complete));

                // build the scoring function
                Func <Stats, double> sort = (m) =>
                {
                    double pts = 0;

                    foreach (string stat in statNames)
                    {
                        // if this stat is used for sorting
                        if (Sort[stat] != 0)
                        {
                            // sum points for the stat
                            pts += m[stat] / Sort[stat];
                            // if exceeding max, subtracted the gained points and then some
                            if (Threshold[stat] != 0)
                            {
                                pts -= Math.Max(0, m[stat] - Threshold[stat]) / Sort[stat];
                            }
                        }
                    }
                    // look, cool metrics!
                    foreach (string extra in extraNames)
                    {
                        if (Sort.ExtraGet(extra) != 0)
                        {
                            pts += m.ExtraValue(extra) / Sort.ExtraGet(extra);
                            if (Threshold.ExtraGet(extra) != 0)
                            {
                                pts -= Math.Max(0, m.ExtraValue(extra) - Threshold.ExtraGet(extra)) / Sort.ExtraGet(extra);
                            }
                        }
                    }

                    return(pts);
                };

                int[]  slotFakes = new int[6];
                bool[] slotPred  = new bool[6];

                // crank the rune prediction
                for (int i = 0; i < 6; i++)
                {
                    Rune[] rs          = runes[i];
                    int    raiseTo     = 0;
                    bool   predictSubs = false;

                    // find the largest number to raise to
                    // if any along the tree say to predict, do it
                    if (runePrediction.ContainsKey("g"))
                    {
                        int glevel = runePrediction["g"].Key;
                        if (glevel > raiseTo)
                        {
                            raiseTo = glevel;
                        }
                        predictSubs |= runePrediction["g"].Value;
                    }
                    if (runePrediction.ContainsKey(((i % 2 == 0) ? "o" : "e")))
                    {
                        int mlevel = runePrediction[((i % 2 == 0) ? "o" : "e")].Key;
                        if (mlevel > raiseTo)
                        {
                            raiseTo = mlevel;
                        }
                        predictSubs |= runePrediction[((i % 2 == 0) ? "o" : "e")].Value;
                    }
                    if (runePrediction.ContainsKey((i + 1).ToString()))
                    {
                        int slevel = runePrediction[(i + 1).ToString()].Key;
                        if (slevel > raiseTo)
                        {
                            raiseTo = slevel;
                        }
                        predictSubs |= runePrediction[(i + 1).ToString()].Value;
                    }

                    slotFakes[i] = raiseTo;
                    slotPred[i]  = predictSubs;
                }

                // set to running
                isRun = true;

                // Parallel the outer loop
                var loopRes = Parallel.ForEach <Rune>(runes[0], (r0, loopState) =>
                {
                    if (!isRun)
                    {
                        //break;
                        loopState.Break();
                    }

                    // number of builds ruled out since last sync
                    int kill = 0;
                    // number of builds added since last sync
                    int plus = 0;

                    foreach (Rune r1 in runes[1])
                    {
                        if (!isRun) // Can't break to a lable, don't want to goto
                        {
                            break;
                        }
                        foreach (Rune r2 in runes[2])
                        {
                            if (!isRun)
                            {
                                break;
                            }
                            foreach (Rune r3 in runes[3])
                            {
                                if (!isRun)
                                {
                                    break;
                                }
                                foreach (Rune r4 in runes[4])
                                {
                                    if (!isRun)
                                    {
                                        break;
                                    }
                                    foreach (Rune r5 in runes[5])
                                    {
                                        if (!isRun)
                                        {
                                            break;
                                        }

                                        Monster test         = new Monster(mon);
                                        test.Current.shrines = shrines;
                                        test.Current.leader  = leader;

                                        test.Current.FakeLevel   = slotFakes;
                                        test.Current.PredictSubs = slotPred;

                                        test.ApplyRune(r0);
                                        test.ApplyRune(r1);
                                        test.ApplyRune(r2);
                                        test.ApplyRune(r3);
                                        test.ApplyRune(r4);
                                        test.ApplyRune(r5);

                                        if (saveStats)
                                        {
                                            foreach (Rune r in test.Current.runes)
                                            {
                                                r.manageStats_LoadGen++;
                                            }
                                        }

                                        var cstats = test.GetStats();

                                        bool maxdead = false;

                                        if (Maximum != null)
                                        {
                                            foreach (var stat in statNames)
                                            {
                                                if (Maximum[stat] > 0 && cstats[stat] > Maximum[stat])
                                                {
                                                    maxdead = true;
                                                    break;
                                                }
                                            }
                                        }

                                        // check if build meets minimum
                                        if (Minimum != null && !(cstats > Minimum))
                                        {
                                            kill++;
                                        }
                                        else if (maxdead)
                                        {
                                            kill++;
                                        }
                                        // if no broken sets, check for broken sets
                                        else if (!AllowBroken && !test.Current.SetsFull)
                                        {
                                            kill++;
                                        }
                                        // if there are required sets, ensure we have them
                                        else if (RequiredSets != null && RequiredSets.Count > 0 && !RequiredSets.All(s => test.Current.sets.Contains(s)))
                                        {
                                            kill++;
                                        }
                                        else
                                        {
                                            // we found an okay build!
                                            plus++;

                                            if (saveStats)
                                            {
                                                foreach (Rune r in test.Current.runes)
                                                {
                                                    r.manageStats_LoadFilt++;
                                                }
                                            }

                                            // if we are to track all good builds, keep it
                                            if (!dumpBads)
                                            {
                                                tests.Add(test);
                                            }
                                            else
                                            {
                                                //lock (tests)
                                                //{
                                                // if there are currently no good builds, keep it

                                                if (tests.FirstOrDefault() == null)
                                                {
                                                    tests.Add(test);
                                                    Best = test;
                                                }
                                                else
                                                {
                                                    if (Best.GetStats() < test.GetStats())
                                                    {
                                                        Best = test;
                                                        tests.Add(test);
                                                    }

                                                    // take a snapshot of the builds (multithread /may/ cause a "collection modified" excepion in next step)

                                                    /*var tt = tests.ToList();
                                                     * // if this build is better than any other build, keep it
                                                     * // can't just keep a copy of Max becaues of threading
                                                     * if (tt.Max(t => sort(t.GetStats())) < sort(test.GetStats()))
                                                     * {
                                                     *  tests.Add(test);
                                                     * }*/
                                                }
                                                //}
                                            }
                                        }

                                        // every second, give a bit of feedback to those watching
                                        if (DateTime.Now > timer.AddSeconds(1))
                                        {
                                            timer = DateTime.Now;
                                            Console.WriteLine(count + "/" + total + "  " + String.Format("{0:P2}", (double)(count + complete - total) / (double)complete));
                                            if (printTo != null)
                                            {
                                                printTo.Invoke(String.Format("{0:P2}", (double)(count + complete - total) / (double)complete));
                                            }
                                            if (progTo != null)
                                            {
                                                progTo.Invoke((double)(count + complete - total) / (double)complete);
                                            }

                                            if (time > 0)
                                            {
                                                if (DateTime.Now > begin.AddSeconds(time))
                                                {
                                                    isRun = false;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    // sum up what work we've done
                                    Interlocked.Add(ref total, -kill);
                                    kill = 0;
                                    Interlocked.Add(ref count, plus);
                                    plus = 0;

                                    // if we've got enough, stop
                                    if (top > 0 && count >= top)
                                    {
                                        isRun = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                });

                // write out completion
                Console.WriteLine(isRun + " " + count + "/" + total + "  " + String.Format("{0:P2}", (double)(count + complete - total) / (double)complete));
                if (printTo != null)
                {
                    printTo.Invoke("100%");
                }
                if (progTo != null)
                {
                    progTo.Invoke(1);
                }

                // sort *all* the builds
                loads = tests.Where(t => t != null).OrderByDescending(r => sort(r.GetStats())).Take((top > 0 ? top : 1));

                // dump everything to console, if nothing to print to
                if (printTo == null)
                {
                    foreach (var l in loads)
                    {
                        Console.WriteLine(l.GetStats().Health + "  " + l.GetStats().Attack + "  " + l.GetStats().Defense + "  " + l.GetStats().Speed
                                          + "  " + l.GetStats().CritRate + "%" + "  " + l.GetStats().CritDamage + "%" + "  " + l.GetStats().Resistance + "%" + "  " + l.GetStats().Accuracy + "%");
                    }
                }

                // sadface if no builds
                if (loads.Count() == 0)
                {
                    Console.WriteLine("No builds :(");
                    if (printTo != null)
                    {
                        printTo.Invoke("Zero :(");
                    }
                }
                else
                {
                    // remember the good one
                    Best = loads.First();
                    foreach (Rune r in Best.Current.runes)
                    {
                        r.manageStats_In = true;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error " + e);
                if (printTo != null)
                {
                    printTo.Invoke(e.ToString());
                }
            }
        }
Example #4
0
        /// <summary>
        /// Fills the instance with acceptable runes from save
        /// </summary>
        /// <param name="save">The Save data that contais the runes</param>
        /// <param name="useLocked">If it should include locked runes</param>
        /// <param name="useEquipped">If it should include equipped runes (other than the current monster)</param>
        public void GenRunes(Save save, bool useLocked = false, bool useEquipped = false, bool saveStats = false)
        {
            if (save == null)
            {
                return;
            }
            if (save.Runes == null)
            {
                return;
            }

            IEnumerable <Rune> rsGlobal = save.Runes;

            // Only using 'inventory' or runes on mon
            if (!useEquipped)
            {
                rsGlobal = rsGlobal.Where(r => (r.AssignedName == "Unknown name" || r.AssignedName == mon.Name));
            }
            // only if the rune isn't currently locked for another purpose
            if (!useLocked)
            {
                rsGlobal = rsGlobal.Where(r => r.Locked == false);
            }

            // Only runes which we've included
            rsGlobal = rsGlobal.Where(r => BuildSets.Contains(r.Set));

            if (saveStats)
            {
                foreach (Rune r in rsGlobal)
                {
                    r.manageStats_Set++;
                }
            }

            int[]  slotFakes = new int[6];
            bool[] slotPred  = new bool[6];

            // For each runeslot
            for (int i = 0; i < 6; i++)
            {
                // put the right ones in
                runes[i] = rsGlobal.Where(r => r.Slot == i + 1).ToArray();

                // crank the rune prediction
                Rune[] rs          = runes[i];
                int    raiseTo     = 0;
                bool   predictSubs = false;

                // find the largest number to raise to
                // if any along the tree say to predict, do it
                if (runePrediction.ContainsKey("g"))
                {
                    int glevel = runePrediction["g"].Key;
                    if (glevel > raiseTo)
                    {
                        raiseTo = glevel;
                    }
                    predictSubs |= runePrediction["g"].Value;
                }
                if (runePrediction.ContainsKey(((i % 2 == 0) ? "o" : "e")))
                {
                    int mlevel = runePrediction[((i % 2 == 0) ? "o" : "e")].Key;
                    if (mlevel > raiseTo)
                    {
                        raiseTo = mlevel;
                    }
                    predictSubs |= runePrediction[((i % 2 == 0) ? "o" : "e")].Value;
                }
                if (runePrediction.ContainsKey((i + 1).ToString()))
                {
                    int slevel = runePrediction[(i + 1).ToString()].Key;
                    if (slevel > raiseTo)
                    {
                        raiseTo = slevel;
                    }
                    predictSubs |= runePrediction[(i + 1).ToString()].Value;
                }

                slotFakes[i] = raiseTo;
                slotPred[i]  = predictSubs;


                // default fail OR
                Predicate <Rune> slotTest = r => false;
                int and = 0;
                // this means that runes won't get in unless they meet at least 1 criteria

                // which tab we pulled the filter from
                string gotScore = "";
                // the value to test SUM against
                int testVal = 0;

                // TODO: check what inheriting SUM (eg. Odd and 3) does
                // TODO: check what inheriting AND/OR then SUM (or visa versa)

                // find the most significant operatand of joining checks
                if (runeScoring.ContainsKey("g") && runeFilters.ContainsKey("g") && runeFilters["g"].Any(r => r.Value.NonZero))
                {
                    var kv = runeScoring["g"];
                    gotScore = "g";
                    and      = kv.Key;
                    if (kv.Key == 1)
                    {
                        slotTest = r => true;
                    }
                    else if (kv.Key == 2)
                    {
                        testVal = kv.Value;
                    }
                }
                // is it and odd or even slot?
                string tmk = (i % 2 == 1 ? "e" : "o");
                if (runeScoring.ContainsKey(tmk) && runeFilters.ContainsKey(tmk) && runeFilters[tmk].Any(r => r.Value.NonZero))
                {
                    var kv = runeScoring[tmk];
                    gotScore = tmk;
                    and      = kv.Key;
                    if (kv.Key == 1)
                    {
                        slotTest = r => true;
                    }
                    else if (kv.Key == 2)
                    {
                        testVal = kv.Value;
                    }
                }
                // turn the 0-5 to a 1-6
                tmk = (i + 1).ToString();
                if (runeScoring.ContainsKey(tmk) && runeFilters.ContainsKey(tmk) && runeFilters[tmk].Any(r => r.Value.NonZero))
                {
                    var kv = runeScoring[tmk];
                    gotScore = tmk;
                    and      = kv.Key;
                    if (kv.Key == 1)
                    {
                        slotTest = r => true;
                    }
                    else if (kv.Key == 2)
                    {
                        testVal = kv.Value;
                    }
                }


                // if an operand was found, ensure the tab contains filter data
                if (gotScore != "")
                {
                    if (runeFilters.ContainsKey(gotScore))
                    {
                        // if all the filters for the tab are zero
                        if (runeFilters[gotScore].All(r => !r.Value.NonZero))
                        {
                            // set to OR TRUE
                            slotTest = r => true;
                            and      = 0;
                        }
                    }
                }
                else
                {
                    // if there wasn't any relevant data for how to pick runes, just take 'em all!
                    slotTest = r => true;
                }

                // pull the filters (flat, perc, test) for all the tabs and stats
                Dictionary <string, RuneFilter> rfG = new Dictionary <string, RuneFilter>();
                if (runeFilters.ContainsKey("g"))
                {
                    rfG = runeFilters["g"];
                }

                Dictionary <string, RuneFilter> rfM = new Dictionary <string, RuneFilter>();
                if (runeFilters.ContainsKey((i % 2 == 1 ? "e" : "o")))
                {
                    rfM = runeFilters[(i % 2 == 1 ? "e" : "o")];
                }

                Dictionary <string, RuneFilter> rfS = new Dictionary <string, RuneFilter>();
                if (runeFilters.ContainsKey((i + 1).ToString()))
                {
                    rfS = runeFilters[(i + 1).ToString()];
                }

                // if there where no filters with data
                bool blank = true;

                Stats rFlat = new Stats();
                Stats rPerc = new Stats();
                Stats rTest = new Stats();

                foreach (string stat in statNames)
                {
                    RuneFilter rf = new RuneFilter();
                    if (rfS.ContainsKey(stat))
                    {
                        rf = rfS[stat];
                        if (rfM.ContainsKey(stat))
                        {
                            rf = RuneFilter.Min(rf, rfM[stat]);
                        }

                        if (rfG.ContainsKey(stat))
                        {
                            rf = RuneFilter.Min(rf, rfG[stat]);
                        }
                    }
                    else
                    {
                        if (rfM.ContainsKey(stat))
                        {
                            rf = rfM[stat];
                            if (rfG.ContainsKey(stat))
                            {
                                rf = RuneFilter.Min(rf, rfG[stat]);
                            }
                        }
                        else
                        {
                            if (rfG.ContainsKey(stat))
                            {
                                rf = rfG[stat];
                            }
                        }
                    }
                    if (rf.NonZero)
                    {
                        // put the most relevant divisor in?
                        rFlat[stat] = rf.Flat;
                        rPerc[stat] = rf.Percent;
                        rTest[stat] = rf.Test;
                        blank       = false;
                    }
                }

                // TODO: seems like it just ignores all the slotTesting before now

                // no filter data = use all
                if (blank)
                {
                    slotTest = r => true;
                }
                else
                {
                    // Set the test based on the type found
                    if (and == 0)
                    {
                        slotTest = r => r.Or(rFlat, rPerc, rTest, raiseTo, predictSubs);
                    }
                    else if (and == 1)
                    {
                        slotTest = r => r.And(rFlat, rPerc, rTest, raiseTo, predictSubs);
                    }
                    else if (and == 2)
                    {
                        slotTest = r => r.Test(rFlat, rPerc, raiseTo, predictSubs) >= testVal;
                    }
                }
                runes[i] = runes[i].Where(r => slotTest.Invoke(r)).ToArray();

                if (saveStats)
                {
                    foreach (Rune r in runes[i])
                    {
                        r.manageStats_RuneFilt++;
                    }
                }

                if (i % 2 == 1) // actually evens because off by 1
                {
                    // makes sure that the primary stat type is in the selection
                    if (slotStats[i].Count > 0)
                    {
                        runes[i] = runes[i].Where(r => slotStats[i].Contains(r.MainType.ToForms())).ToArray();
                    }
                }

                if (saveStats)
                {
                    foreach (Rune r in runes[i])
                    {
                        r.manageStats_TypeFilt++;
                    }
                }
            }

            // Make sure that for each set type, there are enough slots with runes in them
            // Eg. if only 1,4,5 have Violent, remove all violent runes because you need 4
            // for each included set
            foreach (RuneSet s in BuildSets)
            {
                // find how many slots have acceptable runes for it
                int slots = 0;
                for (int i = 0; i < 6; i++)
                {
                    if (runes[i].Any(r => r.Set == s))
                    {
                        slots += 1;
                    }
                }
                // if there isn't enough slots
                if (slots < Rune.SetRequired(s))
                {
                    // remove that set
                    for (int i = 0; i < 6; i++)
                    {
                        runes[i] = runes[i].Where(r => r.Set != s).ToArray();
                    }
                }
            }
        }
Example #5
0
        // Check what sets are completed in this build
        public void CheckSets()
        {
            SetsFull = false;

            // If there are an odd number of runes, don't bother (maybe even check < 6?)
            if (runeCount % 2 == 1)
            {
                return;
            }

            // can only have 3 sets max (eg. energy / energy / blade)
            sets = new RuneSet[3];

            // which set we are looking for
            int setInd = 0;
            // what slot we are looking at
            int slotInd = 0;

            // if we have used this slot in a set yet
            bool[] used = new bool[6];

            // how many runes are in sets
            int setNums = 0;

            // Check slots 1 - 5, minimum set size is 2.
            // Because it will search forward for sets, can't find more from 6
            // Eg. starting from 6, working around, find 2 runes?
            for (; slotInd < 5; slotInd++)
            {
                //if there is a uncounted rune in this slot
                Rune rune = runes[slotInd];
                if (rune != null && used[slotInd] == false)
                {
                    // look for more in the set
                    RuneSet set = rune.Set;
                    // how many runes we need to get
                    int getNum = Rune.SetRequired(set);
                    // how many we got
                    int gotNum = 1;
                    // we have now used this slot
                    used[slotInd] = true;

                    // for the runes after this rune
                    for (int ind = slotInd + 1; ind < 6; ind++)
                    {
                        // if there is a rune in this slot
                        if (runes[ind] != null)
                        {
                            // that hasn't been counted
                            if (used[ind] == false)
                            {
                                // that is the type I want
                                if (runes[ind].Set == set)
                                {
                                    used[ind] = true;
                                    gotNum++;
                                }
                            }
                        }

                        // if we have more than 1 rune
                        if (gotNum > 1)
                        {
                            // if we have enough runes for a set
                            if (gotNum == getNum)
                            {
                                // log this set
                                sets[setInd] = set;
                                // increase the number of runes in sets
                                setNums += getNum;
                                // look for the next set
                                setInd++;
                                // stop looking forward
                                break;
                            }
                        }
                    }
                }
            }

            // if all runes are in sets
            if (setNums == 6)
            {
                SetsFull = true;
            }
            // notify hackers their attempt has failed
            else if (setNums > 6)
            {
                throw new Exception("Wut");
            }
        }