Path: blob/master/languages/python/algorithm_npuzzle.py
1240 views
#!/usr/bin/python1# -*- coding: utf-8 -*-2# vim: ts=4 sw=4 et ai ff=unix ft=python nowrap3#4# Program: npuzzle.py5#6# Description: Solves the N-Puzzle Sliding Block Problem.7#8# Usage: python npuzzle.py.9#10# License: GNU GPL Version 2.0. Please refer www.gnu.org.1112import random131415class State:1617def __init__(self, nsize):18"""Initialze the n-puzzle problem, with n-size value, tsize the total nodes and initial the goal state from n.19"""2021self.nsize = nsize22self.tsize = pow(self.nsize, 2)23self.goal = list(range(1, self.tsize))24self.goal.append(0)2526def printst(self, st):27"""Print the list in a Matrix Format."""2829for (index, value) in enumerate(st):30print(' %s ' % value, end=' ')31if index in [x for x in range(self.nsize - 1, self.tsize,32self.nsize)]:33print()34print()3536def getvalues(self, key):37"""Utility function to gather the Free Motions at various key positions in the Matrix."""3839values = [1, -1, self.nsize, -self.nsize]40valid = []41for x in values:42if 0 <= key + x < self.tsize:43if x == 1 and key in range(self.nsize - 1, self.tsize,44self.nsize):45continue46if x == -1 and key in range(0, self.tsize, self.nsize):47continue48valid.append(x)49return valid5051def expand(self, st):52"""Provide the list of next possible states from current state."""5354pexpands = {}55for key in range(self.tsize):56pexpands[key] = self.getvalues(key)57pos = st.index(0)58moves = pexpands[pos]59expstates = []60for mv in moves:61nstate = st[:]62(nstate[pos + mv], nstate[pos]) = (nstate[pos], nstate[pos +63mv])64expstates.append(nstate)65return expstates6667def one_of_poss(self, st):68"""Choose one of the possible states."""6970exp_sts = self.expand(st)71rand_st = random.choice(exp_sts)72return rand_st7374def start_state(self, seed=1000):75"""Determine the Start State of the Problem."""7677start_st = (self.goal)[:]78for sts in range(seed):79start_st = self.one_of_poss(start_st)80return start_st8182def goal_reached(self, st):83"""Check if the Goal Reached or Not."""8485return st == self.goal8687def manhattan_distance(self, st):88"""Calculate the Manhattan Distances of the particular State.89Manhattan distances are calculated as Total number of Horizontal and Vertical moves required by the values in the current state to reach their position in the Goal State.90"""9192mdist = 093for node in st:94if node != 0:95gdist = abs(self.goal.index(node) - st.index(node))96(jumps, steps) = (gdist // self.nsize, gdist % self.nsize)97mdist += jumps + steps98return mdist99100def huristic_next_state(self, st):101"""This is the Huristic Function. It determines the next state to follow and uses Mahattan distances method as the huristics. This this determined way, a A* approach for path finding is used.102If more than one path have same manhattan distance, then a random choice of one of them is analyzed and carried forward. If not best path, randomness to providethe other choice is relied upon. No Depth First search is Used."""103104exp_sts = self.expand(st)105mdists = []106for st in exp_sts:107mdists.append(self.manhattan_distance(st))108mdists.sort()109short_path = mdists[0]110if mdists.count(short_path) > 1:111least_paths = [st for st in exp_sts if self.manhattan_distance(st) == short_path]112return random.choice(least_paths)113else:114for st in exp_sts:115if self.manhattan_distance(st) == short_path:116return st117118def solve_it(self, st):119while not self.goal_reached(st):120st = self.huristic_next_state(st)121self.printst(st)122123124if __name__ == '__main__':125print('N-Puzzle Solver!')126print(10 * '-')127state = State(3)128print('The Starting State is:')129start = state.start_state(5)130state.printst(start)131print('The Goal State should be:')132state.printst(state.goal)133print('Here it Goes:')134state.printst(start)135state.solve_it(start)136137138139140