/// <summary> /// TODO: API /// </summary> /// <param name="oppGame"></param> /// <param name="opponent">the controller of the opponent</param> /// <param name="predicitionMap">the map with all predictions</param> /// <param name="newSimulations"></param> /// <returns></returns> private double simulateOpponentWithPrediction(double lowerTimeBound, double timePerLeaf, POGame.POGame oppGame, Controller opponent, List <Prediction> predicitionMap, ref Dictionary <POGame.POGame, List <MCTSNode> > newSimulations) { double predictionScore = 0; if (predicitionMap?.Any() ?? false) { int denominator = predicitionMap.Count; var scorings = predicitionMap.GroupBy(p => p.Deck.Scoring) .Select(c => new MCTSNode.ScoreExt(((double)c.Count() / denominator), c.Key)) .OrderByDescending(s => s.Value).ToList(); // the simulation time for one prediction double timePerPrediction = timePerLeaf / predicitionMap.Count; // use prediction for each game for (int i = 0; i < predicitionMap.Count; i++) { Prediction prediction = predicitionMap[i]; var setasideZone = opponent.ControlledZones[Zone.SETASIDE] as SetasideZone; setasideZone = new SetasideZone(opponent); // create deck zone List <Card> deckCards = prediction.Deck.Cards; var deckZone = opponent.ControlledZones[Zone.DECK] as DeckZone; deckZone = new DeckZone(opponent); createZone(opponent, deckCards, deckZone, ref setasideZone); deckZone.Shuffle(); // create hand zone List <Card> handCards = prediction.Hand.Cards; var handZone = opponent.ControlledZones[Zone.HAND] as HandZone; handZone = new HandZone(opponent); createZone(opponent, handCards, handZone, ref setasideZone); var oppLeafNodes = new List <MCTSNode>(); IScore oppStrategy = prediction.Deck.Scoring; // forward game POGame.POGame forwardGame = oppGame.getCopy(); // upper time bound for simulation the opponent using the current prediction double oppSimulationTime = lowerTimeBound + (i + 1) * timePerPrediction / 2; // simulate opponent's moves while (forwardGame != null && forwardGame.State == State.RUNNING && forwardGame.CurrentPlayer.Id == opponent.Id) { // simulate var oppRoot = new MCTSNode(opponent.Id, scorings, forwardGame, null, null); MCTSNode bestOppNode = simulate(oppSimulationTime, oppRoot, ref oppLeafNodes); // get solution List <PlayerTask> solutions = bestOppNode.GetSolution(); for (int j = 0; j < solutions.Count && (forwardGame != null); j++) { PlayerTask oppTask = solutions[j]; Dictionary <PlayerTask, POGame.POGame> dir = forwardGame.Simulate(new List <PlayerTask> { oppTask }); forwardGame = dir[oppTask]; if (forwardGame != null && forwardGame.CurrentPlayer.Choice != null) { break; } } } // upper time bound for simulation the player using the forwarded game double simulationTime = oppSimulationTime + timePerPrediction / 2; double score = 0; var leafs = new List <MCTSNode>(); // simulate player using forwarded opponent game while (forwardGame != null && forwardGame.State == State.RUNNING && forwardGame.CurrentPlayer.Id == _playerId) { // simulate var root = new MCTSNode(_playerId, new List <MCTSNode.ScoreExt> { new MCTSNode.ScoreExt(1.0, _scoring) }, forwardGame, null, null); MCTSNode bestNode = simulate(simulationTime, root, ref leafs); // get solution List <PlayerTask> solutions = bestNode.GetSolution(); for (int j = 0; j < solutions.Count && (forwardGame != null); j++) { PlayerTask task = solutions[j]; Dictionary <PlayerTask, POGame.POGame> dir = forwardGame.Simulate(new List <PlayerTask> { task }); forwardGame = dir[task]; if (forwardGame != null && forwardGame.CurrentPlayer.Choice != null) { break; } } // TODO: maybe penalty forwardGame == null score = bestNode.TotalScore; } predictionScore += score; if (forwardGame != null) { newSimulations.Add(forwardGame, leafs); } } } return(predictionScore); }
/// <summary> /// TODO: API /// </summary> /// <param name="game"></param> /// <returns></returns> public override MCTSNode simulate(POGame.POGame game) { POGame.POGame gameCopy = game.getCopy(); // initials root node var initLeafs = new List <MCTSNode>(); var root = new MCTSNode(_playerId, new List <MCTSNode.ScoreExt> { new MCTSNode.ScoreExt(1.0, _scoring) }, gameCopy, null, null); // simulate MCTSNode bestNode = simulate(_deltaTime, root, ref initLeafs); // initials opponent's history if (_oppHistory == null) { List <PlayHistoryEntry> history = gameCopy.CurrentOpponent.PlayHistory; PlayHistoryEntry[] copyHistory = new PlayHistoryEntry[history.Count]; history.CopyTo(copyHistory); _oppHistory = copyHistory.ToList(); } var simulationQueue = new Queue <KeyValuePair <POGame.POGame, List <MCTSNode> > >(); simulationQueue.Enqueue(new KeyValuePair <POGame.POGame, List <MCTSNode> >(gameCopy, initLeafs)); int i = 0; while (i < _predictionParameters.SimulationDepth && simulationQueue.Count > 0) { // calculate the lower and upper time bound of the current depth double lowerSimulationTimeBound = _deltaTime + i * (2 * _deltaTime); KeyValuePair <POGame.POGame, List <MCTSNode> > simulation = simulationQueue.Dequeue(); POGame.POGame simulationGame = simulation.Key; List <MCTSNode> leafs = simulation.Value; leafs = leafs.Where(l => l.Game != null) .OrderByDescending(l => l.Score) .Take((leafs.Count > _predictionParameters.LeafCount) ? _predictionParameters.LeafCount : leafs.Count) .ToList(); if (leafs.Count() < 0) { return(bestNode); } Controller opponent = getOpponent(simulationGame); List <Prediction> predicitionMap = getPredictionMap(simulationGame, opponent); var oldSimulations = new Dictionary <POGame.POGame, List <MCTSNode> >(); // the simulation time for one leaf double timePerLeaf = (2 * _deltaTime) / leafs.Count; // get all games from all leaf nodes for (int j = 0; j < leafs.Count; j++) { // calculate the lower time bound of the current leaf double lowerLeafTimeBound = lowerSimulationTimeBound + j * timePerLeaf; MCTSNode leafNode = leafs[j]; POGame.POGame oppGame = leafNode.Game; double leafScore; // XXX: game can be null leafScore = simulateOpponentWithPrediction(lowerLeafTimeBound, timePerLeaf, oppGame, opponent, predicitionMap, ref oldSimulations); // back-propagate score backpropagate(leafNode, leafScore); } var newSimulations = new Dictionary <POGame.POGame, List <MCTSNode> >(); oldSimulations.ToList() .OrderByDescending(s => s.Value.Sum(l => l.TotalScore)) .Take((leafs.Count > _predictionParameters.OverallLeafCount) ? _predictionParameters.OverallLeafCount : leafs.Count) .ToList() .ForEach(l => newSimulations.Add(l.Key, l.Value)); // add new simulations foreach (KeyValuePair <POGame.POGame, List <MCTSNode> > sim in oldSimulations) { simulationQueue.Enqueue(sim); } i++; } return(root.Children .OrderByDescending(c => c.TotalScore) .First()); }
/// <summary> /// The expanditation step of the MCTS which adds all children to the selected leaf node. /// </summary> /// <param name="selectedNode">the selected leaf node</param> protected void expand(MCTSNode selectedNode) { // TODO: add something like a expansion-threshold selectedNode.Children = selectedNode .Tasks.Select(t => new MCTSNode(selectedNode.Game, t, selectedNode)).ToList(); }