/* ***METHODS*** */ private Tuple <long, long> simulateBranch(MCTSNode_QAI currNode) { //checks to see if current node is in an simulation end state if (currNode.flag[qflags.ENDBOARD] || currNode.flag[qflags.ALLCHILDRENSIMULATED]) { //currNode.flag[qflags.ENDBOARD] = true; return(new Tuple <long, long>(0, 0)); } if (currNode.possibleChildren.Count != 0) { int newChildDataIndex = random.Next(0, currNode.possibleChildren.Count); MCTSNode_QAI newChild = currNode.addChild(currNode.possibleChildren[newChildDataIndex]); //possibly simplified currNode.possibleChildren.RemoveAt(newChildDataIndex); if (newChild.isNodeScored()) { if (newChild.isLosingNode()) { currNode.flag[qflags.CHILDHASLOSINGBOARD] = true; currNode.flag[qflags.ALLCHILDRENSIMULATED] = true; } else if (newChild.isWinState()) { currNode.flag[qflags.CHILDHASWINNINGBOARD] = true; currNode.flag[qflags.ALLCHILDRENSIMULATED] = true; } return(currNode.addResultToScore(newChild.score));; } else { Tuple <long, long> tempScore = simulateBranch(newChild); return(currNode.addResultToScore(tempScore));; } } else { MCTSNode_QAI nextChild = selectMostPromisingNodeForSimulation(currNode); if (nextChild == null) { //pos A.0 return(new Tuple <long, long>(0, 0)); } else { Tuple <long, long> tempScore = simulateBranch(nextChild); //currNode.addResultToScore(tempScore); return(currNode.addResultToScore(tempScore)); } } }
//returns null unless it was first turn public Tuple <byte, byte> AITurnUpkeep(byte givenPiece, byte boardPosition, int firstTurnSimulationTime = 4500) { //navigate tree to new state if (this.root == null && givenPiece == 255) //first turn of game { root = new MCTSNode_QAI(); root.flag[qflags.OWNER] = true; root.flag[qflags.TYPE] = true; root.nodeValue = (byte)(random.Next(1, 16) * 15); root.possibleChildren = new List <byte>(root.boardLogic.legalMoves); //simulate tree from seed root time.Restart(); while (time.ElapsedMilliseconds < firstTurnSimulationTime) { simulateBranch(root); } time.Stop(); return(new Tuple <byte, byte>(255, root.nodeValue)); } else if (this.root == null && givenPiece != 255) //second turn of game { root = new MCTSNode_QAI(); root.flag[qflags.OWNER] = false; root.flag[qflags.TYPE] = true; root.nodeValue = givenPiece; root.possibleChildren = new List <byte>(root.boardLogic.legalMoves); //below is a bandage for an issue where the AI would try to give back the first piece it was given //root.boardLogic.unplayedPieces.Remove(givenPiece); } else { MCTSNode_QAI tempRoot = findChildWithVal(boardPosition); if (tempRoot == null) { tempRoot = root.addChild(boardPosition); } root = tempRoot; tempRoot = findChildWithVal(givenPiece); if (tempRoot == null) { tempRoot = root.addChild(givenPiece); } root = tempRoot; } return(null); }