# Assignment 2: Iterative-Deepening Search¶

• A2.1: New A2grader.tar and modified explanation of one of the depth_limited_search results.

## Overview¶

Implement the iterative-deepening search algorithm as discussed in our lecture notes and as shown in figures 3.17 and 3.18 in our text book. Apply it to the 8-puzzle and a second puzzle of your choice.

## Required Code¶

In this jupyter notebook, implement the following functions:

• iterative_deepening_search(start_state, goal_state, actions_f, take_action_f, max_depth)
• depth_limited_search(start_state, goal_state, actions_f, take_action_f, depth_limit)

depth_limited_search is called by iterative_deepening_search with depth_limits of $0, 1, \ldots,$ max_depth. Both must return either the solution path as a list of states, or the strings 'cutoff' or 'failure'. 'failure' signifies that all states were searched and the goal was not found.

• the starting state,
• the goal state,
• a function actions_f that is given a state and returns a list of valid actions from that state,
• a function take_action_f that is given a state and an action and returns the new state that results from applying the action to the state,
• either a depth_limit for depth_limited_search, or max_depth for iterative_deepening_search.

Use your solution to solve the 8-puzzle. Implement the state of the puzzle as a list of integers. 0 represents the empty position.

Required functions for the 8-puzzle are the following.

• find_blank_8p(state): return the row and column index for the location of the blank (the 0 value).
• actions_f_8p(state): returns a list of up to four valid actions that can be applied in state. Return them in the order left, right, up, down, though only if each one is a valid action.
• take_action_f_8p(state, action): return the state that results from applying action in state.
• print_state_8p(state): prints the state as a 3 x 3 table, as shown in lecture notes, or a bit fancier with, for example, '-' and '|' characters to separate tiles. This function is useful to call when debugging your search algorithms.
• print_path_8p(start_state, goal_state, path): print a solution path in a readable form by calling print_state_8p.

Also, implement a second search problem of your choice. Apply your iterative_deepening_search function to it.

Here are some example results.

In [34]:
start_state = [1, 0, 3, 4, 2, 5, 6, 7, 8]

In [35]:
print_state_8p(start_state)

 1 - 3
4 2 5
6 7 8

In [36]:
find_blank_8p(start_state)

Out[36]:
(0, 1)
In [37]:
actions_f_8p(start_state)

Out[37]:
['left', 'right', 'down']
In [38]:
take_action_f_8p(start_state, 'down')

Out[38]:
[1, 2, 3, 4, 0, 5, 6, 7, 8]
In [39]:
print_state_8p(take_action_f_8p(start_state, 'down'))

 1 2 3
4 - 5
6 7 8

In [40]:
goal_state = take_action_f_8p(start_state, 'down')

In [41]:
new_state = take_action_f_8p(start_state, 'down')

In [42]:
new_state == goal_state

Out[42]:
True
In [43]:
start_state

Out[43]:
[1, 0, 3, 4, 2, 5, 6, 7, 8]
In [47]:
path = depth_limited_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 1)
path

Out[47]:
[[1, 2, 3, 4, 0, 5, 6, 7, 8]]

Notice that depth_limited_search result is missing the start state. This is inserted by iterative_deepening_search.

In [48]:
path = depth_limited_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 2)
path

Out[48]:
[[1, 2, 3, 4, 0, 5, 6, 7, 8]]
In [49]:
path = depth_limited_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 3)
path

Out[49]:
[[0, 1, 3, 4, 2, 5, 6, 7, 8],
[1, 0, 3, 4, 2, 5, 6, 7, 8],
[1, 2, 3, 4, 0, 5, 6, 7, 8]]

Here depth_limited_search returns more than the solution path. This is due to how we implement depth_limited_search. This only happens when we don't find the shortest path. Of course, when called from iterative_deepening_search we do find the shortest path.

In [50]:
path = iterative_deepening_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 4)
path

Out[50]:
[[1, 0, 3, 4, 2, 5, 6, 7, 8], [1, 2, 3, 4, 0, 5, 6, 7, 8]]

Also notice that the successor states are lists, not tuples. This is okay, because the search functions for this assignment do not make use of python dictionaries.

In [14]:
start_state = [4, 7, 2, 1, 6, 5, 0, 3, 8]
path = iterative_deepening_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 3)
path

Out[14]:
'cutoff'
In [15]:
start_state = [4, 7, 2, 1, 6, 5, 0, 3, 8]
path = iterative_deepening_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 5)
path

Out[15]:
'cutoff'

Humm...maybe we can't reach the goal state from this state. We need a way to randomly generate a valid start state.

In [16]:
import random

In [17]:
random.choice(['left', 'right', 'down', 'up'])

Out[17]:
'down'
In [20]:
def random_start_state(goal_state, actions_f, take_action_f, n_steps):
state = goal_state
for i in range(n_steps):
state = take_action_f(state, random.choice(list(actions_f(state))))  # list required because actions_f is generator
return state

In [21]:
goal_state = [1, 2, 3, 4, 0, 5, 6, 7, 8]
random_start_state(goal_state, actions_f_8p, take_action_f_8p, 10)

Out[21]:
[1, 2, 3, 4, 7, 5, 0, 6, 8]
In [22]:
start_state = random_start_state(goal_state, actions_f_8p, take_action_f_8p, 50)
start_state

Out[22]:
[1, 3, 8, 4, 2, 7, 6, 5, 0]
In [23]:
path = iterative_deepening_search(start_state, goal_state, actions_f_8p, take_action_f_8p, 20)
path

Out[23]:
[[1, 3, 8, 4, 2, 7, 6, 5, 0],
[1, 3, 8, 4, 2, 0, 6, 5, 7],
[1, 3, 0, 4, 2, 8, 6, 5, 7],
[1, 0, 3, 4, 2, 8, 6, 5, 7],
[1, 2, 3, 4, 0, 8, 6, 5, 7],
[1, 2, 3, 4, 5, 8, 6, 0, 7],
[1, 2, 3, 4, 5, 8, 6, 7, 0],
[1, 2, 3, 4, 5, 0, 6, 7, 8],
[1, 2, 3, 4, 0, 5, 6, 7, 8]]

Let's print out the state sequence in a readable form.

In [24]:
for p in path:
print_state_8p(p)
print()

 1 3 8
4 2 7
6 5 -

1 3 8
4 2 -
6 5 7

1 3 -
4 2 8
6 5 7

1 - 3
4 2 8
6 5 7

1 2 3
4 - 8
6 5 7

1 2 3
4 5 8
6 - 7

1 2 3
4 5 8
6 7 -

1 2 3
4 5 -
6 7 8

1 2 3
4 - 5
6 7 8



Here is one way to format the search problem and solution in a readable form.

In [25]:
print_path_8p(start_state, goal_state, path)

Path from
1 3 8
4 2 7
6 5 -
to
1 2 3
4 - 5
6 7 8
is 9 nodes long:
1 3 8
4 2 7
6 5 -

1 3 8
4 2 -
6 5 7

1 3 -
4 2 8
6 5 7

1 - 3
4 2 8
6 5 7

1 2 3
4 - 8
6 5 7

1 2 3
4 5 8
6 - 7

1 2 3
4 5 8
6 7 -

1 2 3
4 5 -
6 7 8

1 2 3
4 - 5
6 7 8



In [27]:
%run -i A2grader.py

======================= Code Execution =======================

Extracting python code from notebook named 'Anderson-A2.ipynb' and storing in notebookcode.py
Removing all statements that are not function or class defs or import statements.

Searching this graph:
{'a': ['b', 'z', 'd'], 'b': ['a'], 'e': ['z'], 'd': ['y'], 'y': ['z']}

Looking for path from a to y with max depth of 1.
5/ 5 points. Your search correctly returned cutoff

Looking for path from a to z with max depth of 5.
10/10 points. Your search correctly returned ['a', 'z']

Testing find_blank_8p([1, 2, 3, 4, 5, 6, 7, 0, 8])
5/ 5 points. Your find_blank_8p correctly returned 2 1

Testing actions_f_8p([1, 2, 3, 4, 5, 6, 7, 0, 8])
10/10 points. Your actions_f_8p correctly returned ['left', 'right', 'up']

Testing take_action_f_8p([1, 2, 3, 4, 5, 6, 7, 0, 8], up)
10/10 points. Your take_actions_f_8p correctly returned [1, 2, 3, 4, 0, 6, 7, 5, 8]

Testing iterative_deepening_search([1, 2, 3, 4, 5, 6, 7, 0, 8],
[0, 2, 3, 1, 4,  6, 7, 5, 8],
actions_f_8p, take_action_f_8p, 5)
20/20 points. Your search correctly returned
[1, 2, 3, 4, 5, 6, 7, 0, 8]
[1, 2, 3, 4, 0, 6, 7, 5, 8]
[1, 2, 3, 0, 4, 6, 7, 5, 8]
[0, 2, 3, 1, 4, 6, 7, 5, 8]

Testing iterative_deepening_search([5, 2, 8, 0, 1, 4, 3, 7, 6],
[0, 2, 3, 1, 4,  6, 7, 5, 8],
actions_f_8p, take_action_f_8p, 10)
10/10 points. Your search correctly returned cutoff.

======================================================================
notebooks Execution Grade is 70 / 70
======================================================================

__ / 10 points. At least four sentences describing the solutions found for the 8 puzzle.

__ / 20 points. At least six sentences describing the second search problem, your implementation
of state, and the solutions found.

======================================================================
======================================================================

======================================================================
notebooks FINAL GRADE is  _  / 100
======================================================================

Extra Credit: Earn one point of extra credit for using your search functions to solve the variation
of the grid problem in Assignment 1.

notebooks EXTRA CREDIT is 0 / 1


Check in your notebook for Assignment 2 on our Canvas site.

## Extra Credit¶

For extra credit, apply your solution to the grid example in Assignment 1 with the addition of at least one horizontal and at least one vertical barrier, all at least three positions long. Demonstrate the solutions found in four different pairs of start and goal states.