public override PlayerTask GetMove(POGame game) { playerid = game.CurrentPlayer.PlayerId; thinkcounter++; sw.Start(); float timeLeft = 1 - sw.ElapsedMilliseconds / 30000.0f; List <PlayerTask> options = game.CurrentPlayer.Options(); Dictionary <PlayerTask, int> values = new Dictionary <PlayerTask, int>(); int depth = 2; if (sw.ElapsedMilliseconds > 15000) { depth--; } if (sw.ElapsedMilliseconds > 25000) { depth--; } values = SimulateAll(game, options, depth); PlayerTask besttask = values.OrderBy(x => x.Value).ToList().Last().Key; game.Process(besttask); if (Score(game) == int.MaxValue) { Console.WriteLine("Won after: " + Math.Round(sw.ElapsedMilliseconds / 1000.0f) + "s; Turns: " + thinkcounter); } sw.Stop(); return(besttask); }
public override PlayerTask GetMove(POGame poGame) { if (controller == null) { controller = poGame.CurrentPlayer; } List <PlayerTask> options = poGame.CurrentPlayer.Options(); if (options.Count == 1) { return(options[0]); } // For now the MCTS does not have memory. // It Creates a new MCTS node, simulates, and deletes it. MCTSNode realGame = new MCTSNode(null, null, poGame, null); while (realGame.N < NUM_ITERATIONS) { MCTSNode node = Select(realGame); node = Expand(node); double rolloutY6 = Rollout(node); BackPropagate(node, rolloutY6); } return(realGame.Children.OrderBy(x => x.Y6()).Last().Action); }
public SabberStoneAction Act(SabberStoneState state) { var timer = System.Diagnostics.Stopwatch.StartNew(); var gameState = (SabberStoneState)state.Copy(); if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine(Name()); } if (_debug) { Console.WriteLine($"Starting a Heuristic search in turn {(gameState.Game.Turn + 1) / 2}"); } var solution = new SabberStoneAction(); while (gameState.CurrentPlayer() == PlayerID() && gameState.Game.State != State.COMPLETE) { var poGame = new POGame(gameState.Game, _debug); var task = GetMove(poGame); solution.AddTask((SabberStonePlayerTask)task); gameState.Game.Process(task); } var time = timer.ElapsedMilliseconds; if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine($"Heuristic returned with solution: {solution}"); } if (_debug) { Console.WriteLine($"My total calculation time was: {time} ms."); } // Check if the solution is a complete action. if (!solution.IsComplete()) { // Otherwise add an End-Turn task before returning. if (_debug) { Console.WriteLine("Solution was an incomplete action; adding End-Turn task."); } solution.Tasks.Add((SabberStonePlayerTask)EndTurnTask.Any(Player)); } if (_debug) { Console.WriteLine(); } return(solution); }
private Dictionary <PlayerTask, int> SimulateAll(POGame initgame, List <PlayerTask> opitons, int depth) { Dictionary <PlayerTask, POGame> sims = initgame.Simulate(opitons); Dictionary <PlayerTask, int> scores = new Dictionary <PlayerTask, int>(); foreach (KeyValuePair <PlayerTask, POGame> sim in sims) { int score = int.MinValue; if (sim.Key.PlayerTaskType == PlayerTaskType.END_TURN || depth <= 0) { score = Score(sim.Value); } else { List <PlayerTask> new_options = sim.Value.CurrentPlayer.Options(); if (new_options.Count() > 0) { score = SimulateAll(sim.Value, new_options, depth - 1).ToList().Max(x => x.Value); } else { score = Score(sim.Value); } } scores.Add(sim.Key, score); } return(scores); }
public MCTSNode(MCTSNode parent, PlayerTask task, POGame poGame) { this.parent = parent; this.task = task; this.poGame = poGame; children = new List <MCTSNode>(); }
public void InitTree(TyStateAnalyzer analyzer, POGame root, List <PlayerTask> options) { _sortedNodes.Clear(); _explorableNodes.Clear(); _nodesToEstimate.Clear(); _analyzer = analyzer; _rootGame = root; //var initialResults = TyStateUtility.GetSimulatedGames(root, options, _analyzer); for (int i = 0; i < options.Count; i++) { PlayerTask task = options[i]; var node = new TyTaskNode(this, _analyzer, task, 0.0f); //end turn is pretty straight forward, should not really be looked at later in the simulations, just simulate once and keep the value: if (task.PlayerTaskType == PlayerTaskType.END_TURN) { TySimResult sim = TyStateUtility.GetSimulatedGame(root, task, _analyzer); node.AddValue(sim.value); } else { _explorableNodes.Add(node); _sortedNodes.Add(node); } _nodesToEstimate.Add(task, node); } }
private float DefaultPolicyHeuristic(Node node) { float result = 0; POGame state = node.State; int currentTurnDepth = node.TurnDepth; while (state.State != State.COMPLETE && (node.Action.PlayerTaskType == PlayerTaskType.END_TURN ? currentTurnDepth < TurnDepth - 1 : currentTurnDepth < TurnDepth)) { Controller currentPlayer = state.CurrentPlayer; List <PlayerTask> actions = currentPlayer.Options(); List <PlayerTask> oldActions = new List <PlayerTask>(actions); bool uncertainity = currentPlayer.Options() .Any(option => option.PlayerTaskType == PlayerTaskType.PLAY_CARD && option.Source.Card.Name == "No Way!"); // end potential infinite loop of 0 cost spells (happend few times with a mage) if (currentPlayer.CardsPlayedThisTurn.Count > 50) { break; } if (uncertainity) { // depending on active player choose one: // 1) simulate player's card draw // 2) simulate opponent's possible actions actions = state.CurrentPlayer.PlayerId == player.PlayerId ? ActionEstimator.DrawSimulation(currentPlayer) : ActionEstimator.ActionEstimaton(state, currentPlayer); } var bestPair = state.Simulate(actions.Any() ? actions : oldActions) .Where(pair => pair.Value != null) .OrderBy(pair => StateRateStrategies.GetStateRateStrategy(StateRateStrategy.Greedy)(pair.Value, currentPlayer)) .Last(); //Console.WriteLine(currentTurnDepth + ", " + bestPair.Key); if (bestPair.Key.PlayerTaskType == PlayerTaskType.END_TURN) { currentTurnDepth++; } state = bestPair.Value; // this should be redundant.. but, you know.. just in case.. if (state == null) { return(0.5f); } } var firstPlayer = state.CurrentPlayer.PlayerId == player.PlayerId ? state.CurrentPlayer : state.CurrentOpponent; result = StateRateStrategies.GetStateRateStrategy(StateRateStrategy.Greedy)(state, firstPlayer); return(result); }
public MCTSNode(POGame poGame) { parent = null; task = null; children = new List <MCTSNode>(); this.poGame = poGame; }
public PlayerTask GetBestMove(POGame game) { Dictionary <PlayerTask, POGame> SimulationData = SimulateGame(game); PlayerTask BestMove = EvaluateSimulation(SimulationData, game); return(BestMove); }
private static PlayerTask greedyTask(POGame poGame, ParametricGreedyAgent greedyAgent, Random Rnd, double CHILDREN_CONSIDERED_SIMULATING) { PlayerTask bestTask = null; double bestScore = Double.MinValue; double score = 0; List <PlayerTask> taskToSimulate = new List <PlayerTask>(); POGame stateAfterSimulate = null; List <PlayerTask> options = poGame.CurrentPlayer.Options(); int cutPoint = (int)Math.Ceiling(poGame.CurrentPlayer.Options().Count *CHILDREN_CONSIDERED_SIMULATING); while (options.Count > cutPoint) { options.Remove(options[Rnd.Next(0, options.Count - 1)]); } foreach (PlayerTask task in poGame.CurrentPlayer.Options()) { taskToSimulate.Add(task); stateAfterSimulate = poGame.Simulate(taskToSimulate)[task]; score = greedyAgent.scoreTask(poGame, stateAfterSimulate); if (score > bestScore) { bestScore = score; bestTask = task; } taskToSimulate.Clear(); } return(bestTask); }
internal RicksNode(POGame _game, PlayerTask _task = null, RicksNode _parent = null) { game = _game; parent = _parent; task = _task; score = 0; }
public override PlayerTask GetMove(POGame game) { var player = game.CurrentPlayer; //var opponent = game.CurrentOpponent; // Get all simulation results for simulations that didn't fail //var validOpts = game.Simulate(player.Options()).Where(x => x.Value != null); var validOpts = game.Simulate(player.Options()); //Put player options in a variable var playerOptions = player.Options(); /*foreach (var x in playerOptions) * { * Console.WriteLine($"Here is an option {x.PlayerTaskType}"); * }*/ List <PlayerTask> PlayerTaskList = new List <PlayerTask>(validOpts.Keys); PlayerTask endTurnTask = playerOptions.First(); PlayerTask returnTask; updateStates(game); //Prints the game turn and the remaining mana available //Console.WriteLine($"Turn {game.Turn} Move {moveNum}, you have {player.RemainingMana} mana available."); //Prints the board state for the game turn //Console.WriteLine($"Board State for Turn {game.Turn}:" + game.PartialPrint()); InspectHand(player.HandZone); returnTask = PlayCard(PlayerTaskList, game.CurrentPlayer, player.HandZone, player.BoardZone, game); if (returnTask != null) { return(returnTask); } returnTask = MinionAttack(PlayerTaskList, game); if (returnTask != null) { return(returnTask); } if (player.RemainingMana > 0) { returnTask = HeroPower(PlayerTaskList, game.CurrentPlayer); if (returnTask != null) { return(returnTask); } } returnTask = heroAttack(PlayerTaskList); if (returnTask != null) { return(returnTask); } //Console.WriteLine($"Turn {game.Turn}: Ending Turn {endTurnTask}"); return(endTurnTask); }
public override PlayerTask GetMove(POGame game) { var player = game.CurrentPlayer; var validOpts = game.Simulate(player.Options()).Where(x => x.Value != null); var optcount = validOpts.Count(); var returnValue = validOpts.Any() ? validOpts.Select(x => score(x, player.PlayerId, (optcount >= 5) ? ((optcount >= 25) ? 1 : 2) : 3)).OrderBy(x => x.Value).Last().Key : player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN); return(returnValue); KeyValuePair <PlayerTask, int> score(KeyValuePair <PlayerTask, POGame> state, int player_id, int max_depth = 3) { int max_score = int.MinValue; if (max_depth > 0 && state.Value.CurrentPlayer.PlayerId == player_id) { var subactions = state.Value.Simulate(state.Value.CurrentPlayer.Options()).Where(x => x.Value != null); foreach (var subaction in subactions) { max_score = Math.Max(max_score, score(subaction, player_id, max_depth - 1).Value); } } max_score = Math.Max(max_score, Score(state.Value, player_id)); return(new KeyValuePair <PlayerTask, int>(state.Key, max_score)); } }
private PlayerTask GetSimulationTreeTask(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); } TyTaskNode bestNode = _simTree.GetBestNode(); return(bestNode.Task); }
//\the helper methods //the worth functions------------------------------------------------------------------------ private double getWorth(POGame poGame, int playerId) //TODO: implement { Controller own = poGame.CurrentPlayer.PlayerId == playerId ? poGame.CurrentPlayer : poGame.CurrentOpponent; Controller enemy = poGame.CurrentPlayer.PlayerId == playerId ? poGame.CurrentOpponent : poGame.CurrentPlayer; //variables bevore the task execution int turn = getTurn(poGame); double ownStrengthFactor = factors[0] * (getMinionStrehgth(own) + getPlayerAttackDamage(own)) + factors[1] * getMinionHealth(own); double ownHealthFactor = factors[2] * (getPlayerArmor(own) + getPlayerHealth(own)); double ownPotentialFactor = factors[3] * getMana(own) + factors[4] * getHandCardCount(own); double ownFactor = (ownStrengthFactor + ownHealthFactor + ownPotentialFactor) * factors[5]; double enemyStrengthFactor = factors[6] * (getMinionStrehgth(enemy) + getPlayerAttackDamage(enemy)) + factors[7] * getMinionHealth(enemy); double enemyHealthFactor = factors[8] * (getPlayerArmor(enemy) + getPlayerHealth(enemy)); double enemyPotentialFactor = factors[9] * getMana(enemy) + factors[10] * getHandCardCount(enemy); double enemyFactor = (enemyStrengthFactor + enemyHealthFactor + enemyPotentialFactor) * factors[11]; return(ownFactor + enemyFactor); //unused potential: //GraveyardZone myGraveyardZone = poGame.CurrentPlayer.GraveyardZone; //GraveyardZone enemyGraveyardZone = poGame.CurrentOpponent.GraveyardZone; //concider potential synergy effects from cards (like boost for dragon cards) //concider evvects like shield or the unbreakable thing //Concider shield/armor(?) on the health of the own player }
private PlayerTask BeamSearch(POGame game, int depth, int playerbeamWidth, int opponentBeamWidth) { Controller me = game.CurrentPlayer; List <HardSimulation> bestSimulations = Simulate(game, playerbeamWidth); LabelSimulations(bestSimulations, 0); for (int i = 1; i < depth; i++) { var newBestSimulations = new List <HardSimulation>(); foreach (HardSimulation sim in bestSimulations) { int beamWidth = sim.Game.CurrentPlayer.PlayerId == me.PlayerId ? playerbeamWidth : opponentBeamWidth; List <HardSimulation> childSims = Simulate(sim.Game, beamWidth); LabelSimulations(childSims, i); childSims.ForEach(x => x.Parent = sim); newBestSimulations.AddRange(childSims); } bestSimulations = newBestSimulations .OrderBy(x => Score(x.Game, me.PlayerId)) .TakeLast(playerbeamWidth) .Reverse() .ToList(); } PlayerTask nextMove = bestSimulations.Any() ? bestSimulations.First().GetFirstTask() : me.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN); return(nextMove); }
static public float estimateFromState(string estimationMode, POGame poGame) { float score = 0.5f; switch (estimationMode) { case "LinearEstimation": score = linearEstimation(poGame); break; case "ValueEstimation": score = valueEstimation(poGame); break; case "GradualEstimation": score = gradualEstimation(poGame); break; default: score = 0; break; } return(score); }
KeyValuePair <PlayerTask, double> getBestTask(POGame state) { double bestScore = Double.MinValue; PlayerTask bestTask = null; List <PlayerTask> list = state.CurrentPlayer.Options(); foreach (PlayerTask t in list) { debug("---->POSSIBLE " + stringTask(t)); double score = 0; POGame before = state; if (t.PlayerTaskType == PlayerTaskType.END_TURN) { score = 0; } else { List <PlayerTask> toSimulate = new List <PlayerTask>(); toSimulate.Add(t); Dictionary <PlayerTask, POGame> simulated = state.Simulate(toSimulate); //Console.WriteLine("SIMULATION COMPLETE"); POGame nextState = simulated[t]; score = scoreTask(state, nextState); //Warning: if using tree, avoid overflow with max values! } debug("SCORE " + score); if (score >= bestScore) { bestTask = t; bestScore = score; } } return(new KeyValuePair <PlayerTask, double>(bestTask, bestScore)); }
// Calculate different scores based on our hero's class public int Score(POGame state, int playerId) { Controller p = state.CurrentPlayer.PlayerId == playerId ? state.CurrentPlayer : state.CurrentOpponent; switch (h_score) { case 0: return(new HarderAggroScore { Controller = p }.Rate()); case 1: return(new HarderMidRangeScore { Controller = p }.Rate()); case 2: return(new HarderControlScore { Controller = p }.Rate()); default: return(new HarderMidRangeScore { Controller = p }.Rate()); } }
public override PlayerTask GetMove(POGame game) { var player = game.CurrentPlayer; // Implement a simple Mulligan Rule if (player.MulliganState == Mulligan.INPUT) { List <int> mulligan = new WeightedScore().MulliganRule().Invoke(player.Choice.Choices.Select(p => game.getGame().IdEntityDic[p]).ToList()); return(ChooseTask.Mulligan(player, mulligan)); } //Lookhead n steps and choose the best scoring <PlayerTask> and each depth -> branch ->score->until depth //(DFS search) var validOpts = game.Simulate(player.Options()).Where(x => x.Value != null); var voptcount = validOpts.Count(); if (validOpts.Any()) { var depth = voptcount > 5 ? (voptcount > 25 ? 1: 2) : 3; var scored = validOpts.Select(x => Simulate(x, player.PlayerId, depth)); // Array.ForEach(scored.Select(x=>x.Item1).ToArray(),Console.Write); // Console.Write($"\r{scored.Count()} "); return(scored.OrderBy(x => x.Value).Last().Key); } else { return(player.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN)); } }
// Simulates an option and returns the score that this option achieves // maxDepth: the maximum amount of recursive calls that is allowed private KeyValuePair <PlayerTask, double> Simulate(POGame poGame, int playerId, int maxDepth = 3) { List <PlayerTask> options = poGame.CurrentPlayer.Options(); Dictionary <PlayerTask, double> scores = new Dictionary <PlayerTask, double>(); options.ForEach(o => scores[o] = 0.0); poGame.Simulate(options).ToList().ForEach(simulation => { if (simulation.Value == null) { scores[simulation.Key] = Double.MinValue; return; } scores[simulation.Key] += ComputeScore(simulation.Value, playerId); if (maxDepth > 0 && playerId == poGame.CurrentPlayer.PlayerId) { scores[simulation.Key] += Simulate(simulation.Value, playerId, maxDepth - 1).Value; } }); // Get the option with the highest score return(scores.Aggregate((x, y) => x.Value > y.Value ? x : y)); }
private void Expand(Node node, POGame poGame) { #if DEBUG Console.WriteLine($"basemana:{poGame.CurrentPlayer.BaseMana}, usedmana:{poGame.CurrentPlayer.UsedMana}, tempmana:{poGame.CurrentPlayer.TemporaryMana}"); foreach (var minion in poGame.CurrentPlayer.BoardZone) { Console.WriteLine($"minion:{minion}, cost:{minion.Cost}"); } foreach (var card in poGame.CurrentPlayer.HandZone) { Console.WriteLine($"hand:{card}, cost:{card.Cost}"); } if (poGame.CurrentPlayer.Hero.Weapon != null) { Console.WriteLine($"weapon:{poGame.CurrentPlayer.Hero.Weapon.AttackDamage}"); } #endif var options = poGame.CurrentPlayer.Options(); node.edges = new List <Edge>(); foreach (PlayerTask task in options) { var code = GetActionHashCode(task); #if DEBUG Console.WriteLine($"{task}, {code}"); #endif node.edges.Add(new Edge(code /*, task.ToString()*/)); } }
private void InitializeRoot(Node root, POGame poGame) { foreach (PlayerTask task in poGame.CurrentPlayer.Options()) { root.children.Add(new Node(task, root, root.depth + 1)); } }
public override PlayerTask GetMove(POGame game) { int depth; int beamWidth; // Check how much time we have left on this turn. The hard limit is 75 seconds so we already stop // beam searching when 60 seconds have passed, just to be sure. if (_watch.ElapsedMilliseconds < 60 * 1000) { // We still have ample time, proceed with beam search depth = 15; beamWidth = 12; } else { // Time is running out, just simulate one timestep now depth = 1; beamWidth = 1; Console.WriteLine("Over 60s in turn already. Pausing beam search for this turn!"); } _watch.Start(); var move = BeamSearch(game, depth, playerbeamWidth: beamWidth, opponentBeamWidth: 1); _watch.Stop(); if (move.PlayerTaskType == PlayerTaskType.END_TURN) { _watch.Reset(); } return(move); }
public SimGame(POGame _game, int _depth) { tasks = new PlayerTask[0]; depth = _depth; step = 0; game = _game; }
//public int AlternativeGameValue(int playerID) => new ScoreTest { Controller = playerID == game.CurrentPlayer.PlayerId ? game.CurrentPlayer : game.CurrentOpponent }.Rate(); public SimGame(POGame _game, int _depth, PlayerTask[] _tasks, int _step) { game = _game; depth = _depth; tasks = _tasks; step = _step; }
public PlayerTask MCTS(POGame state) { Controller player = state.CurrentPlayer; var timer = Stopwatch.StartNew(); Node rootNode = new Node(parentNode: null, gameState: new KeyValuePair <PlayerTask, POGame>(null, state)); // Do as long as we've got time while (timer.ElapsedMilliseconds < 10000 && rootNode.N < numSimulations) { //Selection Node currentNode = Selection(rootNode); //Expansion currentNode = Expansion(currentNode, 2); //Rollout int result = Rollout(currentNode, player); //Backpropagation Backpropagate(currentNode, result); } // Return the action that has accumulated the highest rewards return(rootNode.Children.Any() ? rootNode.Children.OrderBy(x => SafeCalculateValue(x.T, x.N)).Last().State.Key : rootNode.State.Value.CurrentPlayer.Options().First(x => x.PlayerTaskType == PlayerTaskType.END_TURN)); }
// Calculate different scores based on our hero's class private static int Score(POGame state, int playerId) { Controller cont = state.CurrentPlayer.PlayerId == playerId ? state.CurrentPlayer : state.CurrentOpponent; return(new My_Score_m { Controller = cont }.Rate()); }
// Calculate different scores based on our hero's class private static int Score(POGame state, int playerId) { var p = state.CurrentPlayer.PlayerId == playerId ? state.CurrentPlayer : state.CurrentOpponent; return(new ShroudedScore3 { Controller = p }.Rate()); }
private int Score(POGame state, int playerId) { var p = state.CurrentPlayer.PlayerId == playerId ? state.CurrentPlayer : state.CurrentOpponent; return(new CustomScore { Controller = p }.Rate(RuntimeScaling)); }