private static void SokobanRandom(string levelPath, int maxDepth, int iterations, uint seed) { string[] levels = ReadSokobanLevels(levelPath); int randomSolved = 0; List <IPuzzleMove> moves = null; RNG.Seed(seed + threadIndex); MersenneTwister rng; for (int i = 0; i < levels.Length; i++) { RNG.Seed(seed + threadIndex); rng = new MersenneTwister(seed + threadIndex); IPuzzleState state = new AbstractSokobanState(levels[i], RewardType.R0, useNormalizedPosition, useGoalMacro, useTunnelMacro, useGoalCut, null, rng); IPuzzleMove move = null; int restart = 0; IPuzzleState clone = state.Clone(); string solution; while (!state.EndState() && restart < iterations) { moves = new List <IPuzzleMove>(); state = clone.Clone(); int count = 0; while (!state.isTerminal() && count < maxDepth) { move = state.GetRandomMove(); moves.Add(move); state.DoMove(move); count++; } restart++; } if (state.EndState()) { solution = ""; int pushCount = 0; foreach (SokobanPushMove push in moves) { foreach (IPuzzleMove m in push.MoveList) { if (m > 3) { pushCount++; } solution += m; } } Log("Level " + (i + 1) + "\titerations: " + restart + "\tsolution length: (moves/pushes)" + solution.Length + "/" + pushCount + "\tsolution: " + solution); randomSolved++; } else { Log("Level " + (i + 1) + "\tNo solution found"); } } Log("Solved: " + randomSolved + "/" + levels.Length); }
/// <summary> /// Takes in a state and returns all the states that can be reached from that state via player input. /// In our case, we have one transition for each color that the player can paint each area. /// </summary> /// <param name="state"></param> /// <returns></returns> public IPuzzleState[] GetReachableStates(IPuzzleState state) { KamiState kamiState = state as KamiState; //Cast IPuzzleState instance to KamiState so that specific information can be extracted. if (kamiState == null) //If the state is not a KamiState, something has gone wrong. Print a debug message and return an empty array; { Debug.Log("State was not castable to KamiState."); return(new KamiState[0]); } //Make a list of states that can be reached from the current state by player input. //If I were optimizing I would use an array since we can calculate the exact number of transitions: (numberOfColors -1) * areas. Readability would suffer though List <IPuzzleState> reachableStates = new List <IPuzzleState>(); foreach (ColorArea area in kamiState.areas) //foreach area... { for (int paintColor = 0; paintColor < mNumberOfColors; paintColor++) //foreach color that are could be painted... { if (area.color != paintColor) //An area can't be painted its current color. { reachableStates.Add(TransitionState(kamiState, area, paintColor)); //Call TransitionState to change color of area and check adjacent areas for merge. } } } return(reachableStates.ToArray()); //reachableStates could be an array to begin with; more optimal but less readable. }
public List <IPuzzleMove> GetSolution(IPuzzleState gameState) { iterations = mcts.IterationsExecuted; List <IPuzzleMove> solution = mcts.Solve(gameState, iterations); return(solution); }
//Check whether the state is a solution to the puzzle. public bool CheckForSolution(IPuzzleState state) { KamiState kamiState = state as KamiState; if (kamiState == null) //If the state is not a KamiState, something has gone wrong. Print a debug message and return an empty array; { Debug.Log("State was not castable to KamiState."); return(false); } if (kamiState.areas.Length <= 1) { return(true); //if there is only one area remaining, the puzzle is solved. } else { //Later levels have discontinous areas that must be set to the same color. int firstColor = kamiState.areas[0].color; for (int i = 1; i < kamiState.areas.Length; i++) { if (kamiState.areas[i].color != firstColor) { return(false); //If there is any mismatch, the state is not a solution. } } return(true); //If they all match, the solution has been reached. } }
public Opt_SP_UCTTreeNode(IPuzzleMove move, Opt_SP_UCTTreeNode parent, IPuzzleState state, MersenneTwister rng, bool ucb1Tuned, bool rave, double raveThreshold, bool nodeRecycling, double const_C = 1, double const_D = 20000, bool generateUntriedMoves = true) { Move = move; this.parent = parent; this.const_C = const_C; this.const_D = const_D; rnd = rng; childNodes = new List <Opt_SP_UCTTreeNode>(); NextLRUElem = null; PrevLRUElem = null; SetActive = false; wins = 0; visits = 0; squares_rewards = 0; RAVEwins = 0; RAVEvisits = 0; squaredReward = 0; topScore = double.MinValue; this.ucb1Tuned = ucb1Tuned; this.rave = rave; this.raveThreshold = raveThreshold; this.nodeRecycling = nodeRecycling; if (generateUntriedMoves) { untriedMoves = state.GetMoves(); } }
public virtual ISPTreeNode AddChild(IPuzzleMove move, IPuzzleState state) { untriedMoves.Remove(move); SP_UCTTreeNode n = new SP_UCTTreeNode(move, this, state, rnd, const_C, const_D, true); childNodes.Add(n); return(n); }
/// <summary> /// Register discovered states in stateNodes dictionary. /// </summary> /// <param name="state"></param> /// <param name="depth"></param> private void RecordState(IPuzzleState state, int depth) { if (!stateNodes.ContainsKey(state)) { //Only create, record, and queue state for exploration if it is new. StateNode node = new StateNode(state, depth); stateNodes.Add(state, node); mNodesToBeExplored.Enqueue(node); } }
private static void SokobanIDAStarTest(string levelPath, int maxCost, RewardType rewardType, int maxTableSize, bool useNormalizedPosition, bool useTunnelMacro, bool useGoalMacro, bool useGoalCut) { string[] levels = ReadSokobanLevels(levelPath); IPuzzleState[] states = new IPuzzleState[levels.Length]; int solvedLevels = 0; Stopwatch stopwatch = new Stopwatch(); long stateInitTime; long solvingTime; //GoalMacroWrapper.BuildMacroTree(null); for (int i = 0; i < states.Length; i++) { stopwatch.Restart(); states[i] = new AbstractSokobanState(levels[i], rewardType, useNormalizedPosition, useGoalMacro, useTunnelMacro, useGoalCut, null); stopwatch.Stop(); stateInitTime = stopwatch.ElapsedMilliseconds; IDAStarSearch idaStar = new IDAStarSearch(); //Log("Level" + (i + 1) + ":\n" + states[i].PrettyPrint()); stopwatch.Restart(); List <IPuzzleMove> solution = idaStar.Solve(states[i], maxCost, maxTableSize, 700); stopwatch.Stop(); solvingTime = stopwatch.ElapsedMilliseconds; string moves = ""; int pushCount = 0; if (solution != null) { foreach (IPuzzleMove m in solution) { //Debug.WriteLine(states[i]); //Debug.WriteLine(m); SokobanPushMove push = (SokobanPushMove)m; foreach (IPuzzleMove basicMove in push.MoveList) { moves += basicMove; if (basicMove.move > 3)//the move is a push move { pushCount++; } } states[i].DoMove(m); } if (states[i].EndState()) { solvedLevels++; } Log("Level " + (i + 1) + " solved: " + (states[i].EndState()) + " with " + idaStar.NodeCount + " nodes; solution length:" + moves.Count() + "/" + pushCount + " - Init Time: " + TimeFormat(stateInitTime) + " - Solving Time: " + TimeFormat(solvingTime)); Log("Moves: " + moves); Log("Solved " + solvedLevels + "/" + (i + 1)); Console.Write("\rSolved " + solvedLevels + "/" + (i + 1)); } } }
public List <IPuzzleMove> Solve(IPuzzleState rootState, int iterations, double maxTimeInMinutes = 5) { topScore = double.MinValue; bestRollout = null; IPuzzleMove bestMove = Search(rootState, iterations, maxTimeInMinutes); List <IPuzzleMove> moves = new List <IPuzzleMove>() { bestMove }; moves.AddRange(bestRollout); return(moves); }
public SP_UCTTreeNode(IPuzzleMove move, SP_UCTTreeNode parent, IPuzzleState state, MersenneTwister rng, double const_C = 1, double const_D = 20000, bool generateUntriedMoves = true) { this.move = move; this.parent = parent; this.const_C = const_C; this.const_D = const_D; rnd = rng; childNodes = new List <SP_UCTTreeNode>(); wins = 0; visits = 0; squaredReward = 0; topScore = double.MinValue; if (generateUntriedMoves) { untriedMoves = state.GetMoves(); } }
public IPuzzleMove selectMove(IPuzzleState gameState) { if (rnd.NextDouble() < inertiaProbability) { List <IPuzzleMove> moves = gameState.GetMoves(); SokobanGameState state = (SokobanGameState)gameState; foreach (IPuzzleMove m in moves) { SokobanPushMove push = (SokobanPushMove)m; if (push.MoveList.Count() == 0) { return(m); } } } return(gameState.GetRandomMove()); }
public IPuzzleMove selectMove(IPuzzleState gameState) { List <IPuzzleMove> moves = gameState.GetMoves(); if (rnd.NextDouble() <= 0.00007) //epsilon greedy { return(moves[rnd.Next(moves.Count)]); } moves.RemoveAll(item => gameState.GetBoard(SamegameGameMove.GetX(item), SamegameGameMove.GetY(item)) == selectedColor); if (moves.Count == 0) { moves = gameState.GetMoves(); } IPuzzleMove selectedMove = moves[rnd.Next(moves.Count)]; return(selectedMove); }
public IPuzzleMove selectMove(IPuzzleState gameState) { //if (moveList != null) //{ // if (moveList.Count > 0) // { // IPuzzleMove move = moveList[0]; // moveList.RemoveAt(0); // return move; // } // else // { // moveList = null; // return (IPuzzleMove)(-1); // } //} //else //{ // moveList = idaStar.Solve(gameState, maxNodes, tableSize, maxDepth); // if (moveList.Count == 0) // { // return (IPuzzleMove)(-1); // } // IPuzzleMove move = moveList[0]; // moveList.RemoveAt(0); // return move; //} if (RNG.NextDouble() < epsilon) { return(gameState.GetMoves()[RNG.Next(gameState.GetMoves().Count)]); } moveList = idaStar.Solve(gameState, maxNodes, tableSize, maxDepth); if (moveList.Count > 0) { return(moveList[0]); } else { return((IPuzzleMove)(-1)); } }
private static void SamegameIDAStarTest(string levelPath, int maxCost, int tableSize)//TODO Need a good heuristic for samegame { string[] levels = ReadSamegameLevels(levelPath); IPuzzleState[] states = new IPuzzleState[levels.Length]; int solvedLevels = 0; double totalScore = 0; for (int i = 0; i < states.Length; i++) { states[i] = new SamegameGameState(levels[i], null, null); IDAStarSearch idaStar = new IDAStarSearch(); Log("Level" + (i + 1) + ":\n" + states[i].PrettyPrint()); List <IPuzzleMove> solution = null; string moves = ""; while (!states[i].isTerminal()) { solution = idaStar.Solve(states[i], maxCost, tableSize, 100); if (solution.Count > 0) { moves += solution[0]; states[i].DoMove(solution[0]); } else { break; } } if (states[i].EndState()) { solvedLevels++; } totalScore += states[i].GetResult(); Log("Level " + (i + 1) + " solved: " + (states[i].EndState()) + " solution length:" + moves.Count() + " Score: " + states[i].GetResult()); Log("Moves: " + moves); Log("Solved " + solvedLevels + "/" + (i + 1)); Console.Write("\rSolved " + solvedLevels + "/" + (i + 1)); } Log("Total score: " + totalScore); }
public IPuzzleMove selectMove(IPuzzleState gameState) { List <IPuzzleMove> moves = gameState.GetMoves(); IPuzzleMove bestMove = null; if (rng.NextDouble() > epsilon) { IPuzzleState clone = gameState.Clone(); double maxReward = double.MinValue; List <IPuzzleMove> bestMoves = new List <IPuzzleMove>(); foreach (IPuzzleMove move in clone.GetMoves()) { clone.DoMove(move); double result = clone.GetResult(); if (result > maxReward) { bestMoves.Clear(); bestMoves.Add(move); maxReward = result; //bestMove = move; } else if (result == maxReward) { bestMoves.Add(move); } clone = gameState.Clone(); } //return bestMoves[0]; return(bestMoves[rng.Next(bestMoves.Count())]); } else { bestMove = gameState.GetRandomMove(); } return(bestMove); }
public IPuzzleMove selectMove(IPuzzleState gameState) { return(mcts.Search(gameState, iterations)); }
public IPuzzleMove selectMove(IPuzzleState gameState) { return(gameState.GetRandomMove()); }
public AStarNode(IPuzzleState state, IPuzzleMove move, AStarNode parent) { this.state = state; this.move = move; this.parent = parent; }
public ISPTreeNode AddChild(ObjectPool objectPool, IPuzzleMove move, IPuzzleState state) { throw new NotImplementedException(); }
public BFSNodeState(IPuzzleState state, IPuzzleMove move, BFSNodeState parent) { this.state = state; this.move = move; this.parent = parent; }
public StateNode(IPuzzleState puzzleState, int depthInGraph) { state = puzzleState; depth = depthInGraph; }
public ISPTreeNode GenRootNode(IPuzzleState rootState) { return(new SP_UCTTreeNode(null, null, rootState, rnd, const_C, const_D, true)); }
public IPuzzleMove Search(IPuzzleState rootState, int iterations, double maxTimeInMinutes = 5) { IterationsForFirstSolution = -1; nodeCount = 0; nodesEliminated = 0; nodesNotExpanded = 0; bool looped; if (!search) { search = true; } double minReward = double.MaxValue; double maxReward = double.MinValue; maxDepth = 0; // If needed clean the pool, restore all objects in the pool to the initial value if (objectPool.NeedToClean) { objectPool.CleanObjectPool(); } ISPTreeNode rootNode = treeCreator.GenRootNode(rootState); ISPTreeNode head = null; ISPTreeNode tail = null; HashSet <IPuzzleMove> allFirstMoves = new HashSet <IPuzzleMove>(); List <IPuzzleMove> currentRollout = new List <IPuzzleMove>(); solutionHashes = new HashSet <int>(); #if PROFILING long beforeMemory = GC.GetTotalMemory(false); long afterMemory = GC.GetTotalMemory(false); long usedMemory = afterMemory - beforeMemory; long averageUsedMemoryPerIteration = 0; #endif int deadlocksInTree = 0; int currentDepth = 0; for (iterationsExecuted = 0; iterationsExecuted < iterations; iterationsExecuted++) { looped = false; ISPTreeNode node = rootNode; IPuzzleState state = rootState.Clone(); //Debug.WriteLine(node.TreeToString(0)); HashSet <IPuzzleState> visitedStatesInRollout = new HashSet <IPuzzleState>() { state.Clone() }; // Clear lists of moves used for RAVE updates && best rollout solutionHash = 27; currentRollout = new List <IPuzzleMove>(); allFirstMoves.Clear(); // Select while (!node.HasMovesToTry() && node.HasChildren()) { // UCB1-Tuned and RAVE Optimizations node = node.SelectChild(); state.DoMove(node.Move); visitedStatesInRollout.Add(state.Clone()); // RAVE Optimization && best rollout currentRollout.Add(node.Move); UpdateSolutionHash(node.Move); allFirstMoves.Add(node.Move); // Node Recycling Optimization if (((Opt_SP_UCTTreeNode)node).NodeRecycling) { // Non-leaf node removed from LRU queue during playout if (node.NextLRUElem != null && node.PrevLRUElem != null) { LRUQueueManager.LRURemoveElement(ref node, ref head, ref tail); } } } IPuzzleState backupState = state.Clone(); if (!node.HasChildren() && !node.HasMovesToTry()) { deadlocksInTree++; } else { Debug.Write(""); } // Expand if (node.HasMovesToTry()) { IPuzzleMove move = node.SelectUntriedMove(); if (move != -1) { state.DoMove(move); // Node Recycling Optimization if (((Opt_SP_UCTTreeNode)node).NodeRecycling) { if (memoryBudget == nodeCount && head != null) { head.ChildRecycle(); nodeCount--; // Change LRU queue head when it becomes a leaf node if (!head.HasChildren()) { LRUQueueManager.LRURemoveFirst(ref head, ref tail); } } } if (visitedStatesInRollout.Contains(state)) { if (avoidCycles) { while (node.GetUntriedMoves().Count > 0 && visitedStatesInRollout.Contains(state)) { state = backupState.Clone(); move = node.GetUntriedMoves()[RNG.Next(node.GetUntriedMoves().Count)]; state.DoMove(move); node.RemoveUntriedMove(move); } if (!visitedStatesInRollout.Contains(state)) //found valid move { node = node.AddChild(objectPool, move, state); UpdateSolutionHash(move); currentRollout.Add(move); allFirstMoves.Add(move); nodeCount++; } else //all moves visited { nodesNotExpanded++; state = backupState; } } else { nodesNotExpanded++; looped = true; } } else { node = node.AddChild(objectPool, move, state); // RAVE Optimization && best rollout UpdateSolutionHash(move); currentRollout.Add(move); allFirstMoves.Add(move); nodeCount++; } visitedStatesInRollout.Add(state.Clone()); } else { state.Pass(); } } else { nodesNotExpanded++; } // Rollout while (!state.isTerminal() && !looped) { var move = state.GetSimulationMove(); backupState = state.Clone(); if (move != -1) { state.DoMove(move); if (visitedStatesInRollout.Contains(state)) { if (avoidCycles) { state = backupState.Clone(); List <IPuzzleMove> availableMoves = state.GetMoves(); while (availableMoves.Count > 0 && visitedStatesInRollout.Contains(state)) { //keep trying different moves until we end up in an unvisited state state = backupState.Clone(); move = availableMoves[RNG.Next(availableMoves.Count)]; availableMoves.Remove(move); state.DoMove(move); } if (availableMoves.Count == 0 && visitedStatesInRollout.Contains(state))//all states have already been visited { break; } } else { looped = true; } } // RAVE Optimization && best rollout UpdateSolutionHash(move); currentRollout.Add(move); allFirstMoves.Add(move); visitedStatesInRollout.Add(state.Clone()); } else //simulation ended { break; //state.Pass(); } } //Keep topScore and update bestRollout double result = state.GetResult(); minReward = Math.Min(result, minReward); maxReward = Math.Max(result, maxReward); if (state.EndState() && !solutionHashes.Contains(solutionHash)) { solutionHashes.Add(solutionHash); solutionCount++; if (iterationsForFirstSolution < 0) { iterationsForFirstSolution = iterationsExecuted + 1; } } if (result > topScore || result == topScore && currentRollout.Count < bestRollout.Count) { topScore = result; bestRollout = currentRollout; if (state.EndState() && stopOnResult) { iterationsExecuted++; break; } } // Backpropagate currentDepth = 0; while (node != null) { if (looped) { //TODO penalize score for loops? } ISPTreeNode parent = node.Parent; //if a node is a dead end remove it from the tree if (!node.HasChildren() && !node.HasMovesToTry() && !state.EndState() && useNodeElimination) { if (node.Parent == null)//unsolvable level. The tree has been completely explored. Return current best score { //SinglePlayerMCTSMain.Log("Unsolvable Level"); //Console.WriteLine("\nUnsolvable Level"); break; } node.Parent.RemoveChild(node); nodeCount--; nodesEliminated++; currentDepth--; } // RAVE Optimization node.Update(result, allFirstMoves); node = parent; currentDepth++; // Node Recycling Optimization if (((Opt_SP_UCTTreeNode)rootNode).NodeRecycling) { // Non-leaf node pushed back to LRU queue when updated if (node != rootNode && node != null && node.HasChildren()) { LRUQueueManager.LRUAddLast(ref node, ref head, ref tail); } } } maxDepth = Math.Max(maxDepth, currentDepth); if (!rootNode.HasChildren() && !rootNode.HasMovesToTry()) { break; } if (!search) { search = true; return(null); } #if PROFILING afterMemory = GC.GetTotalMemory(false); usedMemory = afterMemory - beforeMemory; averageUsedMemoryPerIteration = usedMemory / (i + 1); var outStringToWrite = string.Format(" optMCTS search: {0:0.00}% [{1} of {2}] - Total used memory B(MB): {3}({4:N7}) - Average used memory per iteration B(MB): {5}({6:N7})\n", (float)((i + 1) * 100) / (float)iterations, i + 1, iterations, usedMemory, usedMemory / 1024 / 1024, averageUsedMemoryPerIteration, (float)averageUsedMemoryPerIteration / 1024 / 1024); #if DEBUG if (showMemoryUsage) { Console.Write(outStringToWrite); Console.SetCursorPosition(0, Console.CursorTop); } #endif #endif //Console.WriteLine(rootNode.TreeToString(0)); } //Console.WriteLine(); objectPool.NeedToClean = true; //#if DEBUG // Console.WriteLine(rootNode.ChildrenToString()); // Console.WriteLine(rootNode.TreeToString(0)); //#endif IPuzzleMove bestMove; if (bestRollout != null && bestRollout.Count > 0) //Remove first move from rollout so that if the topScore is not beaten we can just take the next move on the next search { bestMove = bestRollout[0]; bestRollout.RemoveAt(0); } else { bestMove = rootNode.GetBestMove(); } Debug.WriteLine(rootNode.TreeToString(0)); Debug.WriteLine("Min Reward: " + minReward + " - Max Reward: " + maxReward); visits = new List <int>(); raveVisits = new List <int>(); CountVisits((Opt_SP_UCTTreeNode)rootNode, visits, raveVisits); visits.Sort((x, y) => (x.CompareTo(y))); raveVisits.Sort((x, y) => (x.CompareTo(y))); //string visitsString = LogVisits((Opt_SP_UCTTreeNode) rootNode); //SinglePlayerMCTSMain.Log("Iterations: "+IterationsExecuted+" NodeCount: " + nodeCount+" "+visitsString); return(bestMove); }
private static int[] SokobanTest(double const_C, double const_D, int iterations, int restarts, string[] levels, uint seed, bool abstractSokoban, RewardType rewardType, bool stopOnResult, double epsilonValue, bool log) { uint threadIndex = GetThreadIndex(); RNG.Seed(seed + threadIndex); MersenneTwister rng = new MersenneTwister(seed + threadIndex); int currentLevelIndex = GetTaskIndex(threadIndex); ISPSimulationStrategy simulationStrategy; simulationStrategy = new SokobanEGreedyStrategy(epsilonValue, rng); IPuzzleState[] states = new IPuzzleState[levels.Length]; //SokobanMCTSStrategy player; //Debug.WriteLine("Solved random: "+randomSolved+"/"+levels.Length); // Debug.WriteLine(restart); int solvedLevels = 0; int[] rolloutsCount = new int[states.Length]; Stopwatch stopwatch = new Stopwatch(); long stateInitializationTime; long solvingTime; int totalRollouts = 0; int totalNodes = 0; List <int> visitsList = new List <int>(); List <int> raveVisitsList = new List <int>(); double totalDepth = 0; int totalNodesEliminated = 0; int totalNodesNotExpanded = 0; for (int i = 0; i < states.Length; i++) { RNG.Seed(seed + threadIndex); rng = new MersenneTwister(seed + threadIndex); if (simulationType == SimulationType.EpsilonGreedy) { simulationStrategy = new SokobanEGreedyStrategy(epsilonValue, rng); } else { simulationStrategy = new SokobanIDAstarStrategy(maxNodes, tableSize, 200, 0.2); } if (i % SinglePlayerMCTSMain.threadIndex != threadIndex) { continue; } stopwatch.Restart(); if (abstractSokoban) { states[i] = new AbstractSokobanState(levels[i], rewardType, useNormalizedPosition, useGoalMacro, useTunnelMacro, useGoalCut, simulationStrategy, rng); } else { states[i] = new SokobanGameState(levels[i], rewardType, simulationStrategy); } stopwatch.Stop(); stateInitializationTime = stopwatch.ElapsedMilliseconds; List <IPuzzleMove> moveList = new List <IPuzzleMove>(); //player = new SokobanMCTSStrategy(rng, iterations, 600, null, const_C, const_D, stopOnResult); //SP_MCTSAlgorithm mcts = new SP_MCTSAlgorithm(new SP_UCTTreeNodeCreator(const_C, const_D, rng), stopOnResult); OptMCTSAlgorithm mcts = new OptMCTSAlgorithm(new Opt_SP_UCTTreeNodeCreator(const_C, const_D, rng, ucb1Tuned, rave, raveThreshold, nodeRecycling), iterations, memoryBudget, stopOnResult, avoidCycles, useNodeElimination); string moves = ""; stopwatch.Restart(); moveList = mcts.Solve(states[i], iterations); stopwatch.Stop(); solvingTime = stopwatch.ElapsedMilliseconds; //moveList = player.GetSolution(states[i]); int pushCount = 0; foreach (IPuzzleMove m in moveList) { if (abstractSokoban) { //Debug.WriteLine("Move: " + m); //Debug.WriteLine(states[i]); SokobanPushMove push = (SokobanPushMove)m; foreach (IPuzzleMove basicMove in push.MoveList) { moves += basicMove; if (basicMove.move > 3)//the move is a push move { pushCount++; } } } else { moves += m; if (m.move > 3)//the move is a push move { pushCount++; } } states[i].DoMove(m); } if (states[i].EndState()) { solvedLevels++; totalRollouts += mcts.IterationsForFirstSolution; } else { totalRollouts += mcts.IterationsExecuted; } totalDepth += mcts.maxDepth; totalNodesEliminated += mcts.nodesEliminated; totalNodesNotExpanded += mcts.nodesNotExpanded; rolloutsCount[i] = mcts.IterationsExecuted; scores[i] = rolloutsCount[i]; solved[i] = states[i].EndState(); if (log) { Log("Level " + (i + 1) + "\titerations: " + mcts.IterationsExecuted + "\titerations for first solution: " + mcts.IterationsForFirstSolution + "\ttotal solutions: " + mcts.SolutionCount + "\tbest solution length (moves/pushes): " + moves.Count() + "/" + pushCount + "\tInit Time: " + TimeFormat(stateInitializationTime) + " - Solving Time: " + TimeFormat(solvingTime) + "\tTree depth: " + mcts.maxDepth + "\tNodes: " + mcts.NodeCount + "\tNodes Eliminated: " + mcts.nodesEliminated + "\tNodes Not Expanded: " + mcts.nodesNotExpanded + "\tBest solution: " + moves); } totalNodes += mcts.NodeCount; visitsList.AddRange(mcts.visits); raveVisitsList.AddRange(mcts.raveVisits); Console.Write("\r "); Console.Write("\rSolved " + solvedLevels + "/" + (i + 1)); } visitsList.Sort((x, y) => (x.CompareTo(y))); raveVisitsList.Sort((x, y) => (x.CompareTo(y))); double avgVisits = 0; foreach (int v in visitsList) { avgVisits += v; } double avgRaveVisits = 0; foreach (int v in raveVisitsList) { avgRaveVisits += v; } avgVisits /= visitsList.Count; avgRaveVisits /= raveVisitsList.Count; Log("Solved " + solvedLevels + "/" + levels.Length); Log("Total iterations: " + totalRollouts); Log("Total nodes: " + totalNodes); Log("Nodes eliminated: " + totalNodesEliminated); Log("Nodes Not Expanded: " + totalNodesNotExpanded); Log("avg nodes:" + ((double)totalNodes) / states.Length); Log("avg visits: " + avgVisits); Log("avg raveVisits: " + avgRaveVisits); Log("median visits: " + (visitsList.Count % 2 == 0 ? visitsList[visitsList.Count / 2] : (visitsList[visitsList.Count / 2] + visitsList[1 + visitsList.Count / 2]) / 2)); Log("median raveVisits: " + (raveVisitsList.Count % 2 == 0 ? raveVisitsList[raveVisitsList.Count / 2] : (raveVisitsList[raveVisitsList.Count / 2] + raveVisitsList[1 + raveVisitsList.Count / 2]) / 2)); Log("avg depth: " + totalDepth / states.Length); return(rolloutsCount); }
/// <summary> /// Returns an active object from the object pool without resetting any of its values. /// You will need to set its values and set it inactive again when you are done with it. /// </summary> /// <returns>ITreeNode of requested type if it is available, otherwise null.</returns> public Opt_SP_UCTTreeNode GetObject(IPuzzleMove move, Opt_SP_UCTTreeNode parent, IPuzzleState state, MersenneTwister rng, bool ucb1Tuned, bool rave, double raveThreshold, bool nodeRecycling, double const_C, double const_D) { //iterate through all pooled objects. foreach (Opt_SP_UCTTreeNode node in pooledObjects) { //look for the first one that is inactive. if (node.SetActive) { continue; } //set the object to active. node.SetActive = true; //set object's values node.Move = move; node.Parent = parent; node.untriedMoves = state.GetMoves(); node.Rnd = rng; node.Ucb1Tuned = ucb1Tuned; node.Rave = rave; node.RaveThreshold = raveThreshold; node.NodeRecycling = nodeRecycling; node.ConstC = const_C; node.ConstD = const_D; //return the object we found. return(node); } //if we make it this far, we obviously didn't find an inactive object. //so we need to see if we can grow beyond our current count. //if we reach the maximum size we didn't have any inactive objects. //we also were unable to grow, so return null as we can't return an object. if (maxPoolSize <= pooledObjects.Count) { return(null); } //Instantiate a new object. //set it to active since we are about to use it. Opt_SP_UCTTreeNode objNode = new Opt_SP_UCTTreeNode(move, parent, state, rng, ucb1Tuned, rave, raveThreshold, nodeRecycling, const_C, const_D) { SetActive = true }; //add it to the pool of objects pooledObjects.Add(objNode); //return the object to the requestor. return(objNode); }