In [1]:
%%HTML
<style>
.container { width:100% }
</style>
The class deque from the module collections provides doubly linked lists that can be used as stacks.
In [2]:
from collections import deque
The function search
takes three arguments to solve a search problem:
start
is the start state of the search problem,goal
is the goal state, andnext_states
is a function with signature $\texttt{next_states}:Q \rightarrow 2^Q$, where $Q$ is the set of states.
For every state $s \in Q$, $\texttt{next_states}(s)$ is the set of states that can be reached from $s$ in one step.
If successful, search
returns a path from start
to goal
that is a solution of the search problem
$$ \langle Q, \texttt{next_states}, \texttt{start}, \texttt{goal} \rangle. $$The implementation of search
works as follows:
Stack
.Stack
, we have a dictionary Parent
.
For every state $s$ that is on Stack
, $\texttt{Parent}[s]$ returns a state $p$ such that $s \in \texttt{next_states}(p)$,
i.e. $p$ is the state that immediately precedes $s$ on the path that leads from start
to $s$. Stack
only contains the state start
.Stack
is not empty, the state
on top of Stack
is replaced by all states that be reached in one step
from state
. However, in order to prevent depth first search to run in circles, only those states ns
from the set
next_states(state)
are appended to Stack
that have not been encountered previously. This is checked by testing
whether ns
is in the domain of Parent
.goal
is reached, a path leading from start
to goal
is returned.
In [3]:
def search(start, goal, next_states):
Stack = deque([start])
Parent = { start: start }
while len(Stack) > 0:
state = Stack.pop()
for ns in next_states(state):
if ns == goal:
return path_to(state, Parent) + [goal]
if ns not in Parent:
Parent[ns] = state
Stack.append(ns)
Given a state
and a parent dictionary Parent
, the function path_to
returns a path leading to the given state
.
In [4]:
def path_to(state, Parent):
p = Parent[state]
if p == state:
return [state]
return path_to(p, Parent) + [state]
In [5]:
%run Sliding-Puzzle.ipynb
We need to import sys
in order to increase the
recursion limit.
In [6]:
import sys
In [7]:
sys.setrecursionlimit(10000)
In [8]:
%%time
Path = search(start, goal, next_states)
print(len(Path)-1)
In [ ]: