//Adds to the list public void Add(Node b) { currentFrontier.Add(b); //BUBBLE SORT! kinda... Default sorting for list is quicksort //which was causing a HUGE performance reduction for only one //element out of the list for (int x = 1; x < currentFrontier.Count; x++) { if(currentFrontier[x - 1] > currentFrontier[x]) { Node temp = currentFrontier[x - 1]; currentFrontier[x - 1] = currentFrontier[x]; currentFrontier[x] = temp; } } if (currentFrontier.Count > max_size) max_size = currentFrontier.Count; }
/// <summary> /// Tranverses upwards and adds to the list /// </summary> /// <param name="end"></param> /// <returns></returns> public static List<Node> pathReconstruction(Node end) { List<Node> path = new List<Node>(); Node walker = end; while (walker != null) { path.Add(walker); walker = walker.parent; } return path; }
/// <summary> /// /// Could be easily divided up into four sections, but makes more sense to be one in c# /// /// </summary> /// <param name="passedNode"></param> public static bool generateChildren(Node passedNode){ Node currentNode = passedNode; bool addedNode = false; //Valid Directions bool up = false; bool down = false; bool left = false; bool right = false; if (currentNode.rowVal < (MAX_ROW - 1)) down = true; if (currentNode.colVal < (MAX_COL - 1)) right = true; if (currentNode.rowVal > 0) up = true; if (currentNode.colVal > 0) left = true; //These are pretty uniform //Creates a new state, Node, assigns values, and adds to the frontier if(left == true){ int[,] newArr = currentNode.copyPuzzle(); newArr[currentNode.colVal, currentNode.rowVal] = newArr[(currentNode.colVal - 1), currentNode.rowVal]; newArr[(currentNode.colVal - 1), currentNode.rowVal] = 0; Node newNode = new Node(newArr, (currentNode.colVal - 1), currentNode.rowVal, calculateHeuristic(newArr), (currentNode.cValue + 1), "GO-LEFT"); if(!listContainsArray(closedList, newArr)) { addedNode = true; generatedNodes++; newNode.parent = currentNode; frontier.Add(newNode); closedList.Add(newArr); } } if(right == true){ int[,] newArr = currentNode.copyPuzzle(); newArr[currentNode.colVal, currentNode.rowVal] = newArr[(currentNode.colVal + 1), currentNode.rowVal]; newArr[(currentNode.colVal + 1), currentNode.rowVal] = 0; Node newNode = new Node(newArr, (currentNode.colVal + 1), currentNode.rowVal, calculateHeuristic(newArr), (currentNode.cValue + 1), "GO-RIGHT"); if (!listContainsArray(closedList, newArr)) { addedNode = true; generatedNodes++; newNode.parent = currentNode; frontier.Add(newNode); closedList.Add(newArr); } } if(up == true){ int [,] newArr = currentNode.copyPuzzle(); newArr[currentNode.colVal, currentNode.rowVal] = newArr[currentNode.colVal, (currentNode.rowVal - 1)]; newArr[currentNode.colVal, (currentNode.rowVal - 1)] = 0; Node newNode = new Node(newArr, currentNode.colVal, (currentNode.rowVal - 1), calculateHeuristic(newArr), (currentNode.cValue + 1), "GO-UP"); if (!listContainsArray(closedList, newArr)) { addedNode = true; generatedNodes++; newNode.parent = currentNode; frontier.Add(newNode); closedList.Add(newArr); } } if (down == true) { int[,] newArr = currentNode.copyPuzzle(); newArr[currentNode.colVal, currentNode.rowVal] = newArr[currentNode.colVal, (currentNode.rowVal + 1)]; newArr[currentNode.colVal, (currentNode.rowVal + 1)] = 0; Node newNode = new Node(newArr, currentNode.colVal, (currentNode.rowVal + 1), calculateHeuristic(newArr), (currentNode.cValue + 1), "GO-DOWN"); if (!listContainsArray(closedList, newArr)) { addedNode = true; generatedNodes++; newNode.parent = currentNode; frontier.Add(newNode); closedList.Add(newArr); } } return addedNode; }
/// <summary> /// ***As far as I know you cant pass in a function call as a parameter, so I improvised*** /// /// The heuristic mode is gathered from the global variable "heuristicMode" /// The nodes are gathered from the global 2d array "puzValues & goalState" /// children function cant be passed in /// the f-value function is part of the Node /// /// </summary> public static void a_StarSearch() { //If solved, dont attempt again if (solved) { Console.WriteLine("Puzzle has already been solved. Select new configuration to solve."); return; } //Check to see if we have solved this puzzle configuration // //Pseudo-Pattern Database, didnt want to check in actual //foreach (List<Node> ln in solvedPuzzleStates) //{ // Node temp = ln[0]; // if (temp.stateEquality(puzValues)) // { // Console.WriteLine("Configuration already solved."); // foreach (Node nd in ln) // { // nd.printStructure(); // } // Console.WriteLine(); // return; // } //} //Configure initial node/state Node startingState = new Node(puzValues, Col , Row, calculateHeuristic(puzValues), 0, "INITIAL-STATE"); frontier.Add(startingState); //Members for tracking stats and movement int Expansions = 0; int Cost = 0; int F_Val = 0; List<Node> path = new List<Node>(); Console.WriteLine("Please wait... (The form may freeze while searching the state space)"); Console.WriteLine(); //Start timing the actual process System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); timer.Start(); //Do the work while (!frontier.isEmpty()) { Node temp = frontier.removeFromFrontier(); if (temp.isGoalState(goalState)) { path = pathReconstruction(temp); solved = true; Cost = temp.cValue; F_Val = temp.getF_Val(); break; } if (generateChildren(temp)) { Expansions++; } } timer.Stop(); //Stores the currently selected heuristic to display string Heuristic; if (heuristicMode == 0) Heuristic = "Manhattan"; else if (heuristicMode == 1) Heuristic = "Misplaced"; else Heuristic = "Breadth-First"; double abf = (double)generatedNodes/Expansions; int Depth = (path.Count - 1); if (Depth == -1) Depth = 0; //Stats Console.WriteLine("-------------------------------------------------------------------"); Console.WriteLine("Statistics on the Solution:"); Console.WriteLine("-------------------------------------------------------------------"); Console.WriteLine("Heuristic Used: {0}", Heuristic); Console.WriteLine("Time Taken to Expand Nodes: {0}", timer.Elapsed); Console.WriteLine("Depth: {0}, Cost: {1}", Depth, Cost); Console.WriteLine("Number of Expansions: {0}", Expansions); Console.WriteLine("Number of children generated: {0}", generatedNodes); Console.WriteLine("Total Memory Consumption: {0}", frontier.max_size); Console.WriteLine("Average Branching Factor: {0}", abf); Console.WriteLine("Effective Branchiing Factor: {0}", Math.Pow(Expansions, (double)1/Depth)); Console.WriteLine(); Console.WriteLine("--------------"); Console.WriteLine("| Path Taken |"); Console.WriteLine("--------------"); //Reverse the path, and print out the results! solvedPuzzleStates.Add(path); path.Reverse(); foreach (Node nd in path) { nd.printStructure(); } Console.WriteLine("-------------------------------------------------------------------"); Console.WriteLine(); }