Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class PuzzleNode:
- def __init__(self, n, state):
- self.n = n
- self.tablesize = n**2
- self.goal = []
- self.state = state
- def __str__(self, state):
- #Visualizes the table
- t = " | "
- s = " ----"
- print s * (self.n)
- for i in self.state:
- counter , u = 0, t
- while counter < len(i):
- u += str(i[counter]) + t
- counter += 1
- print u
- print s * (self.n)
- def place_heuristic(state):
- #A heuristic function which is based on the number of tiles in their misplaced place.
- #It first checks the type of data which the input comes in(string or list of list), and then works with it accordingly.
- if type(state) == str:
- state = eval(state)
- elif type(state) == list:
- pass
- # We know an element is misplaced when the index of that element is not equal to that element
- flat_statelist = [item for sublist in state for item in sublist]
- misplacedcounter = 0
- for element in flat_statelist:
- if flat_statelist.index(element) != element:
- misplacedcounter += 1
- return misplacedcounter
- def Manhattan_heuristic(state):
- #A heuristic function which is based on the manhattan distance of a tile from it's ideal position
- #Again, it first checks the type of data which the input comes in(string or list of list), and then works with it accordingly.
- if type(state) == str:
- state = eval(state)
- elif type(state) == list:
- pass
- flat_statelist = [item for sublist in state for item in sublist]
- flat_goallist = range(0, len(flat_statelist))
- mandistance = 0
- #We use it's modular arthmetic to get it's x and y coordinates in the grid. The manhattan distance is the sum of all these x
- #and y coordinates for each of the tiles
- for element in flat_statelist:
- distance = abs(flat_goallist.index(element) - flat_statelist.index(element))
- xcoord, ycoord = distance//len(state[0]), distance%len(state[0])
- mandistance += xcoord + ycoord
- return mandistance
- def myheuristic(state):
- #This is my attempt at the linear conflict heuristic function. It is a type of heuristic that incorporates the manhattan distance and increases it based
- #on whether or not a condition is satisfied. It's better than the Manhattan heuristic in principle because it incorporates it in it's design, and thus can't be
- #worse than it.
- #Again, it first checks the type of data which the input comes in(string or list of list), and then works with it accordingly.
- if type(state) == str:
- state = eval(state)
- elif type(state) == list:
- pass
- flat_statelist = [item for sublist in state for item in sublist]
- flat_goallist = range(0, len(flat_statelist))
- mydistance = 0
- #It checks for two tiles whether or not they are in the same row in the goal state, and the present state, and
- # adds 2 to the manhattan distance if they are across each other as they would have been in the goal state
- for i in range(len(state[0])):
- for j in state[i]:
- for k in state[i]:
- if j and k in goalstate(state)[i] and (flat_goallist.index(j) - flat_statelist.index(j) > 0 and flat_goallist.index(k) - flat_statelist.index(k) < 0) or (flat_goallist.index(j) - flat_statelist.index(j) < 0 and flat_goallist.index(k) - flat_statelist.index(k) > 0):
- mydistance += 2
- return mydistance/2 + Manhattan_heuristic(state)
- #Creating list heuristics which is a pointer to both heuristics created
- heuristics = [place_heuristic, Manhattan_heuristic, myheuristic]
- def goalstate(state):
- flat_statelist = [item for sublist in state for item in sublist]
- flat_goallist = range(0, len(flat_statelist))
- goal = []
- glstcounter = 0
- for j in range(len(state[0])):
- goal.append(range(glstcounter, glstcounter + len(state[0])))
- glstcounter += len(state[0])
- return goal
- def moves(inputs, n):
- #Move generator, takes in a state and the different possible next moves
- storage = []
- inputs = str(inputs)
- move = eval(inputs)
- i = 0
- while 0 not in move[i]: i += 1
- j = move[i].index(0); # blank space (zero)
- # Sets boundary for the topmost cells. Allows for downward movement of adjacent cells if they aren't at the topmost edge.
- if i > 0:
- move[i][j], move[i - 1][j] = move[i - 1][j], move[i][j];
- storage.append(str(move))
- move[i][j], move[i - 1][j] = move[i - 1][j], move[i][j];
- # Sets boundary for the bottommost cells. Allows for upward movement of adjacent cells if they aren't at the bottommost edge.
- if i < n-1:
- move[i][j], move[i + 1][j] = move[i + 1][j], move[i][j]
- storage.append(str(move))
- move[i][j], move[i + 1][j] = move[i + 1][j], move[i][j]
- # Sets boundary for the rightmost cells. Allows for upward movement of adjacent cells if they aren't at the rightmost edge.
- if j > 0:
- move[i][j], move[i][j - 1] = move[i][j - 1], move[i][j]
- storage.append(str(move))
- move[i][j], move[i][j - 1] = move[i][j - 1], move[i][j]
- # Sets boundary for the leftmost cells. Allows for upward movement of adjacent cells if they aren't at the leftmost edge.
- if j < n-1:
- move[i][j], move[i][j + 1] = move[i][j + 1], move[i][j]
- storage.append(str(move))
- move[i][j], move[i][j + 1] = move[i][j + 1], move[i][j]
- return storage
- def Astar(start, finish, heuristic):
- #The A star part of the algorithm
- n = len(start)
- start , finish = str(start), str(finish)
- pathstorage = [[heuristic(start), start]] # optional: heuristic_1
- expanded = []
- expanded_nodes = 0
- while pathstorage:
- i = 0
- for j in range(1, len(pathstorage)):
- if pathstorage[i][0] > pathstorage[j][0]:
- i = j
- path = pathstorage[i]
- pathstorage = pathstorage[:i] + pathstorage[i + 1:]
- finishnode = path[-1]
- if finishnode == finish:
- break
- if finishnode in expanded: continue
- for b in moves(finishnode, n):
- if b in expanded: continue
- newpath = [path[0] + heuristic(b) - heuristic(finishnode)] + path[1:] + [b]
- pathstorage.append(newpath)
- expanded.append(finishnode)
- expanded_nodes += 1
- return expanded_nodes, len(path), path
- def solvePuzzle(n, state, heuristic, prnt):
- flat_statelist = [item for sublist in state for item in sublist]
- flat_goallist = range(0, len(flat_statelist))
- #Part that returns the error code -1
- #It checks if the length of the input is a perfect square, and then if all the leements int
- # he goal state is in the start sstate.
- if len(flat_statelist) != n**2:
- steps, frontierSize, err = 0, 0, -1
- elif True in [i not in flat_statelist for i in range(0,n**2-1)]:
- steps, frontierSize, err = 0, 0, -1
- else:
- steps, frontierSize, solutions = Astar(state,goalstate(state), heuristic)
- err = 0
- #Prints the solutions if the prnt = True
- if prnt == True:
- for i in solutions[1:]:
- t = PuzzleNode(n, eval(i))
- t.__str__(i)
- print "The next step is :"
- return "The frontier size, number of steps and error code are :" , steps, frontierSize, err,
- puzzle = [[7,0,8],[4,6,1],[5,3,2]]
- print solvePuzzle(3, puzzle, heuristics[2], True)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement