public void cuttingposibilities(int maxwide) { // take the x best values List <Playfield> temp = new List <Playfield>(); Dictionary <Int64, Playfield> tempDict = new Dictionary <Int64, Playfield>(); posmoves.Sort((a, b) => - (botBase.getPlayfieldValue(a)).CompareTo(botBase.getPlayfieldValue(b)));//want to keep the best if (this.useComparison) { int i = 0; int max = Math.Min(posmoves.Count, maxwide); Playfield p = null; //foreach (Playfield p in posmoves) for (i = 0; i < max; i++) { p = posmoves[i]; Int64 hash = p.GetPHash(); p.hashcode = hash; if (!tempDict.ContainsKey(hash)) { tempDict.Add(hash, p); } } foreach (KeyValuePair <Int64, Playfield> d in tempDict) { temp.Add(d.Value); } } else { temp.AddRange(posmoves); } posmoves.Clear(); posmoves.AddRange(temp.GetRange(0, Math.Min(maxwide, temp.Count))); }
private void startEnemyTurnSimThread(List <Playfield> source, int startIndex, int endIndex) { int threadnumber = 0; lock (threadnumberLocker) { threadnumber = threadnumberGlobal++; Monitor.Pulse(threadnumberLocker); } if (threadnumber > Ai.Instance.maxNumberOfThreads - 2) { threadnumber = Ai.Instance.maxNumberOfThreads - 2; Helpfunctions.Instance.ErrorLog("You need more threads!"); return; } int berserk = Settings.Instance.berserkIfCanFinishNextTour; int printRules = Settings.Instance.printRules; for (int i = startIndex; i < endIndex; i++) { Playfield p = source[i]; if (p.complete || p.ownHero.HealthPoints <= 0) { } else if (!enoughCalculations) { //gernerate actions and play them! List <Action> actions = movegen.GetMoveList(p, usePenalityManager, useCutingTargets, true); if (printRules > 0) { p.endTurnState = new Playfield(p); } foreach (Action a in actions) { Playfield pf = new Playfield(p); pf.doAction(a); pf.evaluatePenality += -pf.ruleWeight + RulesEngine.Instance.getRuleWeight(pf); if (pf.ownHero.HealthPoints > 0 && pf.evaluatePenality < 500) { p.nextPlayfields.Add(pf); } } } if (isLethalCheck) { if (berserk > 0) { p.endTurn(); if (p.enemyHero.HealthPoints > 0) { bool needETS = true; if (p.anzEnemyTaunt < 1) { foreach (Minion m in p.ownMinions) { if (m.Ready) { needETS = false; break; } } } else { if (p.anzOwnTaunt < 1) { foreach (Minion m in p.ownMinions) { if (m.Ready) { needETS = false; break; } } } } if (needETS) { Ai.Instance.enemyTurnSim[threadnumber].simulateEnemysTurn(p, simulateSecondTurn, playaround, false, playaroundprob, playaroundprob2); } } } p.complete = true; } else { p.endTurn(); if (p.enemyHero.HealthPoints > 0) { Ai.Instance.enemyTurnSim[threadnumber].simulateEnemysTurn(p, simulateSecondTurn, playaround, false, playaroundprob, playaroundprob2); if (p.value <= -10000) { bool secondChance = false; foreach (Action a in p.playactions) { if (a.actionType == actionEnum.playcard) { if (pen.cardDrawBattleCryDatabase.ContainsKey(a.card.card.name)) { secondChance = true; } } } if (secondChance) { p.value += 1500; } } } p.complete = true; } botBase.getPlayfieldValue(p); } }
public float DoAllMoves(Playfield playf) { print = playf.print; isLethalCheck = playf.isLethalCheck; enoughCalculations = false; botBase = Ai.Instance.botBase; posmoves.Clear(); twoturnfields.Clear(); addToPosmoves(playf); bool havedonesomething = true; List <Playfield> temp = new List <Playfield>(); int deep = 0; calculated = 0; Playfield bestold = null; bestoldval = -20000000; while (havedonesomething) { if (printNormalstuff) { LogHelper.WriteCombatLog($"ailoop{deep}"); } GC.Collect(); temp.Clear(); temp.AddRange(posmoves); posmoves.Clear(); havedonesomething = false; threadnumberGlobal = 0; if (print) { startEnemyTurnSimThread(temp, 0, temp.Count); } else { Parallel.ForEach(Partitioner.Create(0, temp.Count), range => { startEnemyTurnSimThread(temp, range.Item1, range.Item2); }); } foreach (Playfield p in temp) { if (totalboards > 0) { calculated += p.nextPlayfields.Count; } if (calculated <= totalboards) { posmoves.AddRange(p.nextPlayfields); p.nextPlayfields.Clear(); } //get the best Playfield float pVal = botBase.getPlayfieldValue(p); if (pVal > bestoldval) { bestoldval = pVal; bestold = p; bestoldDuplicates.Clear(); } else if (Math.Abs(pVal - bestoldval) < 0.001f) { bestoldDuplicates.Add(p); } } if (isLethalCheck && bestoldval >= 10000) { posmoves.Clear(); } if (posmoves.Count > 0) { havedonesomething = true; } if (printNormalstuff) { int donec = 0; foreach (Playfield p in posmoves) { if (p.complete) { donec++; } } LogHelper.WriteCombatLog("deep " + deep + " len " + posmoves.Count + " dones " + donec); } cuttingposibilities(isLethalCheck);//will update posmoves if (printNormalstuff) { LogHelper.WriteCombatLog("cut to len " + posmoves.Count); } int itemPlayfieldIndex = 0; foreach (var itemPlayfield in posmoves) { itemPlayfieldIndex++; var actionsCount = itemPlayfield.playactions.Count; LogHelper.WriteTestCombatLog($"{nameof(itemPlayfield)}{itemPlayfieldIndex} with {actionsCount} actions"); itemPlayfield.printActions(); } deep++; temp.Clear(); if (calculated > totalboards) { enoughCalculations = true; } if (deep >= maxdeep) { enoughCalculations = true; } } if (dirtyTwoTurnSim > 0 && !twoturnfields.Contains(bestold)) { twoturnfields.Add(bestold); } posmoves.Clear(); posmoves.Add(bestold); posmoves.AddRange(bestoldDuplicates); // search the best play........................................................... //do dirtytwoturnsim first :D if (!isLethalCheck && bestoldval < 10000) { doDirtyTwoTurnsim(); } if (posmoves.Count >= 1) { posmoves.Sort((a, b) => botBase.getPlayfieldValue(b).CompareTo(botBase.getPlayfieldValue(a))); Playfield bestplay = posmoves[0]; float bestval = botBase.getPlayfieldValue(bestplay); int pcount = posmoves.Count; for (int i = 1; i < pcount; i++) { float val = botBase.getPlayfieldValue(posmoves[i]); if (bestval > val) { break; } if (posmoves[i].cardsPlayedThisTurn > bestplay.cardsPlayedThisTurn) { continue; } if (posmoves[i].cardsPlayedThisTurn == bestplay.cardsPlayedThisTurn) { if (bestplay.optionsPlayedThisTurn > posmoves[i].optionsPlayedThisTurn) { continue; } if (bestplay.optionsPlayedThisTurn == posmoves[i].optionsPlayedThisTurn && bestplay.enemyHero.HealthPoints <= posmoves[i].enemyHero.HealthPoints) { continue; } } bestplay = posmoves[i]; bestval = val; } bestmove = bestplay.getNextAction(); bestmoveValue = bestval; bestboard = new Playfield(bestplay); bestboard.guessingHeroHP = bestplay.guessingHeroHP; bestboard.value = bestplay.value; bestboard.hashcode = bestplay.hashcode; bestoldDuplicates.Clear(); return(bestval); } bestmove = null; bestmoveValue = -100000; bestboard = playf; return(-10000); }
public float doallmoves(Playfield playf, bool print = false) { //todo only one time! bool isLethalCheck = playf.isLethalCheck; int totalboards = Settings.Instance.nextTurnTotalBoards; int maxwide = Settings.Instance.nextTurnMaxWide; int maxdeep = Settings.Instance.nextTurnDeep; bool playaround = Settings.Instance.playaround; int playaroundprob = Settings.Instance.playaroundprob; int playaroundprob2 = Settings.Instance.playaroundprob2; botBase = Ai.Instance.botBase; this.posmoves.Clear(); this.posmoves.Add(new Playfield(playf)); bool havedonesomething = true; List <Playfield> temp = new List <Playfield>(); int deep = 0; this.calculated = 0; Playfield bestold = null; float bestoldval = -20000000; while (havedonesomething) { //GC.Collect(); temp.Clear(); temp.AddRange(this.posmoves); havedonesomething = false; foreach (Playfield p in temp) { if (p.complete || p.ownHero.HealthPoints <= 0) { continue; } List <Action> actions = movegen.GetMoveList(p, usePenalityManager, useCutingTargets, true); foreach (Action a in actions) { havedonesomething = true; Playfield pf = new Playfield(p); pf.doAction(a); if (pf.ownHero.HealthPoints > 0) { this.posmoves.Add(pf); } if (totalboards > 0) { this.calculated++; } } p.endTurn(); if (!isLethalCheck) { this.startEnemyTurnSim(p, this.simulateSecondTurn, false, playaround, playaroundprob, playaroundprob2); } //sort stupid stuff ouf if (botBase.getPlayfieldValue(p) > bestoldval) { bestoldval = botBase.getPlayfieldValue(p); bestold = p; } posmoves.Remove(p); if (this.calculated > totalboards) { break; } } cuttingposibilities(maxwide); deep++; if (this.calculated > totalboards) { break; } if (deep >= maxdeep) { break; } } posmoves.Add(bestold); foreach (Playfield p in posmoves) { if (!p.complete) { p.endTurn(); if (!isLethalCheck) { this.startEnemyTurnSim(p, this.simulateSecondTurn, false, playaround, playaroundprob, playaroundprob2); } } } // find best if (posmoves.Count >= 1) { posmoves.Sort((a, b) => botBase.getPlayfieldValue(b).CompareTo(botBase.getPlayfieldValue(a))); Playfield bestplay = posmoves[0]; float bestval = botBase.getPlayfieldValue(bestplay); int pcount = posmoves.Count; for (int i = 1; i < pcount; i++) { float val = botBase.getPlayfieldValue(posmoves[i]); if (bestval > val) { break; } if (bestplay.playactions.Count <= posmoves[i].playactions.Count) { continue; //priority to the minimum acts } bestplay = posmoves[i]; bestval = val; } this.bestmove = bestplay.getNextAction(); this.bestmoveValue = bestval; this.bestboard = new Playfield(bestplay); return(bestval); } this.bestmove = null; this.bestmoveValue = -100000; this.bestboard = playf; return(-10000); }