private void UpdateParentValues(ref NodeMCTS root) { foreach (KeyValuePair <Direction, NodeMCTS> child in root.children) { root.winCount += child.Value.winCount; root.lossCount += child.Value.lossCount; root.playsCount += child.Value.playsCount; } }
private int GetNValue(NodeMCTS node) { int N = 0; foreach (KeyValuePair <Direction, NodeMCTS> child in node.children) { N += child.Value.playsCount; } return(N); }
private NodeMCTS FindParent(ref NodeMCTS best, ref NodeMCTS root) { foreach (KeyValuePair <Direction, NodeMCTS> child in root.children) { //encontrei o best if (child.Value == best) { //encontrei o pai e atualizo-o UpdateParentValues(ref root); return(root); } } foreach (KeyValuePair <Direction, NodeMCTS> child in root.children) { NodeMCTS childVal = child.Value; FindParent(ref childVal, ref root); } return(new NodeMCTS()); }
private NodeMCTS GetBestPath(NodeMCTS root) { //formula variables int C = 1; int N = 0; float result; float bestResult = 0f; NodeMCTS bestResNode = new NodeMCTS(); int i = 0; //calculate the formula value for each child foreach (KeyValuePair <Direction, NodeMCTS> child in root.children) { //setting the N value N = GetNValue(child.Value); //calculate the node's formula result = (float)child.Value.winCount / child.Value.playsCount + C * (float)Math.Sqrt(2 * Math.Log(Math.E, N) / child.Value.playsCount); if (i == 0) { bestResult = result; bestResNode = child.Value; } //update the best current result given the result else if (result > bestResult) { bestResult = result; bestResNode = child.Value; } i++; } //return the child with the best result return(bestResNode); }
public void Run() { // get all possible moves List <Direction> possibleMoves = gameState.board.Node(gameState.player.position).neighbors.Keys.ToList(); foreach (Direction move in possibleMoves) { if (!children.ContainsKey(move)) { bool isCopy = false; GameState childState = gameState.Copy(); if (childState.player.Move(move)) { //if the gamestate exists, don't make a new child foreach (KeyValuePair <Direction, NodeMCTS> c in children) { if (c.Value.gameState == childState) { GameState copy = gameState; //make random run int result = copy.PlayTest(MCRuns); playsCount++; if (result > 0) { winCount++; } if (result < 0) { lossCount++; } isCopy = true; break; } } //create a new child if (!isCopy) { NodeMCTS child = new NodeMCTS(childState); winCount += child.winCount; lossCount += child.lossCount; children[move] = child; } return; // Our work is done here, one node was expanded! } } } // If we got here, all moves were tested. // Decide which move should be explored. int N = children.Values.Select(node => node.playsCount).Sum(); Direction?bestDirection = null; float uBest = 0f; foreach (Direction direction in children.Keys) { NodeMCTS node = children[direction]; float u = ((float)node.winCount / node.playsCount) + C * (float)Math.Sqrt(2 * Math.Log(N) / node.playsCount); if (u > uBest) { uBest = u; bestDirection = direction; } } if (bestDirection.HasValue) { // Save child counts int childLosses = children[bestDirection.Value].lossCount; int childWins = children[bestDirection.Value].winCount; int childPlays = children[bestDirection.Value].playsCount; children[bestDirection.Value].Run(); // Recompute counts playsCount = playsCount - childPlays + children[bestDirection.Value].playsCount; winCount = winCount - childWins + children[bestDirection.Value].winCount; lossCount = lossCount - childLosses + children[bestDirection.Value].lossCount; return; // Our work is done, we iterated down once } // If we got here, we were unable to expand, and there were no childs // check: // - if this is a win position, sum one to wins count // - if this is a lose position, sum one to lost count // either way, increment // FIXME!!! }
//public void Iterate(NodeMCTS root, NodeMCTS firstRoot) //{ // int x = (int)root.gameState.player.position.X, y = (int)root.gameState.player.position.Y; // //if the node has a neighbor list, iterate through each neighbor // if (root.gameState.board.nodes[x, y].neighbors != null) // { // //shuffle the neighbors keys so the order is random (not really a necessary step) // var neighborKeys = root.gameState.board.Node(new Microsoft.Xna.Framework.Vector2(x, y)).neighbors.Keys.Shuffle().ToList(); // //saves the best path given the formula // NodeMCTS bestPath = new NodeMCTS(); // NodeMCTS rootCopy = root.Copy(); // bool isExpanding = false; // foreach (var key in neighborKeys) // { // //if the node doesn't have children yet or its direction hasn't yet been visited // if (!root.children.ContainsKey(key)) // { // //if the player can move towards that direction, it moves // if (rootCopy.gameState.player.Move(key)) // { // //create the child node and executes a random run // NodeMCTS child = new NodeMCTS(rootCopy.gameState); // //add the child to the children list // root.children.Add(key, child); // //update the parent's win/loss/plays values // root.playsCount += child.playsCount; // root.lossCount += child.lossCount; // root.winCount += child.winCount; // } // } // //this node has already been visited // else // { // isExpanding = true; // break; // } // } // //if the tree is expanding through evaluation // if (isExpanding) // { // //find the best path using the formula // bestPath = GetBestPath(root); // //iterate through the bestPath's children and expand the tree // Iterate(bestPath, firstRoot); // } // //go through the root again // Iterate(firstRoot, firstRoot); // } //} public bool Iterate(NodeMCTS root, NodeMCTS firstRoot, int iNow, int iTotal) { int x = (int)root.gameState.player.position.X, y = (int)root.gameState.player.position.Y; //if the node has a neighbor list, iterate through each neighbor if (root.gameState.board.nodes[x, y].neighbors != null) { //shuffle the neighbors keys so the order is random (not really a necessary step) var neighborKeys = root.gameState.board.Node(new Microsoft.Xna.Framework.Vector2(x, y)).neighbors.Keys.Shuffle().ToList(); //saves the best path given the formula NodeMCTS bestPath = new NodeMCTS(); NodeMCTS rootCopy = root.Copy(); //new NodeMCTS(); // rootCopy.children = root.children.Copy(); // rootCopy.gameState = root.gameState.Copy(); // rootCopy.lossCount = root.lossCount.Copy(); // rootCopy.winCount = root.winCount.Copy(); bool isExpanding = false; foreach (var key in neighborKeys) { if (iNow == iTotal) { return(true); } //if the node doesn't have children yet or its direction hasn't yet been visited if (!root.children.ContainsKey(key)) { //if the player can move towards that direction, it moves if (rootCopy.gameState.player.Move(key)) { //create the child node and executes a random run NodeMCTS child = new NodeMCTS(rootCopy.gameState); //add the child to the children list root.children.Add(key, child); //update the parent's win/loss/plays values root.playsCount += child.playsCount; root.lossCount += child.lossCount; root.winCount += child.winCount; iNow++; } } //this node has already been visited else { isExpanding = true; break; } } if (iNow == iTotal) { return(true); } //if the tree is expanding through evaluation if (isExpanding) { //find the best path using the formula bestPath = GetBestPath(root); int prevplays = bestPath.playsCount; int prevloss = bestPath.lossCount; int prevwin = bestPath.winCount; bool res = Iterate(bestPath, firstRoot, iNow, iTotal); // FindParent(ref bestPath, ref firstRoot); root.playsCount += bestPath.playsCount - prevplays; root.lossCount += bestPath.lossCount - prevloss; root.winCount += bestPath.winCount - prevwin; //iterate through the bestPath's children and expand the tree if (res) { UpdateParentValues(ref firstRoot); return(true); } } bool result = Iterate(firstRoot, firstRoot, iNow, iTotal); //root.playsCount += bestPath.playsCount; //root.lossCount += bestPath.lossCount; //root.winCount += bestPath.winCount; //go through the root again if (result) { UpdateParentValues(ref firstRoot); return(true); } } return(false); }