HW05 due 03/31

advertisement
CmSc310 Artificial Intelligence
Homework 05, due 03/31
This assignment is to implement the A* algorithm as applied to the 8-puzzle.
The 8-puzzle is a small board game for a single player; it consists of 8 square tiles
numbered 1 through 8 and one blank space on a 3 x 3 board. Moves of the puzzle are
made by sliding an adjacent tile into the position occupied by the blank space, which has
the effect of exchanging the positions of the tile and blank space. Only tiles that are
horizontally or vertically adjacent (not diagonally adjacent) may be moved into the blank
space.
Requirements:
1. The user has a choice to solve the puzzle for a randomly generated board or for a
board entered by the user
2. The user chooses the evaluation function – tikes-out-of-place or Manhattan
distance
In general, the program organization is the same as the organization of the hopover
program. The difference lies in the way the next node to be expanded is chosen – in the
8-puzzle program nodes are evaluated and inserted in a priority queue. At each iteration
of the “while priority queue not empty” loop, the best node is chosen. Another difference
is that in the 8-puzzle program we need to check for repeated states, while in the
hop_over program such check is not necessary.
Data structures needed:
a. node representation (class Puzzle8)
 an array to represent the 8-puzzle. As discussed in class, this may
be a 1D array where each tile is represented by its index in the goal
state.
For example, let the initial and the goal state be:
5 4 3
1 8 _
6 7 2
1 2 3
4 5 6
7 8 _
The goal representation would be: 0 1 2 3 4 5 6 7 8
The initial representation would be: 4 3 2 0 7 8 5 6 1
Of course, you may choose a different representation of the board.
 the position of the empty tile
 the index of the parent of the node in the search tree
 the operator applied to obtain the node.
 The h(n) component of the heuristic function. When h(n) becomes
0, we have reached the goal.
1
 The g(n) component of the heuristic function – representing the
level of that node in the search tree (the number of the edges from
that node to the root.
There are 4 operations in the 8-puzzle:
slide tile up
slide tile down
slide tile left
slide tile right
b. A priority queue
c. An array to keep all generated nodes
The algorithm for generating new nodes from a given node is:
1. Initialize the starting node with the initial state of the 8-puzzle, compute the
heuristic function f = h + g (for the root g = 0), store it in the array of nodes,
and insert its index in the priority queue.
2. Main loop: while priority queue not empty and the array of states is not full
and goal not found:
a. deleteMin an index of a node from the priority queue
b. if it is not the goal,
b.1. apply the four operations: move up, move down, move left,
move right,
b.2. for each operation: check its preconditions
b.2.1. if applicable, construct the new node
b.2.2. if not repeated state
store in the array of nodes,
insert its index in the priority queue
3. After the loop:
print the solution as a sequence of board configurations and the applied
operator, and the number of generated nodes, e. g. (the empty position is
encoded as “0”)
Initial state:
2 4 5
0 1 7
3 8 6
------ apply op:
0 4 5
2 1 7
3 8 6
move down
------ apply op:
4 0 5
move left
2
2 1 7
3 8 6
..........
------ apply op:
1 2 3
4 5 6
7 8 0
move up
Nodes generated = 5430
Hints:
A. program organization
You need to create a class Puzzle8 that represents each node in the search tree. It
will contain a method to apply the 4 operations (you can use a switch statement similar to
the hop_over program) and a method to evaluate each state. It may contain additional
supporting methods such as printing the board.
The main class will contain the “while queue not empty” loop, and a method to
print the solution (see how the solution is printed recursively in the jugs program)
B. Implementation
1. Initializing the starting node.
You may explicitly specify the array that represents the board (convenient for
debugging purposes), use user input (a lot of typing) or write a generator to scramble the
goal state.
When you test your program, start with an easy example – one that requires two –
three movements to get to the goal. If something goes wrong you will be able to trace
your program. For a more extensive test you may use initial states taken from
http://www.permadi.com/java/puzzle8/ or a generator of initial states. Note that not all
configurations of the board have solutions, that is why the generator has to scramble the
goal state (by applying the four operations).
Design carefully the constructor of the class representing the nodes in the search
tree. Besides the board, it will need the position of the empty space (may be passed as an
argument, or computed in the constructor.
Initialize appropriately the parent of the initial state and the value for the op code.
Finally, you need to specify the values “h” and “g” for the heuristic function.
Since the evaluation is a method of the puzzle class, the node needs first to be created
(without the heuristic values, then evaluated and then values for “h” and “g” have to be
recorded in the node. You may write methods that update the values of the private
variables, or declare the variables as public and update them in the main method.
2. Accessing the priority queue
The priority queue manipulates objects of type Cell with 2 components – the
index of the node in the array of nodes and the priority – this is the value of the heuristic
function f = h + g.
3
At each insert, you have to create a new object of type Cell, assign appropriate
values to its components and then insert it in the priority queue.
The deleteMin operation returns an object of type Cell, and from there you have
to retrieve the index of the node, access the node, etc.
3. Operations
You can implement the four operations in one method using a switch statement
within a method of the Puzzle8 class. You have to copy the parent node (the one retrieved
by the index removed from the priority queue) into a new node and then apply the
operations method to that new node. The call to the operations method is done in the
main method within a “for” loop (similar to the hopover program). Copy the parent node
immediately before calling the operations method.
4. Checking preconditions
Each operation checks if the movement is possible.
a. Slide up: not possible if the empty place is in the last row. Check the index of
the empty space.
b. Slide down: not possible if the empty place is in the first row. Check the index
of the empty place.
c. Slide left: not possible if the empty position is in the last column. Apply mod 3
operation to the index of the empty place, if the result is 2 then “slide left” is not possible.
d. Slide right: not possible if the empty position is in the first column. Apply mod
3 operation to the index of the empty space. If the result is 0 then “slide right” is not
possible.
5. Generating a new state
If the preconditions are satisfied, the operation is performed and the child node
has its board set up. What remains to be done is to assign the appropriate values to the
other components of the node – the position of the empty space, the index of the parent,
the code of the operation, and the value of the heuristic function for that node. Some of
these actions should be done by the operations method, and some – in the main method.
6. Evaluating the state
The evaluation method should be part of the Puzzle8 class. Implement the “tiles
out of place” heuristics and the “Manhattan distance”. In the “tiles out of place”
heuristics, the value of the “h” component of the heuristic function is equal to the number
of the tiles not in their position. In the “Manhattan distance” heuristics, the value of the
“h” component of the heuristic function is equal to the sum of the distances of each tile
from its current position to its target position. The distance is measured in terms of
“blocks”. When h = 0 we have reached the goal state.
The other component, g, is equal to the level of the node in the search tree, it is
equal to its parent's g plus 1.
4
Note that the node records separately the “h” and “g” component of the heuristic
value, however in the priority queue the sum of h and g is used as the priority of the node.
7. Checking for repeated states.
The check for repeated states should be done along the path form the node under
examination to the root of the search tree. It consists in comparing the board of the
current node with the board of each node along the path from the current node to the root.
See how this is done in the jugs program. You may write a separate method to compare
the boards of two nodes. It might be part of the Puzzle8 class, or you may put it in the
main program.
8. Checking for a goal state
The check for a goal state can be done before a node is inserted in the priority
queue or immediately after a node is taken out of the priority queue. If the “h” value for
that node is 0, then this is the goal.
9. Printing the solution path
The solution path is printed recursively, using the array of states (called ‘array’
below):
printPath (currentIndex, array)
{
if currentIndex = 0
// terminating condition
print board of array[0]
else
parent = array[currentIndex].parent
printPath(parent, array)
print operation of array[parent]
print board of array[parent]
}
Note that “print board” will depend on how you choose to represent the board.
10. In the main loop there is a check “and array of states not full”. This is convenient to
have so that your program does not end abruptly with a run time error in case the number
of generated states exceeds the declared size of the array of states.
Use as guidelines the comments to the Puzzle8 and PuzzlePlay classes given below:
Puzzle8:
* Methods:
* Constructors
*
public Puzzle8 ()
*
public Puzzle8(int [] board, int empty, int parent, int g, int h)
* Methods:
*
public boolean operations(int opCode, int parent)
*
opCode codes for the move: up, down, left, right
*
the parent is needed to prevent repeating the previous move
*
5
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
The method is organized around a switch statement by opCode
For each move the prerequisites are checked and if met,
the move is applied, changing the board and the index
of the empty tile.
Returned value: true if the operation is applied,
false otherwise
public int evaluate(int heuristics)
Evaluates the board
heuristics = 1: using number of tiles out of place
heuristics = 2: using Manhattan distance
public void printTiles(int [] goal)
the goal board is needed because the board representation is by
indexes of the tiles in the goal state
public Puzzle8 copyNode()
creates and returns a new node, a copy of the current.
used to create children
public void printAll()
used for debugging purposes
PuzzlePlay
* PuzzlePlay
*
* This is the driver for solving the 8-Puzzle using A* algorithm.
*
* A. Board representation:
* The 3 x 3 square is represented by a 1D array.
* goal state: array of type int goal: goal[i] = k, k = tile face,
*
empty tile is 0
* Example:
*
goal:
1 2 3
*
8 _ 4
*
7 6 5
*
representation: [1,2,3,8,0,4,7,6,5]
*
* The board of each current state is represented in the following way:
* Each tile is represented by its index in the goal board.
* Example:
*
current board:
*
6 8 1
*
_ 7 3
*
5 4 2
*
with respect to the goal above, the representation is:
*
board: [7, 3, 0, 4, 6, 2, 8, 5, 1]
*
board[8] = 1 represents tile 2 (the last in the current board), which
*
has index 1 in the representation of the goal
*
board[0] = 7 represents tile 6, with index 7 in the goal array
*
* Thus, for any goal when the board satisfies the condition board[i] = i,
* we have reached the goal state
*
* B. Generating the initial state.
*
there are two options of generating the initial state:
*
a) automatically
*
The generation starts with the goal state and then
*
100 times randomly choosing moves to apply.
*
Note that not all moves can be applied
*
b) entered by the user as a sequence of tiles,
6
*
with empty tile represented by 0
*
The user input is checked for validity
*
* C. Heuristics
*
two evaluation methods are implemented in the Puzzle8 class *
number of tiles out of place and Manhatten distance.
*
The user makes the choice of the heuristics
*
*
*
* D. Algorithm
*
Initial state is generated, the board is evaluated and
*
the root node is stored in the statesArray
*
Its index is inserted in the priority queue with priority 0
*
*
While priority queue is not empty
*
and the goal is not found
*
and the states array is not full
*
Get a parent node index from the priority queue
*
If not the goal
*
For each move - up, down, left, right
*
copy the parent into a child
*
call the operations method of the Puzzle8 class
*
to apply the move
*
If the move was applied
*
if the child is unique
*
evaluate the board of the child
*
store in the states array
*
insert its index in the priority queue
*
with priority f = g + h
*
If goal was found
*
print the solution
*
7
Download