8puzzle.py
author Eugen Sawin <sawine@me73.com>
Thu, 26 May 2011 23:26:48 +0200
changeset 1 94fc07d1e2e1
permissions -rw-r--r--
Added A* puzzle exercise.
     1 """
     2 Name: A* on 8 puzzle
     3 Author: Eugen Sawin <sawine@informatik.uni-freiburg.de>
     4 """
     5 import heapq
     6 
     7 def main():    
     8     goal = (1, 2, 3, 
     9             8, 0, 4, 
    10             7, 6, 5)
    11     init = (2, 8, 3, 
    12             1, 6, 4, 
    13             7, 0, 5)
    14     print "heuristic: none"
    15     search(init, goal, Heuristic(goal))
    16     print "\nheuristic: misplaced tiles"
    17     search(init, goal, MisplacedTiles(goal))
    18     print "\nheuristic: manhattan distance"
    19     search(init, goal, ManhattanDist(goal))
    20 
    21 def search(init, goal, h): 
    22     frontier = []
    23     print init
    24     print goal
    25     heapq.heapify(frontier)
    26     node = Node(init, None, 0, 0)
    27     heapq.heappush(frontier, (0, node))
    28     explored = set()   
    29     while len(frontier):
    30         k, node = heapq.heappop(frontier)
    31         print k
    32         explored.add(node.state) 
    33         if node.state == goal:
    34             print "goal found in %i steps" % len(explored)
    35             break         
    36         for child in expand(node, h):  
    37             #print child
    38             #print
    39             heapq.heappush(frontier, (child.h_cost, child))
    40         
    41 def expand(node, h):
    42     def swap(i1, i2):
    43         state = list(node.state)       
    44         a = state[i1]
    45         b = state[i2]
    46         state[i1] = b
    47         state[i2] = a
    48         return tuple(state)  
    49 
    50     children = []
    51     cost = node.cost + 1
    52     for i, v in enumerate(node.state):
    53         if v == 0:
    54             if i > 0:
    55                 s = swap(i, i-1)
    56                 children.append(Node(s, node, cost,  h(s) + 1))
    57             if i < 8:
    58                 s = swap(i, i+1)               
    59                 children.append(Node(s, node, cost,  h(s) + 1)) 
    60             if i > 2: 
    61                 s = swap(i, i-3)              
    62                 children.append(Node(s, node, cost,  h(s) + 1))  
    63             if i < 6:
    64                 s = swap(i, i+3)
    65                 children.append(Node(s, node, cost,  h(s) + 1))             
    66     return children      
    67 
    68 class Node(object):
    69     def __init__(self, state, parent, cost, h_cost):
    70         self.state = state
    71         self.parent = parent
    72         self.cost = cost 
    73         self.h_cost = h_cost
    74     def __less__(self, node):
    75         return self.h_cost < node.h_cost
    76     def __str__(self):
    77         return "\n".join((str(self.state[:3]), 
    78                           str(self.state[3:6]), 
    79                           str(self.state[6:])))
    80 
    81 class Heuristic(object):
    82     def __init__(self, goal):
    83         self.goal = goal
    84     def __call__(self, state):
    85         return 0
    86 
    87 class MisplacedTiles(Heuristic):
    88    def __call__(self, state):       
    89        h = 0
    90        for i, s in enumerate(state):
    91            if self.goal[i] != s:
    92                h += 1       
    93        return h
    94 
    95 class ManhattanDist(Heuristic):
    96    def __call__(self, state):       
    97        h = 0
    98        for i, s in enumerate(state):
    99            for i2, s2 in enumerate(self.goal):
   100                if s == s2:
   101                    d = abs(i-i2)
   102                    h += d%3 + int(d/3)      
   103        return h
   104     
   105 from argparse import ArgumentParser
   106 
   107 def parse_arguments():
   108     parser = ArgumentParser(description="8 puzzle")   
   109     return parser.parse_args()
   110 
   111 if __name__ == "__main__":
   112     main()