Ejemplo n.º 1
0
        void button4_Click_1(object sender, EventArgs e)
        {
            btnDL6star.Enabled = false;
            var mref = MonsterStat.FindMon(Build.Mon);

            if (mref != null)
            {
                var mstat  = mref.Download();
                var newmon = mstat.GetMon(Build.Mon);
                Build.Mon = newmon;
                refreshStats(newmon, newmon.GetStats());
            }
            btnDL6star.Enabled = true;
        }
Ejemplo n.º 2
0
        void button5_Click_1(object sender, EventArgs e)
        {
            btnDLawake.Enabled = false;
            var mref = MonsterStat.FindMon(build.Mon);

            if (mref != null)
            {
                var mstat = mref.Download();
                if (!mstat.Awakened && mstat.AwakenTo != null)
                {
                    mstat = mstat.AwakenTo.Download();
                    var newmon = mstat.GetMon(build.Mon);
                    build.Mon = newmon;
                    refreshStats(newmon, newmon.GetStats());
                }
            }
            btnDLawake.Enabled = true;
        }
        static ServedResult renderMagicList()
        {
            // return all completed loads on top, in progress build, unrun builds, mons with no builds
            ServedResult list = new ServedResult("ul");

            list.contentList = new List <ServedResult>();
            if (Program.data == null)
            {
                return("no");
            }

            var pieces = Program.data.InventoryItems.Where(i => i.Type == ItemType.SummoningPieces)
                         .Select(p => new InventoryItem()
            {
                Id = p.Id, Quantity = p.Quantity, Type = p.Type, WizardId = p.WizardId
            }).ToDictionary(p => p.Id);

            foreach (var p in pieces)
            {
                pieces[p.Key].Quantity -= Save.getPiecesRequired(p.Value.Id);
            }
            pieces = pieces.Where(p => p.Value.Quantity > Save.getPiecesRequired(p.Value.Id)).ToDictionary(p => p.Key, p => p.Value);

            var ll   = Program.loads;
            var ldic = ll.ToDictionary(l => l.BuildID);

            var bq = Program.builds.Where(b => !ldic.ContainsKey(b.ID));
            var bb = new List <Build>();

            foreach (var b in bq)
            {
                if (!bb.Any(u => u.MonId == b.MonId))
                {
                    bb.Add(b);
                }
            }

            var bdic = bb.ToDictionary(b => b.MonId);

            var remids = Program.goals.ReservedIds.Where(i => Program.data.GetMonster(i) == null).ToList();

            foreach (var i in remids)
            {
                Program.goals.ReservedIds.Remove(i);
            }
            var reserved = Program.goals.ReservedIds.Select(id => Program.data.GetMonster(id)).Where(m => m != null).ToList();
            //reserved = reserved.Union(Program.data.Monsters.Where(m => !m.Locked && !bdic.ContainsKey(m.Id) && MonsterStat.FindMon(m).isFusion).GroupBy(m => m.monsterTypeId).Select(m => m.First())).Distinct();

            var monunNull = Program.data.Monsters.Where(m => m != null);


            var fuss = monunNull.Where(m => !m.Locked && !bdic.ContainsKey(m.Id) && MonsterStat.FindMon(m).isFusion).OrderByDescending(m => m.awakened).ThenByDescending(m => m.Grade).ThenByDescending(m => m.level);
            // TODO: pull these from goals
            var nKfg  = 1;           // 6 - fuss.Count(m => m.Id.ToString().StartsWith("173") && m.Element == Element.Wind);
            var nJojo = 1;
            var dict  = new Dictionary <string, int>();

            // TODO: get fuse recipes from somewhere else
            foreach (var m in fuss)
            {
                var idk = m.monsterTypeId.ToString().Substring(0, 3);
                if (!dict.ContainsKey(idk))
                {
                    dict.Add(idk, 0);
                }
                var mname = m.monsterTypeId.ToString();
                if (dict[idk] < nKfg && !reserved.Contains(m))
                {
                    if ((mname.StartsWith("110") && m.Element == Element.Fire) ||
                        (mname.StartsWith("102") && m.Element == Element.Water) ||
                        (mname.StartsWith("195") && m.Element == Element.Wind) ||
                        (mname.StartsWith("160") && m.Element == Element.Wind))
                    {
                        reserved.Add(m);

                        dict[idk]++;
                    }
                }
                if (dict[idk] < nJojo && !reserved.Contains(m))
                {
                    if ((mname.StartsWith("154") && m.Element == Element.Fire) ||
                        (mname.StartsWith("140") && m.Element == Element.Fire) ||
                        (mname.StartsWith("114") && m.Element == Element.Water) ||
                        (mname.StartsWith("132") && m.Element == Element.Wind))
                    {
                        reserved.Add(m);
                        dict[idk]++;
                    }
                }

                if (!reserved.Any(r => r.monsterTypeId.ToString().Substring(0, 3) == m.monsterTypeId.ToString().Substring(0, 3)))
                {
                    reserved.Add(m);
                }
            }

            var mm = monunNull.Where(m => !bdic.ContainsKey(m.Id)).Except(reserved);

            var locked   = monunNull.Where(m => m.Locked).Union(bb.Select(b => b.Mon).Where(m => m != null)).Except(reserved).ToList();
            var unlocked = monunNull.Except(locked).Except(reserved).ToList();

            var trashOnes = unlocked.Where(m => m.Grade == 1 && !m.Name.Contains("Devilmon") && !m.FullName.Contains("Angelmon")).ToList();

            unlocked = unlocked.Except(trashOnes).ToList();

            var pairs = new Dictionary <Monster, List <Monster> >();
            var rem   = new List <Monster>();

            foreach (var m in locked.Where(m => !Program.goals.NoSkillIds.Contains(m.Id)).OrderByDescending(m => 1 / (bb.FirstOrDefault(b => b.Mon == m)?.Priority ?? m.priority - 0.1)).ThenByDescending(m => m.Grade)
                     .ThenByDescending(m => m.level)
                     .ThenBy(m => m.Element)
                     .ThenByDescending(m => m.awakened)
                     .ThenBy(m => m.loadOrder))
            {
                pairs.Add(m, new List <Monster>());
                int i = Math.Min(m.Grade, m.SkillupsTotal - m.SkillupsLevel);
                for (; i > 0; i--)
                {
                    Monster um = null;
                    if (m.level == m.Grade * 5 + 10)
                    {
                        um = unlocked
                             .Where(ul => (ul.Grade == m.Grade && ul.level == 1) || ul.Grade == m.Grade - 1)
                             .OrderByDescending(ul => ul.level)
                             .FirstOrDefault(ul => ul.monsterTypeId.ToString().Substring(0, 3) == m.monsterTypeId.ToString().Substring(0, 3));
                    }
                    else
                    {
                        um = unlocked
                             .Where(ul => ul.level == 1)
                             .OrderBy(ul => ul.Grade)
                             .FirstOrDefault(ul => ul.monsterTypeId.ToString().Substring(0, 3) == m.monsterTypeId.ToString().Substring(0, 3));
                    }

                    if (um == null)
                    {
                        break;
                    }
                    pairs[m].Add(um);
                    rem.Add(um);
                    unlocked.Remove(um);
                }
            }
            foreach (var m in locked.Where(m => !Program.goals.NoSkillIds.Contains(m.Id)).OrderByDescending(m => 1 / (bb.FirstOrDefault(b => b.Mon == m)?.Priority ?? m.priority - 0.1)).ThenByDescending(m => m.Grade)
                     .ThenByDescending(m => m.level)
                     .ThenBy(m => m.Element)
                     .ThenByDescending(m => m.awakened)
                     .ThenBy(m => m.loadOrder))
            {
                if (!pairs.ContainsKey(m))
                {
                    pairs.Add(m, new List <Monster>());
                }
                int i = m.SkillupsTotal - m.SkillupsLevel - pairs[m].Count;
                for (; i > 0; i--)
                {
                    Monster um = null;
                    if (m.level == m.Grade * 5 + 10)
                    {
                        um = unlocked
                             .OrderByDescending(ul => ul.Grade == m.Grade && ul.level == 1)
                             .ThenByDescending(ul => ul.Grade == m.Grade - 1)
                             .ThenByDescending(ul => ul.level)
                             .FirstOrDefault(ul => ul.monsterTypeId.ToString().Substring(0, 3) == m.monsterTypeId.ToString().Substring(0, 3));
                    }
                    else
                    {
                        um = unlocked
                             .Where(ul => ul.level == 1)
                             .OrderBy(ul => ul.Grade)
                             .FirstOrDefault(ul => ul.monsterTypeId.ToString().Substring(0, 3) == m.monsterTypeId.ToString().Substring(0, 3));
                    }

                    if (um == null)
                    {
                        break;
                    }
                    pairs[m].Add(um);
                    rem.Add(um);
                    unlocked.Remove(um);
                }
                bool[] zerop = new bool[5];
                while (i > 0 && !zerop.All(p => p))
                {
                    for (int j = 1; j < 6; j++)
                    {
                        int monbase = (m.monsterTypeId / 100) * 100;
                        if (pieces.ContainsKey(monbase + j) && pieces[monbase + j].Quantity >= Save.getPiecesRequired(pieces[monbase + j].Id))
                        {
                            pieces[monbase + j].Quantity -= Save.getPiecesRequired(pieces[monbase + j].Id);
                            pairs[m].Add(new Monster()
                            {
                                Element = pieces[monbase + j].Element, Name = pieces[monbase + j].Name + " Pieces (" + pieces[monbase + j].Quantity + " remain)"
                            });
                            i--;
                        }
                        else
                        {
                            zerop[j - 1] = true;
                        }
                        if (i <= 0)
                        {
                            break;
                        }
                    }
                }
            }

            mm = mm.Except(bb.Select(b => b.Mon));
            mm = mm.Except(Program.builds.Select(b => b.Mon));
            mm = mm.Except(pairs.SelectMany(p => p.Value));
            mm = mm.Except(rem);

            trashOnes = trashOnes.Concat(mm.Where(m => !pairs.ContainsKey(m) && !m.Locked && !m.Name.Contains("Devilmon") && !m.FullName.Contains("Angelmon"))).ToList();
            mm        = mm.Except(trashOnes);

            mm = mm.OrderByDescending(m => !unlocked.Contains(m))
                 .ThenByDescending(m => m.Locked)
                 .ThenByDescending(m => m.Grade)
                 .ThenByDescending(m => m.level)
                 .ThenBy(m => m.Element)
                 .ThenByDescending(m => m.awakened)
                 .ThenBy(m => m.loadOrder)
            ;

            list.contentList.AddRange(ll.Select(l => renderLoad(l, pairs)));

            list.contentList.AddRange(bb.Select(b => {
                var m  = b.Mon;
                var nl = new ServedResult("ul");
                var li = new ServedResult("li")
                {
                    contentList =
                    {
                        new ServedResult("span")
                        {
                            contentList ={ renderMonLink(m,                   "build") }
                        }, nl
                    }
                };
                if (pairs.ContainsKey(m))
                {
                    nl.contentList.AddRange(pairs?[m]?.Select(mo => new ServedResult("li")
                    {
                        contentList = { renderMonLink(mo, "- ", LinkRenderOptions.Grade | LinkRenderOptions.Level) }
                    }));
                }
                if (nl.contentList.Count == 0)
                {
                    nl.name = "br";
                }
                return(li);
            }
                                                ));

            list.contentList.AddRange(mm.Select(m => {
                var nl    = new ServedResult("ul");
                var stars = new StringBuilder();
                for (int s = 0; s < m.Grade; s++)
                {
                    stars.Append("<img class='star' src='/runes/star_unawakened.png' >");                     //style='left: -" + (0.3*s) + "em'
                }
                var li = new ServedResult("li")
                {
                    contentList = { ((unlocked.Contains(m)) ?
                                     renderMonLink(m,          "TRASH: ", LinkRenderOptions.Grade | LinkRenderOptions.Level) :
                                     renderMonLink(m,          "mon")), nl }
                };
                if (!unlocked.Contains(m) && pairs.ContainsKey(m))
                {
                    nl.contentList.AddRange(pairs?[m]?.Select(mo => new ServedResult("li")
                    {
                        contentList = { renderMonLink(mo, "- ", LinkRenderOptions.Grade | LinkRenderOptions.Level) }
                    }));
                }
                if (nl.contentList.Count == 0)
                {
                    nl.name = "br";
                }
                return(li);
            }));
            list.contentList.AddRange(reserved.GroupBy(mg => mg.monsterTypeId).Select(mg => {
                var li = new ServedResult("li");
                li.contentList.Add(new ServedResult(mg.AtLeast(2) ? "a" : "span")
                {
                    contentDic  = { { "href", "\"javascript:showhide('g" + mg.First().Id + "')\"" } },
                    contentList = { "Reserved:" }
                });
                li.contentList.Add(renderMonLink(mg.First(), mg.Count() + "x ", LinkRenderOptions.All));
                if (mg.AtLeast(2))
                {
                    li.contentList.Add(new ServedResult("ul")
                    {
                        contentDic =
                        {
                            { "id",    "g" + mg.First().Id.ToString() },
                            { "style", "'display: none;'"             }
                        },
                        contentList = mg.Skip(1).Select(m => {
                            return(new ServedResult("li")
                            {
                                contentList = { renderMonLink(m) }
                            });
                        }).ToList()
                    });
                }
                return(li);
            }));

            //
            var food = trashOnes.OrderBy(t => t.Grade).ThenBy(t => t.Element).ThenByDescending(t => t.monsterTypeId).Select(m => new Food()
            {
                mon = m, fakeLevel = m.Grade
            }).ToList();

            food = makeFood(2, food);
            food = makeFood(3, food);
            food = makeFood(4, food);

            list.contentList.AddRange(food.OrderByDescending(f => f.food.Count).ThenByDescending(f => f.fakeLevel).Select(f => recurseFood(f)).ToList());

            return(list);
        }
Ejemplo n.º 4
0
		public BuildResult GenBuilds(string prefix = "") {
			if (Type == BuildType.Lock) {
				Best = new Monster(Mon, true);
				return BuildResult.Success;
			}
			else if (Type == BuildType.Link) {
				if (LinkBuild == null) {
					for (int i = 0; i < 6; i++)
						runes[i] = new Rune[0];
					return BuildResult.Failure;
				}
				else {
					CopyFrom(LinkBuild);
				}
			}

			if (runes.Any(r => r == null)) {
				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Null rune"));
				return BuildResult.BadRune;
			}
			if (!BuildSaveStats)
				BuildGoodRunes = false;

			if (!BuildGoodRunes) {
				RuneUsage = new RuneUsage();
				BuildUsage = new BuildUsage();
			}
			try {
				// if to get awakened
				if (DownloadAwake && !Mon.downloaded) {
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Downloading Awake def"));
					var mref = MonsterStat.FindMon(Mon);
					if (mref != null) {
						// download the current (unawakened monster)
						var mstat = mref.Download();
						BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Reading stats"));
						// if the retrieved mon is unawakened, get the awakened
						if (!mstat.Awakened && mstat.AwakenTo != null) {
							BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Awakening"));
							Mon = mstat.AwakenTo.Download().GetMon(Mon);
						}
					}
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Downloaded"));
				}
				// getting awakened also gets level 40, so...
				// only get lvl 40 stats if the monster isn't 40, wants to download AND isn't already downloaded (first and last are about the same)
				else if (Mon.level < 40 && DownloadStats && !Mon.downloaded) {
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Downloading 40 def"));
					var mref = MonsterStat.FindMon(Mon);
					if (mref != null)
						Mon = mref.Download().GetMon(Mon);
				}
			}
			catch (Exception e) {
				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Failed downloading def: " + e.Message + Environment.NewLine + e.StackTrace));
			}

			if (!getRunningHandle())
				throw new InvalidOperationException("The build is locked with another action.");
			
			Loads.Clear();

			if (!Sort[Attr.Speed].EqualTo(0) && Sort[Attr.Speed] <= 1 // 1 SPD is too good to pass
				|| Mon.Current.Runes.Any(r => r == null)
				|| !Mon.Current.Runes.All(r => runes[r.Slot - 1].Contains(r)) // only IgnoreLess5 if I have my own runes
				|| Sort.NonZeroStats.HasCount(1)) // if there is only 1 sorting, must be too important to drop???
				IgnoreLess5 = false;

			Thread timeThread = null;

			if (!string.IsNullOrWhiteSpace(BuildStrategy)) {

				var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.GetTypes().Where(t => typeof(IBuildStrategyDefinition).IsAssignableFrom(t)));

				var type = types.FirstOrDefault(t => t.AssemblyQualifiedName.Contains(BuildStrategy));
				if (type != null) {
					RunStrategy();
				}
			}

			tcs.TrySetResult(null);

			try {
				Best = null;
				Stats bstats = null;
				count = 0;
				actual = 0;
				total = runes[0].Length;
				total *= runes[1].Length;
				total *= runes[2].Length;
				total *= runes[3].Length;
				total *= runes[4].Length;
				total *= runes[5].Length;
				complete = total;

				Mon.ExtraCritRate = extraCritRate;
				Mon.GetStats();
				Mon.DamageFormula?.Invoke(Mon);

				int?[] slotFakesTemp = new int?[6];
				bool[] slotPred = new bool[6];
				getPrediction(slotFakesTemp, slotPred);

				int[] slotFakes = slotFakesTemp.Select(i => i ?? 0).ToArray();

				var currentLoad = new Monster(Mon, true);
				currentLoad.Current.TempLoad = true;
				currentLoad.Current.Buffs = Buffs;
				currentLoad.Current.Shrines = Shrines;
				currentLoad.Current.Leader = Leader;

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

				double currentScore = CalcScore(currentLoad.GetStats(true));

				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "cooking"));

				if (total == 0) {
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "0 perms"));
					RuneLog.Info("Zero permuations");
					return BuildResult.NoPermutations;
				}

				bool hasSort = Sort.IsNonZero;
				if (BuildTake == 0 && !hasSort) {
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "No sort"));
					RuneLog.Info("No method of determining best");
					return BuildResult.NoSorting;
				}

				DateTime begin = DateTime.Now;

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


				// set to running
				IsRunning = true;

#if BUILD_PRECHECK_BUILDS_DEBUG
				SynchronizedCollection<string> outstrs = new SynchronizedCollection<string>();
#endif
				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "..."));

				List<Monster> tests = new List<Monster>();

				timeThread = new Thread(() => {
					while (IsRunning) {
						if (RunesOnlyFillEmpty)
							Thread.Sleep(30 / ((Mon?.Current?.RuneCount ?? 1) + 1));
						else
							Thread.Sleep(400);
						// every second, give a bit of feedback to those watching
						RuneLog.Debug(count + "/" + total + "  " + string.Format("{0:P2}", (count + complete - total) / (double)complete));
						if (tests != null)
							BuildProgTo?.Invoke(this, ProgToEventArgs.GetEvent(this, (count + complete - total) / (double)complete, tests.Count));

						if (BuildTimeout > 0 && DateTime.Now > begin.AddSeconds(BuildTimeout)) {
							RuneLog.Info("Timeout");
							BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + "Timeout"));
							BuildProgTo?.Invoke(this, ProgToEventArgs.GetEvent(this, 1, tests.Count));

							IsRunning = false;
						}
					}
				});
				timeThread.Start();

				double bestScore = double.MinValue;

				var opts = new ParallelOptions() {
					MaxDegreeOfParallelism = Environment.ProcessorCount - 1
				};

				var mmm = Maximum.NonZeroCached;

				// Parallel the outer loop
				// TODO: setup the begin/finish Actions with syncList.
				void body (Rune r0, ParallelLoopState loopState) {
					var tempReq = RequiredSets.ToList();
					var tempMax = Maximum == null || !Maximum.IsNonZero ? null : new Stats(Maximum, true);
					int tempCheck = 0;

					Monster myBest = null;
					List<Monster> syncList = new List<Monster>();

					void syncMyList() {
						lock (bestLock) {
#if DEBUG_SYNC_BUILDS
							foreach (var s in syncList) {
								if (s.Current.Runes.All(r => r.Assigned == mon)) {
									Console.WriteLine("!");
								}
							}
#endif
							tests.AddRange(syncList);

						}
						//syncList.ForEach(_ => tests.Add(_));
						syncList.Clear();
						if (tests.Count > Math.Max(BuildGenerate, 250000)) {
#if DEBUG_SYNC_BUILDS
								var rems = tests.OrderByDescending(b => b.score).Skip(75000).ToList();
								foreach (var bbb in rems) {
									if (bbb.Current.Runes.All(r => r.Assigned == mon)) {
										Console.WriteLine("!");
									}
								}
#endif
							lock (bestLock) {
								tests = tests.OrderByDescending(b => b.score).Take(75000).ToList();
							}
						}

						if (tests.Count > MaxBuilds32)
							IsRunning = false;
					}

					if (!IsRunning_Unsafe) {
						syncMyList();
						loopState.Break();
					}

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


					bool isBad;
					double myBestScore = double.MinValue, curScore, lastBest = double.MinValue;
					Stats cstats, myStats;


					Monster test = new Monster(Mon);
					test.Current.TempLoad = true;
					test.Current.Buffs = Buffs;
					test.Current.Shrines = Shrines;
					test.Current.Leader = Leader;

					test.Current.FakeLevel = slotFakes;
					test.Current.PredictSubs = slotPred;
					test.ApplyRune(r0, 7);

					RuneSet set4 = r0.SetIs4 ? r0.Set : RuneSet.Null;
					RuneSet set2 = r0.SetIs4 ? RuneSet.Null : r0.Set;
					int pop4 = 0;
					int pop2 = 0;

					foreach (Rune r1 in runes[1]) {
						// TODO: refactor to local method
						if (!IsRunning_Unsafe) // Can't break to a label, don't want to goto
							break;
						// TODO: break into multiple implementations that have less branching
#if BUILD_PRECHECK_BUILDS
						if (!AllowBroken && !RunesOnlyFillEmpty) {
							if (r1.SetIs4) {
								if (pop2 == 2)
									pop2 = 7;
								if (set4 == RuneSet.Null || pop4 >= 2) {
									set4 = r1.Set;
									pop4 = 2;
								}
								else if (set4 != r1.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
									outstrs.Add($"bad4@2 {set4} {set2} | {r0.Set} {r1.Set}");
#endif
									skip += runes[2].Length * runes[3].Length * runes[4].Length * runes[5].Length;
									continue;
								}
							}
							else {
								if (pop4 == 2)
									pop4 = 7;
								if (set2 == RuneSet.Null || pop2 >= 2) {
									set2 = r1.Set;
									pop2 = 2;
								}
							}
						}
#endif
						test.ApplyRune(r1, 7);

						foreach (Rune r2 in runes[2]) {
							if (!IsRunning_Unsafe)
								break;
#if BUILD_PRECHECK_BUILDS
							if (!AllowBroken && !RunesOnlyFillEmpty) {
								if (r2.SetIs4) {
									if (pop2 == 3)
										pop2 = 7;
									if (set4 == RuneSet.Null || pop4 >= 3) {
										set4 = r2.Set;
										pop4 = 3;
									}
									else if (set4 != r2.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
										outstrs.Add($"bad4@3 {set4} {set2} | {r0.Set} {r1.Set} {r2.Set}");
#endif
										skip += runes[3].Length * runes[4].Length * runes[5].Length;
										continue;
									}
								}
								else {
									if (pop4 == 3)
										pop4 = 7;
									if (set2 == RuneSet.Null || pop2 >= 3) {
										set2 = r2.Set;
										pop2 = 3;
									}
									else if (set4 != RuneSet.Null && set2 != r2.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
										outstrs.Add($"bad2@3 {set4} {set2} | {r0.Set} {r1.Set} {r2.Set}");
#endif
										skip += runes[3].Length * runes[4].Length * runes[5].Length;
										continue;
									}
								}
							}
#endif
							test.ApplyRune(r2, 7);

							foreach (Rune r3 in runes[3]) {
								if (!IsRunning_Unsafe)
									break;
#if BUILD_PRECHECK_BUILDS
								if (!AllowBroken && !RunesOnlyFillEmpty) {
									if (r3.SetIs4) {
										if (pop2 == 4)
											pop2 = 7;
										if (set4 == RuneSet.Null || pop4 >= 4) {
											set4 = r3.Set;
											pop4 = 4;
										}
										else if (set4 != r3.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
											outstrs.Add($"bad4@4 {set4} {set2} | {r0.Set} {r1.Set} {r2.Set} {r3.Set}");
#endif
											skip += runes[4].Length * runes[5].Length;
											continue;
										}
									}
									else {
										if (pop4 == 4)
											pop4 = 7;
										if (set2 == RuneSet.Null || pop2 >= 4) {
											set2 = r3.Set;
											pop2 = 4;
										}
										else if (set4 != RuneSet.Null && set2 != r3.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
											outstrs.Add($"bad2@4 {set4} {set2} | {r0.Set} {r1.Set} {r2.Set} {r3.Set}");
#endif
											skip += runes[4].Length * runes[5].Length;
											continue;
										}
									}
								}
#endif
								test.ApplyRune(r3, 7);

								foreach (Rune r4 in runes[4]) {
									if (!IsRunning_Unsafe) {
										break;
									}
#if BUILD_PRECHECK_BUILDS
									if (!AllowBroken && !RunesOnlyFillEmpty) {
										if (r4.SetIs4) {
											if (pop2 == 5)
												pop2 = 7;
											if (set4 == RuneSet.Null || pop4 >= 5) {
												set4 = r4.Set;
												pop4 = 5;
											}
											else if (set4 != r4.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
												outstrs.Add($"bad4@5 {set4} {set2} | {r0.Set} {r1.Set} {r2.Set} {r3.Set} {r4.Set}");
#endif
												skip += runes[5].Length;
												continue;
											}
										}
										else {
											if (pop4 == 5)
												pop4 = 7;
											if (set2 == RuneSet.Null || pop2 >= 5) {
												set2 = r4.Set;
												pop2 = 5;

											}
											else if (set4 != RuneSet.Null && set2 != r4.Set) {
#if BUILD_PRECHECK_BUILDS_DEBUG
												outstrs.Add($"bad2@5 {set4} {set2} | {r0.Set} {r1.Set} {r2.Set} {r3.Set} {r4.Set}");
#endif
												skip += runes[5].Length;
												continue;
											}
										}
									}
#endif
									test.ApplyRune(r4, 7);

									foreach (Rune r5 in runes[5]) {
										if (!IsRunning_Unsafe)
											break;

										test.ApplyRune(r5, 7);
										test.Current.CheckSets();
#if BUILD_PRECHECK_BUILDS_DEBUG
										outstrs.Add($"fine {set4} {set2} | {r0.Set} {r1.Set} {r2.Set} {r3.Set} {r4.Set} {r5.Set}");
#endif
										isBad = false;

										cstats = test.GetStats();

										// check if build meets minimum
										isBad |= !RunesOnlyFillEmpty && !AllowBroken && !test.Current.SetsFull;

										isBad |= tempMax != null && cstats.AnyExceedCached(tempMax);

										if (!isBad && GrindLoads) {
											var mahGrinds = grinds.ToList();
											for (int rg = 0; rg < 6; rg++) {
												var lgrinds = test.Runes[rg].FilterGrinds(mahGrinds);
												foreach (var g in lgrinds) {
													var tr = test.Runes[rg].Grind(g);
												}
												// TODO: 
											}
										}

										isBad |= !RunesOnlyFillEmpty && Minimum != null && !cstats.GreaterEqual(Minimum, true);
										// if no broken sets, check for broken sets
										// if there are required sets, ensure we have them
										/*isBad |= (tempReq != null && tempReq.Count > 0
											// this Linq adds no overhead compared to GetStats() and ApplyRune()
											//&& !tempReq.All(s => test.Current.Sets.Count(q => q == s) >= tempReq.Count(q => q == s))
											//&& !tempReq.GroupBy(s => s).All(s => test.Current.Sets.Count(q => q == s.Key) >= s.Count())
											);*/
										// TODO: recheck this code is correct
										if (tempReq != null && tempReq.Count > 0) {
											tempCheck = 0;
											foreach (var r in tempReq) {
												int i;
												for (i = 0; i < 3; i++) {
													if (test.Current.Sets[i] == r && (tempCheck & 1 << i) != 1 << i) {
														tempCheck |= 1 << i;
														break;
													}
												}
												if (i >= 3) {
													isBad |= true;
													break;
												}
											}
										}

										if (isBad) {
											kill++;
											curScore = 0;
										}
										else {
											// try to reduce CalcScore hits
											curScore = CalcScore(cstats);
											isBad |= IgnoreLess5 && curScore < currentScore * 1.05;
											if (isBad)
												kill++;
										}

										if (!isBad) {
											// we found an okay build!
											plus++;
											test.score = curScore;

											if (BuildSaveStats) {
												foreach (Rune r in test.Current.Runes) {
													if (!BuildGoodRunes) {
														r.manageStats.AddOrUpdate("LoadFilt", 1, (s, d) => { return d + 1; });
														RuneUsage.runesGood.AddOrUpdate(r, (byte)r.Slot, (key, ov) => (byte)r.Slot);
														r.manageStats.AddOrUpdate("currentBuildPoints", curScore, (k, v) => Math.Max(v, curScore));
														r.manageStats.AddOrUpdate("cbp" + ID, curScore, (k, v) => Math.Max(v, curScore));
													}
													else {
														r.manageStats.AddOrUpdate("LoadFilt", 0.001, (s, d) => { return d + 0.001; });
														RuneUsage.runesOkay.AddOrUpdate(r, (byte)r.Slot, (key, ov) => (byte)r.Slot);
														r.manageStats.AddOrUpdate("cbp" + ID, curScore, (k, v) => Math.Max(v, curScore * 0.9));
													}
												}
											}

											if (syncList.Count >= 500) {
												syncMyList();
											}

											// if we are to track all good builds, keep it
											if (!BuildDumpBads) {

												syncList.Add(new Monster(test, true));

												// locally track my best
												if (myBest == null || curScore > myBestScore) {
													myBest = new Monster(test, true);
													myStats = myBest.GetStats();
													myBestScore = CalcScore(myStats);
													myBest.score = myBestScore;
												}

												// if mine is better than what I last saw
												if (myBestScore > lastBest) {
													lock (bestLock) {
														if (Best == null) {
															Best = new Monster(myBest, true);
															bstats = Best.GetStats();
															bestScore = CalcScore(bstats);
															Best.score = bestScore;
														}
														else {
															// sync best score
															lastBest = bestScore;
															// double check
															if (myBestScore > lastBest) {
																Best = new Monster(myBest, true);
																bestScore = CalcScore(bstats);
																Best.score = bestScore;
																bstats = Best.GetStats();
															}
														}
													}
												}

											}
											// if we only want to track really good builds
											else {
												// if there are currently no good builds, keep it
												// or if this build is better than the best, keep it

												// locally track my best
												if (myBest == null || curScore > myBestScore) {
													myBest = new Monster(test, true);
													myStats = myBest.GetStats();
													myBestScore = CalcScore(myStats);
													myBest.score = myBestScore;
													syncList.Add(myBest);
												}
												else if (BuildSaveStats) {
													// keep it for spreadsheeting
													syncList.Add(new Monster(test, true) {
														score = curScore
													});
												}
											}
										}
									}
									// sum up what work we've done
									Interlocked.Add(ref count, kill);
									Interlocked.Add(ref count, skip);
									Interlocked.Add(ref skipped, skip);
									Interlocked.Add(ref actual, kill);
									Interlocked.Add(ref BuildUsage.failed, kill);
									kill = 0;
									skip = 0;
									Interlocked.Add(ref count, plus);
									Interlocked.Add(ref actual, plus);
									Interlocked.Add(ref BuildUsage.passed, plus);
									plus = 0;

									// if we've got enough, stop
									if (BuildGenerate > 0 && BuildUsage.passed >= BuildGenerate) {
										IsRunning = false;
										break;
									}
								}
							}
						}
					}
					// just before dying
					syncMyList();
				}
				Parallel.ForEach(runes[0], opts, body);


				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + "finalizing..."));
				BuildProgTo?.Invoke(this, ProgToEventArgs.GetEvent(this, 0.99, -1));

#if BUILD_PRECHECK_BUILDS_DEBUG
				System.IO.File.WriteAllLines("_into_the_bridge.txt", outstrs.ToArray());
#endif
				if (BuildSaveStats) {
					foreach (var ra in runes) {
						foreach (var r in ra) {
							if (!BuildGoodRunes) {
								r.manageStats.AddOrUpdate("buildScoreTotal", CalcScore(Best), (k, v) => v + CalcScore(Best));
								RuneUsage.runesUsed.AddOrUpdate(r, (byte)r.Slot, (key, ov) => (byte)r.Slot);
								r.manageStats.AddOrUpdate("LoadGen", total, (s, d) => { return d + total; });

							}
							else {
								RuneUsage.runesBetter.AddOrUpdate(r, (byte)r.Slot, (key, ov) => (byte)r.Slot);
								r.manageStats.AddOrUpdate("LoadGen", total * 0.001, (s, d) => { return d + total * 0.001; });
							}
						}
					}
				}

				// write out completion
				RuneLog.Debug(IsRunning + " " + count + "/" + total + "  " + string.Format("{0:P2}", (count + complete - total) / (double)complete));
				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + " completed"));
				BuildProgTo?.Invoke(this, ProgToEventArgs.GetEvent(this, 1, tests.Count));

				// sort *all* the builds
				int takeAmount = 1;
				if (BuildSaveStats)
					takeAmount = 10;
				if (BuildTake > 0)
					takeAmount = BuildTake;

				if (IgnoreLess5)
					tests.Add(new Monster(Mon, true));

				foreach (var ll in tests.Where(t => t != null).OrderByDescending(r => CalcScore(r.GetStats())).Take(takeAmount))
					Loads.Add(ll);

				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, "Found a load " + Loads.Count()));

				if (!BuildGoodRunes)
					BuildUsage.loads = tests.ToList();

				// dump everything to console, if nothing to print to
				if (BuildPrintTo == null)
					foreach (var l in Loads) {
						RuneLog.Debug(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.Any()) {
					RuneLog.Info("No builds :(");
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + "Zero :("));
				}
				else {
					// remember the good one
					Best = Loads.First();
					Best.Current.TempLoad = false;
					Best.score = CalcScore(Best.GetStats());
					BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + "best " + (Best?.score ?? -1)));
					Best.Current.ActualTests = actual;
					foreach (var bb in Loads) {
						foreach (Rune r in bb.Current.Runes) {
							double val = Best.score;
							if (BuildGoodRunes) {
								val *= 0.25;
								if (bb == Best)
									RuneUsage.runesSecond.AddOrUpdate(r, (byte)r.Slot, (key, ov) => (byte)r.Slot);
							}

							if (bb != Best)
								val *= 0.1;
							else
								r.manageStats.AddOrUpdate("In", BuildGoodRunes ? 2 : 1, (s, e) => BuildGoodRunes ? 2 : 1);

							r.manageStats.AddOrUpdate("buildScoreIn", val, (k, v) => v + val);
						}
					}
					for (int i = 0; i < 6; i++) {
						if (!BuildGoodRunes && Mon.Current.Runes[i] != null && Mon.Current.Runes[i].Id != Best.Current.Runes[i].Id)
							Mon.Current.Runes[i].Swapped = true;
					}
					foreach (var ra in runes) {
						foreach (var r in ra) {
							var cbp = r.manageStats.GetOrAdd("currentBuildPoints", 0);
							if (cbp / Best.score < 1)
								r.manageStats.AddOrUpdate("bestBuildPercent", cbp / Best.score, (k, v) => Math.Max(v, cbp / Best.score));
						}
					}
				}

				tests.Clear();
				tests = null;
				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + "Test cleared"));
				return BuildResult.Success;
			}
			catch (Exception e) {
				RuneLog.Error("Error " + e);
				BuildPrintTo?.Invoke(this, PrintToEventArgs.GetEvent(this, prefix + e.ToString()));
				return BuildResult.Failure;
			}
			finally {
				tcs = new TaskCompletionSource<IBuildRunner>();
				IsRunning = false;
				if (timeThread != null)
					timeThread.Join();
			}
		}
Ejemplo n.º 5
0
		public Monster GenBuild(params Rune[] runes) {
			if (runes.Length != 6)
				return null;

			// if to get awakened
			if (DownloadAwake && !Mon.downloaded) {
				var mref = MonsterStat.FindMon(Mon);
				if (mref != null) {
					// download the current (unawakened monster)
					var mstat = mref.Download();
					// if the retrieved mon is unawakened, get the awakened
					if (!mstat.Awakened && mstat.AwakenTo != null)
						Mon = mstat.AwakenTo.Download().GetMon(Mon);
				}
			}
			// getting awakened also gets level 40, so...
			// only get lvl 40 stats if the monster isn't 40, wants to download AND isn't already downloaded (first and last are about the same)
			else if (Mon.level < 40 && DownloadStats && !Mon.downloaded) {
				var mref = MonsterStat.FindMon(Mon);
				if (mref != null)
					Mon = mref.Download().GetMon(Mon);
			}

			int?[] slotFakes = new int?[6];
			bool[] slotPred = new bool[6];
			getPrediction(slotFakes, slotPred);

			Mon.ExtraCritRate = extraCritRate;
			Monster test = new Monster(Mon);
			test.Current.Shrines = Shrines;
			test.Current.Leader = Leader;

			test.Current.FakeLevel = slotFakes.Select(i => i ?? 0).ToArray();
			test.Current.PredictSubs = slotPred;

			test.ApplyRune(runes[0], 7);
			test.ApplyRune(runes[1], 7);
			test.ApplyRune(runes[2], 7);
			test.ApplyRune(runes[3], 7);
			test.ApplyRune(runes[4], 7);
			test.ApplyRune(runes[5], 7);
			test.Current.CheckSets();


			// TODO: Outsource to whoever wants it
			bool isBad = false;

			var cstats = test.GetStats();

			// check if build meets minimum
			isBad |= Minimum != null && (cstats <= Minimum);
			// if no broken sets, check for broken sets
			isBad |= !AllowBroken && !test.Current.SetsFull;
			// if there are required sets, ensure we have them
			isBad |= RequiredSets != null && RequiredSets.Count > 0
				// this Linq adds no overhead compared to GetStats() and ApplyRune()
				&& !RequiredSets.All(s => test.Current.Sets.Count(q => q == s) >= RequiredSets.Count(q => q == s));

			if (isBad)
				return null;

			return test;
		}
Ejemplo n.º 6
0
 public AwakenGoalDef(MonsterTypeMap monsterType) : base(monsterType, GoalType.Awaken)
 {
     type = monsterType;
     stat = MonsterStat.FindMon((int)type).Download();
 }