//Rollout function (plays random moves till it hits a termination) protected override void rollout(AIState rolloutStart) { //If the rollout start is a terminal state int rolloutStartResult = rolloutStart.getWinner(); if (rolloutStartResult >= 0) { //Add a win is it is a win, or a loss is a loss or otherwise a draw if (rolloutStartResult == rolloutStart.playerIndex) { rolloutStart.addWin(); } else if (rolloutStartResult == (rolloutStart.playerIndex + 1) % 2) { rolloutStart.addLoss(); } else { rolloutStart.addDraw(drawScore); } return; } bool terminalStateFound = false; //Get the children List <AIState> children = rolloutStart.generateChildren(); int loopCount = 0; while (!terminalStateFound) { //Loop through till a terminal state is found loopCount++; //If max roll out is hit or no childern were generated if (loopCount >= maxRollout || children.Count == 0) { //Record a draw rolloutStart.addDraw(drawScore); break; } //Get a random child index int index = randGen.Next(children.Count); //and see if that node is terminal int endResult = children[index].getWinner(); if (endResult >= 0) { terminalStateFound = true; if (endResult == 2) { rolloutStart.addDraw(drawScore); } //If it is a win add a win else if (endResult == rolloutStart.playerIndex) { rolloutStart.addWin(); } //Else add a loss else { rolloutStart.addLoss(); } } else { //Otherwise select that nodes as the childern and continue children = children [index].generateChildren(); } } //Reset the children as these are not 'real' children but just ones for the roll out. foreach (AIState child in rolloutStart.children) { child.children = new List <AIState>(); } }
//Rollout function (plays random moves till it hits a termination) protected override void rollout(AIState rolloutStart) { //If the rollout start is a terminal state int rolloutStartResult = rolloutStart.getWinner(); if (rolloutStartResult >= 0) { //Add a win is it is a win, or a loss is a loss or otherwise a draw if (rolloutStartResult == rolloutStart.playerIndex) { rolloutStart.addWin(); } else if (rolloutStartResult == (rolloutStart.playerIndex + 1) % 2) { rolloutStart.addLoss(); } else { rolloutStart.addDraw(drawScore); } return; } bool terminalStateFound = false; //Get the children List <AIState> children = rolloutStart.generateChildren(); int loopCount = 0; while (!terminalStateFound) { //Loop through till a terminal state is found loopCount++; //If max roll out is hit or no childern were generated if (loopCount >= maxRollout || children.Count == 0) { //record a draw rolloutStart.addDraw(drawScore); break; } //Default is the end of the array (because that will be the best move in a sorted list) int selectedChild = children.Count - 1; //epsilon greedy move selection. if (randGen.NextDouble() < epsilon) { //Sort the array (we have all ready selected the most move indx above foreach (AIState child in children) { if (child.stateScore == null) { child.stateScore = model.evaluate(child); } } children = AIState.mergeSort(children); } else { //Just select a random move selectedChild = randGen.Next(children.Count); } //and see if that node is terminal int endResult = children[selectedChild].getWinner(); if (endResult >= 0) { terminalStateFound = true; if (endResult == 2) { rolloutStart.addDraw(drawScore); } //If it is a win add a win else if (endResult == rolloutStart.playerIndex) { rolloutStart.addWin(); } //Else add a loss else { rolloutStart.addLoss(); } } else { //Otherwise select that nodes as the childern and continue children = children [selectedChild].generateChildren(); } } //Reset the children as these are not 'real' children but just ones for the roll out. foreach (AIState child in rolloutStart.children) { child.treeNode = true; } }