/// <summary> Searches for XX/YY in the given text and parses it to int. </summary> private static bool FindNumberValues(string text, ref int first, ref int second) { Regex regex = new Regex("[0-9]+/[0-9]+"); var match = regex.Match(text); if (match.Success) { var numbers = match.Value.Split("/", StringSplitOptions.RemoveEmptyEntries); if (numbers.Length == 2) { if (int.TryParse(numbers[0], out first)) { if (int.TryParse(numbers[1], out second)) { return(true); } } } } if (TyConst.LOG_UNKNOWN_CORRECTIONS) { TyDebug.LogError("Could find number values in " + text); } return(false); }
public override PlayerTask GetMove(POGame.POGame poGame) { if (!_hasInitialized) { CustomInit(poGame); } if (_isTurnBegin) { OnMyTurnBegin(poGame); } var options = poGame.CurrentPlayer.Options(); PlayerTask choosenTask = ChooseTask(poGame, options); //should not happen, but if, just return anything: if (choosenTask == null) { if (TyConst.LOG_UNKNOWN_CORRECTIONS) { TyDebug.LogError("Choosen task was null!"); } choosenTask = options.GetUniformRandom(_random); } if (choosenTask.PlayerTaskType == PlayerTaskType.END_TURN) { OnMyTurnEnd(); } return(choosenTask); }
public static void CalculateValues(TyState playerState, TyState opponentState, Controller player, Controller opponent) { if (_secretDictionary == null) { Init(); } for (int i = 0; i < player.SecretZone.Count; i++) { var secret = player.SecretZone[i]; var key = secret.Card.Name; if (_secretDictionary.ContainsKey(key)) { var action = _secretDictionary[key]; action(playerState, opponentState, player, opponent, secret); } else { if (TyConst.LOG_UNKNOWN_SECRETS) { TyDebug.LogWarning("Unknown secret: " + secret.Card.FullPrint()); } playerState.BiasValue += secret.Card.Cost * SECRET_VALUE_FACTOR; } } }
private PlayerTask GetSimulationTreeTask(POGame.POGame poGame, List <PlayerTask> options) { double time = TyUtility.GetSecondsSinceStart() - _turnTimeStart; if (time >= TyConst.MAX_TURN_TIME) { TyDebug.LogError("Turn takes too long, fall back to greedy."); return(GetGreedyBestTask(poGame, options)); } _simTree.InitTree(_analyzer, poGame, options); //-1 because TurnEnd won't be looked at: int optionCount = options.Count - 1; int numEpisodes = (int)((optionCount) * _curEpisodeMultiplier); double simStart = TyUtility.GetSecondsSinceStart(); for (int i = 0; i < numEpisodes; i++) { if (!IsAllowedToSimulate(simStart, i, numEpisodes, optionCount)) { break; } bool shouldExploit = ((double)i / (double)numEpisodes) > EXPLORE_TRESHOLD; _simTree.SimulateEpisode(_random, i, shouldExploit); } var bestNode = _simTree.GetBestNode(); return(bestNode.Task); }
private void OnMyTurnEnd() { _isTurnBegin = true; var timeNeeded = TyUtility.GetSecondsSinceStart() - _turnTimeStart; if (AdjustEpisodeMultiplier && UsedAlgorithm == Algorithm.SearchTree) { const double MAX_DIFF = 4.0; double diff = Math.Min(TyConst.DECREASE_SIMULATION_TIME - timeNeeded, MAX_DIFF); double factor = 0.05; //reduce more if above the time limit: if (diff <= 0.0f) { factor = 0.2; } //simulate at max this value * _defaultEpisodeMultiplier: const int MAX_EPISODE_MULTIPLIER = 4; _curEpisodeMultiplier = Math.Clamp(_curEpisodeMultiplier + (int)(factor * diff * _defaultEpisodeMultiplier), _defaultEpisodeMultiplier, _defaultEpisodeMultiplier * MAX_EPISODE_MULTIPLIER); } if (PrintTurnTime) { TyDebug.LogInfo("Turn took " + timeNeeded.ToString("0.000") + "s"); } if (timeNeeded >= TyConst.MAX_TURN_TIME) { TyDebug.LogWarning("Turn took " + timeNeeded.ToString("0.000") + "s"); } }
public static void CalculateValues(TyState playerState, TyState opponentState, Controller player, Controller opponent, PlayerTask task, Spell spell) { if (_spellDictionary == null) { Init(); } //give reward/punishment if spells cost less/more than usual: float diff = (float)spell.Card.Cost - (float)spell.Cost; playerState.BiasValue += diff * 1.25f; var key = spell.Card.Name; if (_spellDictionary.ContainsKey(key)) { var action = _spellDictionary[key]; action(playerState, opponentState, player, opponent, task, spell); } else if (TyConst.LOG_UNKNOWN_SECRETS) { TyDebug.LogInfo("Unknown spell: " + task.FullPrint()); } }
public float GetStateValue(TyState playerState, TyState enemyState, Controller player, Controller opponent, PlayerTask task) { TyDebug.Assert(IsMyPlayer(player)); TyDebug.Assert(!IsMyPlayer(opponent)); if (EstimateSecretsAndSpells) { TySecretUtil.CalculateValues(playerState, enemyState, player, opponent); TySecretUtil.EstimateValues(enemyState, opponent); var spell = task.TryGetSpell(); if (spell != null && !spell.IsSecret) { TySpellUtil.CalculateValues(playerState, enemyState, player, opponent, task, spell); } } if (HasLost(enemyState)) { return(Single.PositiveInfinity); } else if (HasLost(playerState)) { return(Single.NegativeInfinity); } return(GetStateValueFor(playerState, enemyState) - GetStateValueFor(enemyState, playerState)); }
public TyStateWeights(params float[] defaultValues) : this() { TyDebug.Assert(defaultValues.Length == (int)WeightType.Count); for (int i = 0; i < _weights.Length; i++) { _weights[i] = defaultValues[i]; } }
/// <summary> False if there is not enough time left to do simulations. </summary> private bool IsAllowedToSimulate(double startTime, int curEpisode, int maxEpisode, int options) { double time = TyUtility.GetSecondsSinceStart() - startTime; if (time >= TyConst.MAX_SIMULATION_TIME) { TyDebug.LogWarning("Stopped simulations after " + time.ToString("0.000") + "s and " + curEpisode + " of " + maxEpisode + " episodes. Having " + options + " options."); return(false); } return(true); }
private static void RemoveMinion(Minion minion, TyState ownerState, TyState opponentState, PlayerTask task) { //remove the minion value from the overall minion values and remove it from the board ownerState.MinionValues -= TyMinionUtil.ComputeMinionValue(minion); ownerState.NumMinionsOnBoard--; if (minion.HasDeathrattle) { if (!CorrectForSummonAndEquip(minion.Card, ownerState, opponentState) && TyConst.LOG_UNKNOWN_CORRECTIONS) { TyDebug.LogError("Unknown deathrattle from " + minion.Card.FullPrint()); TyDebug.LogWarning("After task " + task.FullPrint()); } } }
/// <summary> Estimates how good the given child state is. </summary> public static float GetStateValue(POGame.POGame parent, POGame.POGame child, PlayerTask task, TyStateAnalyzer analyzer) { float valueFactor = 1.0f; TyState myState = null; TyState enemyState = null; Controller player = null; Controller opponent = null; //it's a buggy state, mostly related to equipping/using weapons on heroes etc. //in this case use the old state and estimate the new state manually: if (child == null) { player = parent.CurrentPlayer; opponent = parent.CurrentOpponent; myState = TyState.FromSimulatedGame(parent, player, task); enemyState = TyState.FromSimulatedGame(parent, opponent, null); //if the correction failes, assume the task is x% better/worse: if (!TyState.CorrectBuggySimulation(myState, enemyState, parent, task)) { valueFactor = 1.25f; } } else { player = child.CurrentPlayer; opponent = child.CurrentOpponent; //happens sometimes even with/without TURN_END, idk if (!analyzer.IsMyPlayer(player)) { player = child.CurrentOpponent; opponent = child.CurrentPlayer; } myState = TyState.FromSimulatedGame(child, player, task); enemyState = TyState.FromSimulatedGame(child, opponent, null); } TyDebug.Assert(analyzer.IsMyPlayer(player)); TyDebug.Assert(!analyzer.IsMyPlayer(opponent)); return(analyzer.GetStateValue(myState, enemyState, player, opponent, task) * valueFactor); }
public static bool CorrectBuggySimulation(TyState lastPlayerState, TyState lastEnemyState, POGame.POGame lastState, PlayerTask task) { var taskType = task.PlayerTaskType; //Testing.TyDebug.LogError(task.FullPrint()); bool corrected = false; if (taskType == PlayerTaskType.END_TURN) { CorrectTurnEnd(lastPlayerState, lastEnemyState, lastState, task, ref corrected); } else if (taskType == PlayerTaskType.HERO_ATTACK) { CorrectHeroAttack(lastPlayerState, lastEnemyState, lastState, task, ref corrected); } else if (taskType == PlayerTaskType.PLAY_CARD) { CorrectPlayCard(lastPlayerState, lastEnemyState, lastState, task, ref corrected); } else if (taskType == PlayerTaskType.MINION_ATTACK) { CorrectMinionAttack(lastPlayerState, lastEnemyState, lastState, task, ref corrected); } else if (taskType == PlayerTaskType.HERO_POWER) { CorrectHeroPower(lastPlayerState, lastEnemyState, lastState, task, ref corrected); } if (TyConst.LOG_UNKNOWN_CORRECTIONS && !corrected) { TyDebug.LogError("Unknown buggy PlayerTask: " + task.FullPrint()); } return(corrected); }
public bool IsMyPlayer(Controller c) { TyDebug.Assert(OwnPlayerId != -1); return(c.PlayerId == OwnPlayerId); }