|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Hiii... please leave a comment and/or vote. Thanks =)Download 8_Puzzle_-_source.zip - 2.02 MBIntroduction75% of the focus of this article is on state space searching algorithms. The other 25% is showing how animation can be used in windows presentation foundation (aka WPF). I wanted to visually represent a computer (A.I.) solving an 8-puzzle using different search algorithms. Different search algorithms being: Depth-First search; Iterative Depth-First search and A*. Background159.302 Artificial Intelligence - Assignment 1! Need I say more? This is just an assignment I was doing while I was taking the A.I. paper. The assignment itself was supposed to be done in C/C++ but I did it using C# as it’s implementing the search algorithms that are important not what language you choose to implement it in. And I was pretty hyped about WPF's animation support and wanted to use it to have a better visual representation of how each algorithm affects how the 8-puzzle is solved. I thought the solution I came up with was pretty neat so what better way to share it than put it up on CodeProject =). Do keep in mind though that like most students if not all, most of the work I did on this assignment was a short time before the due date. I'm going to blame the lack of commenting and possibly not the best way to have organised the code... Brief Introduction to search algorithmsSearch algorithms are very important in AI. They are the backbone of systematic exploration of alternatives you could say. A problem represented as a graph consisting of at least one node and several paths. Like the one below: There are states (Auckland, Hamilton etc...) and edges (lines) that connect the different states. This is the problem domain and it contains a set of possible solutions. Given the task of finding a way to get from Auckland to Raglan, using a search algorithm you can systematically work through all possible paths by searching and examining node by node. There are many different algorithms all with their pros and cons, but all of them are more alike than different. Anyhow if you’re reading this article, I'm already assuming you know about graphs and trees and have a basic concept of search algorithms but I'll just refresh your memory anyhow Depth-First SearchThe most basic of the search algorithms also categorised as Any-path uninformed algorithm. So DFS might not find the most optimal solution if one is found. Examines all possible nodes till it finds the goal. Can be optimised using Visited List (Note: Visited not Expanded), to avoid loops in a uni-directional graph. Implementing DFS is pretty straight forward using a stack. As you examine a node for any child nodes, add the child nodes to the stack, pop the stack and examine the node on the top of the stack. Doesn't get much simpler than this =). DFS doesn't guarantee a shallowest solutions or any solution if it gets stuck in an infinite loop if a visited list is not used. Iterative Depth-First SearchIDFS, also an Any-path uniformed algorithm, expands nodes or finds its way to the solution almost exactly like Breadth-First search. But BFS memory requirements increase at an exponential rate as it searches deeper. BFS is implemented using a queue (FILO). IDFS has the same memory requirements as DFS but unlike DFS it will find the goal at the shallowest depth like the BFS algorithm. A* (Pronounced A Star)Accepted as one of the best search algorithms, it is categorised as an Optimal Informed algorithm. The algorithm uses a heuristic which is an estimate of the straight line distance to the goal in a search space. It has to be a straight line distance because A* will only find the optimal path to the goal if the heuristic (estimate) is admissible; admissible meaning less than or equal to the actual distance to the goal. Using the CodeAll the algorithms are programmed quite similarly so I’ll just explain the first and easiest one: DFS. As you may already know DFS is implemented using a stack. A state is examined and all possible states that can lead on to from that state get added on to the stack. The stack is then popped to retrieve the top most state that was pushed on top, examined to see if it is the goal state if not examine any paths than lead to other states and so on. //I store a state as a 2-dimensional double array. Each element can be thought of as //a square on the 8 puzzle. class State { public Double[][] xPuzzle = new Double[3][]; public Double[][] yPuzzle = new Double[3][]; } static public void initializeArray() { for (int i = 0; i < 3; i++) { xPuzzle[i] = new Double[3]; yPuzzle[i] = new Double[3]; } } The WPF canvas (container for the 8-puzzle images) is 300px square. Each square is 100px. So each element in the array xPuzzle and yPuzzle store the x and y values of the position of the squares. Possible values can only be from the set {0, 100, 200} so each square can only be in 1 out of the 9 possible positions on the canvas. This forms the basis of storing each representing a particular state for the 8-puzzle. I hope I have explained this properly. You should now know how DFS is supposed to work and how I have implemented an 8-puzzle state in c#. The way I animated the squares is using the protected void UpdatePuzzle() { DoubleAnimation xBox1 = new DoubleAnimation(PuzzleData.xPuzzle[0][0], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox2 = new DoubleAnimation(PuzzleData.xPuzzle[0][1], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox3 = new DoubleAnimation(PuzzleData.xPuzzle[0][2], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox4 = new DoubleAnimation(PuzzleData.xPuzzle[1][0], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox5 = new DoubleAnimation(PuzzleData.xPuzzle[1][1], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox6 = new DoubleAnimation(PuzzleData.xPuzzle[1][2], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox7 = new DoubleAnimation(PuzzleData.xPuzzle[2][0], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox8 = new DoubleAnimation(PuzzleData.xPuzzle[2][1], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation xBox9 = new DoubleAnimation(PuzzleData.xPuzzle[2][2], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox1 = new DoubleAnimation(PuzzleData.yPuzzle[0][0], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox2 = new DoubleAnimation(PuzzleData.yPuzzle[0][1], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox3 = new DoubleAnimation(PuzzleData.yPuzzle[0][2], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox4 = new DoubleAnimation(PuzzleData.yPuzzle[1][0], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox5 = new DoubleAnimation(PuzzleData.yPuzzle[1][1], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox6 = new DoubleAnimation(PuzzleData.yPuzzle[1][2], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox7 = new DoubleAnimation(PuzzleData.yPuzzle[2][0], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox8 = new DoubleAnimation(PuzzleData.yPuzzle[2][1], TimeSpan.FromMilliseconds(AnmSpeed)); DoubleAnimation yBox9 = new DoubleAnimation(PuzzleData.yPuzzle[2][2], TimeSpan.FromMilliseconds(AnmSpeed)); //The statement below is basically an eventhandler for when the blank square's //animation stops. The Event handler is called the method Shuffle_Complete is //ShuffleDonw flag is not set and shuffleOn flag is set. This is how it loops //however many number of times defined in the Shuffle class. Look at Shuffle //Class for more info. if ((!Shuffle.shuffleDone)&&(Shuffle.shuffleOn)) { xBox9.Completed += new EventHandler(Shuffle_Completed); } //The statments below start the horizontal animation for each box. Box1.BeginAnimation(Canvas.LeftProperty, xBox1); Box2.BeginAnimation(Canvas.LeftProperty, xBox2); Box3.BeginAnimation(Canvas.LeftProperty, xBox3); Box4.BeginAnimation(Canvas.LeftProperty, xBox4); Box5.BeginAnimation(Canvas.LeftProperty, xBox5); Box6.BeginAnimation(Canvas.LeftProperty, xBox6); Box7.BeginAnimation(Canvas.LeftProperty, xBox7); Box8.BeginAnimation(Canvas.LeftProperty, xBox8); Box9.BeginAnimation(Canvas.LeftProperty, xBox9); //The statements below start the vertical animation for each box. Box1.BeginAnimation(Canvas.TopProperty, yBox1); Box2.BeginAnimation(Canvas.TopProperty, yBox2); Box3.BeginAnimation(Canvas.TopProperty, yBox3); Box4.BeginAnimation(Canvas.TopProperty, yBox4); Box5.BeginAnimation(Canvas.TopProperty, yBox5); Box6.BeginAnimation(Canvas.TopProperty, yBox6); Box7.BeginAnimation(Canvas.TopProperty, yBox7); Box8.BeginAnimation(Canvas.TopProperty, yBox8); Box9.BeginAnimation(Canvas.TopProperty, yBox9); } This is how I animate the squares. They x and y positions for each of the square are stored in an array and I animate all of them every iteration. So if a square hasn't moved it's position than it won't obviously animate. I have attached an animation compelete event handler to just one of the squares. This event starts the next iteration of the particular algorithm being used and so on. How I implemented a search algorithmLets take the dfs algorithm for example. Solving algorithm requires using certain data structures such as a queue, stack list etc. For dfs we will be using a stack as we need a first in first out (FIFO) data structure to store our states.
You probably picked up that there could be the algorithm as it is now doesn't cater for inifinite loops. You can modify the algorithm slightly by using a expanded list to keep track of all the nodes you have examined. This is what I have done in this application. A node or a state in my application is a the combined combination of two 2-d arrays storing the position of the 8 squares. So yea just download the application and just have a play around with it. You will probably get a much better understanding that way to see what's actually going on. Points of InterestWPF is the coolest thing ever for leveraging your video card capabilities in everyday apps don't you think..? I lost all my updates with A* algorithm (darn crappy source code management) so it doesn't work like it should at all... If you can fix it before I can restore it to how it was, please do so and post an update. Cheers. Also like I mentioned before I wanted to show how different algorithms solve the puzzle in different ways. And I think i've done that really well. If you try out both dfs and progressive dfs you can really see the difference of how using different algorithms impact the steps taken to reach the goal. I use a expanded list for dfs by the way as 8-puzzle can have infinite loops in it's search space. Signing offThis is my first article and I just wanted to share something that I thought was pretty cool, and I hope someone finds it useful. I realize it's pretty summarized but just wanted to get something out there. You may use the ideas however you like and do whatever you want with the source, only thing I ask is please give credit where it's due. If you really this article please do vote for me (it doesn't take much you know =P ). Thanks heaps... HistoryCorrected a few spelling mistakes here and there and semantic errors. Thanks to: Manuel & Ravi Cheers for pointing out the errors =)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||