diff --git a/Board.py b/Board.py index 41b1924f7abbb5962353d50ed39e704d34489d11..d3432ed6cd3a2968805fc303f3cd1f2469031e3d 100644 --- a/Board.py +++ b/Board.py @@ -1,7 +1,9 @@ import Tile class Board: # List of exit tiles. Only red at the moment - exit_tiles = [(3,-3), (3,-2), (3,-1), (3,0)] + exit_tiles = {'red':[(3,-3), (3,-2), (3,-1), (3,0)], + 'green':[(-3,3),(-2,3),(-1,3),(0,3)], + 'blue':[(0,-3),(-1,-2),(-2,-1),(-3,0)]} """ directions = ['l', 'tl', 'tr', 'r', 'br', 'bl'] moves = {'l':(-1,0), 'tl':(0,-1), 'tr':(1,-1), 'r':(1,0), @@ -29,15 +31,19 @@ class Board: self.pieces = [] self.g = 0 self.f = 0 + self.toMove = [] self.parent = None + def __lt__(self, other): + return (self.f < other.f) + # Returns a list of valid moves for this board state in the form: ((pos_from),(pos_to)) def getMoves(self): valid_moves = [] for piece in self.pieces: # If the piece is on an exit tile, return that piece - if piece.pos in self.exit_tiles: + if piece.pos in self.exit_tiles[piece.colour]: return piece p_r = piece.pos[1]+3 p_q = piece.pos[0]+3 @@ -46,11 +52,11 @@ class Board: continue if self.tiles[p_r + move[1]][p_q + move[0]] is None: - valid_moves.append(((p_q-3, p_r-3),(p_q-3 + move[0], p_r-3 + move[1]))) + valid_moves.append(('m',(p_q-3, p_r-3),(p_q-3 + move[0], p_r-3 + move[1]))) elif p_r + move[1]*2 <= 6 and p_r + move[1]*2 >= 0 and p_q + move[0]*2 <= 6 and p_q + move[0]*2 >= 0: if self.tiles[p_r + move[1]*2][p_q + move[0]*2] is None: - valid_moves.append(((p_q-3, p_r-3),(p_q-3 + move[0]*2, p_r-3 + move[1]*2))) + valid_moves.append(('j',(p_q-3, p_r-3),(p_q-3 + move[0]*2, p_r-3 + move[1]*2))) return valid_moves diff --git a/__pycache__/Block.cpython-36.pyc b/__pycache__/Block.cpython-36.pyc index cca19998a05c47e7c43fcdab353fedf8e2026b3a..acf1176829b08e7bc81689adab3eebd1ff33ce58 100644 Binary files a/__pycache__/Block.cpython-36.pyc and b/__pycache__/Block.cpython-36.pyc differ diff --git a/__pycache__/Board.cpython-36.pyc b/__pycache__/Board.cpython-36.pyc index f9e8f3375bc235d21baf8a21e37f29b5d1235765..59ff8c998f3173122c9a776294ea3b006d6e8b36 100644 Binary files a/__pycache__/Board.cpython-36.pyc and b/__pycache__/Board.cpython-36.pyc differ diff --git a/__pycache__/Piece.cpython-36.pyc b/__pycache__/Piece.cpython-36.pyc index 8b7c34fc71bb2295e61485daec010de8badf2e74..328793a07f0c93a3324c29969ba816760fac2bcc 100644 Binary files a/__pycache__/Piece.cpython-36.pyc and b/__pycache__/Piece.cpython-36.pyc differ diff --git a/game.cprof b/game.cprof new file mode 100644 index 0000000000000000000000000000000000000000..f7fc51a35b71419ccf7a62c295e3fee20e9585f5 Binary files /dev/null and b/game.cprof differ diff --git a/game.py b/game.py index d0cb9c03ce08475d97d9ab7abdf4822e3f2d2aab..49e87cabaf1deb06192deaca406b9ff2d2ac0ec0 100644 --- a/game.py +++ b/game.py @@ -1,12 +1,17 @@ +import cProfile import sys +import heapq import json import copy import Board import Piece import Block + board = Board.Board() -exit_tiles = {'red':[(3,-3),(3,-2),(3,-1),(3,0)]} +exit_tiles = {'red':[(3,-3),(3,-2),(3,-1),(3,0)], + 'green':[(-3,3),(-2,3),(-1,3),(0,3)], + 'blue':[(0,-3),(-1,-2),(-2,-1),(-3,0)]} def main(): with open(sys.argv[1]) as file: @@ -24,15 +29,30 @@ def main(): for b in data['blocks']: block = Block.Block(tuple(b)) board.tiles[block.pos[1]+3][block.pos[0]+3] = block - + + colour = data['colour'] + bdict = make_bdict(board) + print_board(bdict) # Run a* search and print solution if one exists path = A_Star(board) if path is None: print("No path found") else: for node in path: + """ bdict = make_bdict(node) print_board(bdict) + """ + if not node.toMove: + continue + if node.toMove[0] == 'e': + print("EXIT from (" + str(node.toMove[1]) + ", " + str(node.toMove[2]) + ").") + + elif node.toMove[0] == 'm': + print("MOVE from " + str(node.toMove[1]) + " to " + str(node.toMove[2]) + ".") + + elif node.toMove[0] == 'j': + print ("JUMP from " + str(node.toMove[1]) + " to " + str(node.toMove[2]) + ".") def A_Star(start): @@ -49,18 +69,21 @@ def A_Star(start): while openSet: # Find node in open set with lowest f value and set it as the "current" node + """ minF = 1000000 for node in openSet: if node.f <= minF: current = node - minF = current.f + minF = current.f + """ + current = heapq.heappop(openSet) # If found node is the goal, retrace the path, and return the solution if checkGoal(current): return retrace(current) # Remove the current node from the open set and add it to the closed set - openSet.remove(current) + #openSet.remove(current) closedSet.append(current) #Find all neighbors of the current node @@ -74,6 +97,7 @@ def A_Star(start): for node in closedSet: if listCompare(neighbor.tiles, node.tiles): inClosed = True + break if inClosed: continue @@ -84,20 +108,21 @@ def A_Star(start): for node in openSet: if listCompare(neighbor.tiles, node.tiles): inOpen = True + if tentative_gScore < node.g: + node.parent = current + node.g = tentative_gScore + node.f = node.g + heuristic(node) + heapq.heapify(openSet) + break # If not, add it if not inOpen: - openSet.append(neighbor) + neighbor.parent = current + neighbor.g = tentative_gScore + neighbor.f = neighbor.g + heuristic(neighbor) + heapq.heappush(openSet, neighbor) + #openSet.append(neighbor) - # If it is, but the neighbor has a higher g score than the node already in the list, skip it - elif tentative_gScore >= neighbor.g: - continue - - # Set the parent and g and f scores of the node - neighbor.parent = current - neighbor.g = tentative_gScore - neighbor.f = neighbor.g + heuristic(neighbor) - # Compare two board states def listCompare(list1, list2): for i in range(0,7): @@ -112,10 +137,10 @@ def heuristic(node): h = 0 for piece in node.pieces: min_dist = 10 - for tile in exit_tiles['red']: + for tile in exit_tiles[piece.colour]: if board.distance(piece.pos, tile) <= min_dist: min_dist = board.distance(piece.pos, tile) - h += (min_dist + 1) / 2 + h += (min_dist / 2) + 1 return h # Check if the goal has been reached @@ -127,12 +152,13 @@ def checkGoal(state): # Retrace the path from the goal state to the initial state def retrace(goal): - path = [] + path = [goal] cur = goal while cur.parent is not None: - path.insert(0,cur) cur = cur.parent - path.insert(0,cur) + path.insert(0,cur) + #cur = cur.parent + # path.insert(0,cur) return path # Find the neighbor states of a given board state @@ -143,8 +169,9 @@ def getNeighbors(current): # getMoves returns only a Piece object if a piece is on an exit tile # In that case, the only neighbor is the same board with that piece removed if isinstance(moves, Piece.Piece): - neighbor = copy.deepcopy(current) - + neighbor = copy.deepcopy(current) + neighbor.toMove = ['e'] + list(moves.pos) + for piece in neighbor.pieces: if piece.pos == moves.pos: neighbor.pieces.remove(piece) @@ -159,7 +186,8 @@ def getNeighbors(current): # In that case, return a list of board states with those moves applied for move in moves: neighbor = copy.deepcopy(current) - neighbor.move(move[0], move[1]) + neighbor.move(move[1], move[2]) + neighbor.toMove = list(move) neighbors.append(neighbor) return neighbors @@ -259,4 +287,9 @@ def print_board(board_dict, message="", debug=False, **kwargs): print(board, **kwargs) if __name__ == '__main__': + pr = cProfile.Profile() + pr.enable() main() + pr.disable() + pr.print_stats(sort="cumulative") + diff --git a/game2.py b/game2.py new file mode 100644 index 0000000000000000000000000000000000000000..8de950219d961ba72a58ef83eab82dc02a073154 --- /dev/null +++ b/game2.py @@ -0,0 +1,344 @@ +import cProfile +import sys +import heapq +import json +import copy +import Board +import Piece +import Block + + +board = Board.Board() +exit_tiles = {'red':[(3,-3),(3,-2),(3,-1),(3,0)], + 'green':[(-3,3),(-2,3),(-1,3),(0,3)], + 'blue':[(0,-3),(-1,-2),(-2,-1),(-3,0)]} + +def main(): + with open(sys.argv[1]) as file: + + # Load initial board state + data = json.load(file) + bdict = {} + + # Add pieces and blocks to the board + for p in data['pieces']: + piece = Piece.Piece(tuple(p), data['colour']) + board.tiles[piece.pos[1]+3][piece.pos[0]+3] = piece + board.pieces.append(piece) + + for b in data['blocks']: + block = Block.Block(tuple(b)) + board.tiles[block.pos[1]+3][block.pos[0]+3] = block + + colour = data['colour'] + bdict = make_bdict(board) + print_board(bdict) + # Run a* search and print solution if one exists + path = A_Star(board) + if path is None: + print("No path found") + else: + for node in path: + """ + bdict = make_bdict(node) + print_board(bdict) + """ + if not node.toMove: + continue + if node.toMove[0] == 'e': + print("EXIT from (" + str(node.toMove[1]) + ", " + str(node.toMove[2]) + ").") + + elif node.toMove[0] == 'm': + print("MOVE from " + str(node.toMove[1]) + " to " + str(node.toMove[2]) + ".") + + elif node.toMove[0] == 'j': + print ("JUMP from " + str(node.toMove[1]) + " to " + str(node.toMove[2]) + ".") + + +def A_Star(start): + + # Initialise open and closed sets + closedSet = {} + openSet = [start] + openSet2 = {} + idx = str(len(start.pieces)) + ":" + for p in start.pieces: + idx += str(p.pos[0]) + ":" + idx += str(p.pos[1]) + openSet2[idx] = start + + # Initial path length and heuristic + start.g = 0 + + start.f = heuristic(start) + + while openSet: + + # Find node in open set with lowest f value and set it as the "current" node + """ + minF = 1000000 + for node in openSet: + if node.f <= minF: + current = node + minF = current.f + """ + current = heapq.heappop(openSet) + + # If found node is the goal, retrace the path, and return the solution + if checkGoal(current): + return retrace(current) + + # Remove the current node from the open set and add it to the closed set + #openSet.remove(current) + idx = str(len(current.pieces)) + ":" + for p in current.pieces: + idx += str(p.pos[0]) + ":" + idx += str(p.pos[1]) + del openSet2[idx] + closedSet[idx] = current + + #Find all neighbors of the current node + neighbors = getNeighbors(current, closedSet) + + # Iterate through the neighbors of the current node + for neighbor in neighbors: + + # If the neighbor is already in the closed set, skip it + """ + inClosed = False + for node in closedSet: + if listCompare(neighbor.tiles, node.tiles): + inClosed = True + break + if inClosed: + continue + + idx = str(len(neighbor.pieces)) + ":" + for p in neighbor.pieces: + idx += str(p.pos[0]) + ":" + idx += str(p.pos[1]) + if idx in closedSet: + continue + """ + + tentative_gScore = current.g + 1 + + # Check if the neighbor is in the open set + """ + inOpen = False + for node in openSet: + if listCompare(neighbor.tiles, node.tiles): + inOpen = True + if tentative_gScore < node.g: + node.parent = current + node.g = tentative_gScore + node.f = node.g + heuristic(node) + heapq.heapify(openSet) + break + + # If not, add it + if not inOpen: + neighbor.parent = current + neighbor.g = tentative_gScore + neighbor.f = neighbor.g + heuristic(neighbor) + heapq.heappush(openSet, neighbor) + #openSet.append(neighbor) + """ + idx = str(len(neighbor.pieces)) + ":" + for p in neighbor.pieces: + idx += str(p.pos[0]) + ":" + idx += str(p.pos[1]) + if idx in openSet2: + node = openSet2[idx] + if tentative_gScore < node.g: + node.parent = current + node.g = tentative_gScore + node.f = node.g + heuristic(node) + heapq.heapify(openSet) + + else: + neighbor.parent = current + neighbor.g = tentative_gScore + neighbor.f = neighbor.g + heuristic(neighbor) + heapq.heappush(openSet, neighbor) + openSet2[idx] = neighbor + + +# Compare two board states +def listCompare(list1, list2): + for i in range(0,7): + for j in range(0,7): + if type(list1[i][j]) is not type(list2[i][j]): + return False + + return True + +# Calculates the heuristic for a given board state +def heuristic(node): + h = 0 + for piece in node.pieces: + min_dist = 10 + for tile in exit_tiles[piece.colour]: + if board.distance(piece.pos, tile) <= min_dist: + min_dist = board.distance(piece.pos, tile) + h += (min_dist / 2) + 1 + return h + +# Check if the goal has been reached +def checkGoal(state): + if not state.pieces: + return True + else: + return False + +# Retrace the path from the goal state to the initial state +def retrace(goal): + path = [goal] + cur = goal + while cur.parent is not None: + cur = cur.parent + path.insert(0,cur) + #cur = cur.parent + # path.insert(0,cur) + return path + +# Find the neighbor states of a given board state +def getNeighbors(current, closedSet): + neighbors = [] + moves = current.getMoves() + + # getMoves returns only a Piece object if a piece is on an exit tile + # In that case, the only neighbor is the same board with that piece removed + if isinstance(moves, Piece.Piece): + neighbor = copy.deepcopy(current) + neighbor.toMove = ['e'] + list(moves.pos) + + for piece in neighbor.pieces: + if piece.pos == moves.pos: + neighbor.pieces.remove(piece) + break + + neighbor.tiles[moves.pos[1]+3][moves.pos[0]+3] = None + + neighbors.append(neighbor) + return neighbors + + # Otherwise, it returns a list of possible moves + # In that case, return a list of board states with those moves applied + for move in moves: + current.move(move[1], move[2]) + idx = str(len(current.pieces)) + ":" + for p in current.pieces: + idx += str(p.pos[0]) + ":" + idx += str(p.pos[1]) + + if idx not in closedSet: + neighbor = copy.deepcopy(current) + neighbor.toMove = list(move) + neighbors.append(neighbor) + + current.move(move[2], move[1]) + + return neighbors + +# Functions for printing board state +def make_bdict(state): + + bdict = {} + + for row in state.tiles: + for col in row: + if isinstance(col, Piece.Piece): + bdict[col.pos] = 'p' + elif isinstance(col, Block.Block): + bdict[col.pos] = 'b' + + return bdict + +def print_board(board_dict, message="", debug=False, **kwargs): + """ + Helper function to print a drawing of a hexagonal board's contents. + + Arguments: + + * `board_dict` -- dictionary with tuples for keys and anything printable + for values. The tuple keys are interpreted as hexagonal coordinates (using + the axial coordinate system outlined in the project specification) and the + values are formatted as strings and placed in the drawing at the corres- + ponding location (only the first 5 characters of each string are used, to + keep the drawings small). Coordinates with missing values are left blank. + + Keyword arguments: + + * `message` -- an optional message to include on the first line of the + drawing (above the board) -- default `""` (resulting in a blank message). + * `debug` -- for a larger board drawing that includes the coordinates + inside each hex, set this to `True` -- default `False`. + * Or, any other keyword arguments! They will be forwarded to `print()`. + """ + + # Set up the board template: + if not debug: + # Use the normal board template (smaller, not showing coordinates) + template = """# {0} +# .-'-._.-'-._.-'-._.-'-. +# |{16:}|{23:}|{29:}|{34:}| +# .-'-._.-'-._.-'-._.-'-._.-'-. +# |{10:}|{17:}|{24:}|{30:}|{35:}| +# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-. +# |{05:}|{11:}|{18:}|{25:}|{31:}|{36:}| +# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-. +# |{01:}|{06:}|{12:}|{19:}|{26:}|{32:}|{37:}| +# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-' +# |{02:}|{07:}|{13:}|{20:}|{27:}|{33:}| +# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-' +# |{03:}|{08:}|{14:}|{21:}|{28:}| +# '-._.-'-._.-'-._.-'-._.-'-._.-' +# |{04:}|{09:}|{15:}|{22:}| +# '-._.-'-._.-'-._.-'-._.-'""" + else: + # Use the debug board template (larger, showing coordinates) + template = """# {0} +# ,-' `-._,-' `-._,-' `-._,-' `-. +# | {16:} | {23:} | {29:} | {34:} | +# | 0,-3 | 1,-3 | 2,-3 | 3,-3 | +# ,-' `-._,-' `-._,-' `-._,-' `-._,-' `-. +# | {10:} | {17:} | {24:} | {30:} | {35:} | +# | -1,-2 | 0,-2 | 1,-2 | 2,-2 | 3,-2 | +# ,-' `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' `-. +# | {05:} | {11:} | {18:} | {25:} | {31:} | {36:} | +# | -2,-1 | -1,-1 | 0,-1 | 1,-1 | 2,-1 | 3,-1 | +# ,-' `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' `-. +# | {01:} | {06:} | {12:} | {19:} | {26:} | {32:} | {37:} | +# | -3, 0 | -2, 0 | -1, 0 | 0, 0 | 1, 0 | 2, 0 | 3, 0 | +# `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' +# | {02:} | {07:} | {13:} | {20:} | {27:} | {33:} | +# | -3, 1 | -2, 1 | -1, 1 | 0, 1 | 1, 1 | 2, 1 | +# `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' +# | {03:} | {08:} | {14:} | {21:} | {28:} | +# | -3, 2 | -2, 2 | -1, 2 | 0, 2 | 1, 2 | key: +# `-._,-' `-._,-' `-._,-' `-._,-' `-._,-' ,-' `-. +# | {04:} | {09:} | {15:} | {22:} | | input | +# | -3, 3 | -2, 3 | -1, 3 | 0, 3 | | q, r | +# `-._,-' `-._,-' `-._,-' `-._,-' `-._,-'""" + + # prepare the provided board contents as strings, formatted to size. + ran = range(-3, +3+1) + cells = [] + for qr in [(q,r) for q in ran for r in ran if -q-r in ran]: + if qr in board_dict: + cell = str(board_dict[qr]).center(5) + else: + cell = " " # 5 spaces will fill a cell + cells.append(cell) + + # fill in the template to create the board drawing, then print! + board = template.format(message, *cells) + print(board, **kwargs) + +if __name__ == '__main__': + pr = cProfile.Profile() + pr.enable() + main() + pr.disable() + pr.print_stats(sort="time") diff --git a/input6.json b/input6.json new file mode 100644 index 0000000000000000000000000000000000000000..a4cc4c49ef0117cfcb4664f904c53e3d308afdb7 --- /dev/null +++ b/input6.json @@ -0,0 +1,5 @@ +{ + "colour": "red", + "pieces": [[0,3],[1,-3],[2,-3]], + "blocks": [[3,-3],[3,-2],[3,-1],[2,-1],[2,0],[1,0],[1,1],[0,1],[0,2],[-1,2]] +} diff --git a/input7.json b/input7.json new file mode 100644 index 0000000000000000000000000000000000000000..1494ac6793f27909ab4fe657d19264845f4f66d1 --- /dev/null +++ b/input7.json @@ -0,0 +1,5 @@ +{ + "colour": "green", + "pieces": [[0,0],[0,-1],[-2,1]], + "blocks": [[-1,0],[-1,1],[1,1],[3,-1]] +} diff --git a/input8.json b/input8.json new file mode 100644 index 0000000000000000000000000000000000000000..c18e92476c28363781540a260be076a2e83726f5 --- /dev/null +++ b/input8.json @@ -0,0 +1,5 @@ +{ + "colour":"red", + "pieces":[[2,1],[1,2],[0,3],[-1,3]], + "blocks":[[0,2],[-1,2],[-2,2],[1,1],[0,1],[-1,1],[-2,1],[2,0],[1,0],[0,0],[-1,0],[-2,0],[3,0],[2,-1],[1,-1],[0,-1],[-1,-1],[2,-2],[1,-2],[0,-2]] +} diff --git a/out4 b/out4 new file mode 100644 index 0000000000000000000000000000000000000000..f95cf7f6c6f4ef66e1f77fba55033f851d97ce51 --- /dev/null +++ b/out4 @@ -0,0 +1,102 @@ +# +# .-'-._.-'-._.-'-._.-'-. +# | | | | | +# .-'-._.-'-._.-'-._.-'-._.-'-. +# | | | | | | +# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-. +# | | | p | | | b | +# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-. +# | p | | b | p | | | | +# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-' +# | | p | b | | b | | +# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-' +# | | | | | | +# '-._.-'-._.-'-._.-'-._.-'-._.-' +# | | | | | +# '-._.-'-._.-'-._.-'-._.-' +MOVE from (-3, 0) to (-2, 0). +MOVE from (-2, 0) to (-1, -1). +JUMP from (-1, -1) to (1, -1). +JUMP from (-2, 1) to (0, 1). +JUMP from (0, -1) to (2, -1). +JUMP from (0, 1) to (2, 1). +JUMP from (0, 0) to (2, -2). +JUMP from (1, -1) to (3, -3). +EXIT from (3, -3). +MOVE from (2, 1) to (3, 0). +EXIT from (3, 0). +MOVE from (2, -1) to (3, -2). +EXIT from (3, -2). +MOVE from (2, -2) to (3, -3). +EXIT from (3, -3). + 568057445 function calls (483975328 primitive calls) in 241.139 seconds + + Ordered by: internal time + + ncalls tottime percall cumtime percall filename:lineno(function) +71237512/79022 82.996 0.000 213.082 0.003 copy.py:132(deepcopy) +145111869 20.880 0.000 20.880 0.000 {method 'get' of 'dict' objects} +5273690/1582107 16.499 0.000 190.758 0.000 copy.py:210(_deepcopy_list) +4695044/79022 15.684 0.000 212.355 0.003 copy.py:268(_reconstruct) + 5026161 12.114 0.000 30.281 0.000 copy.py:219(_deepcopy_tuple) + 1509 11.717 0.008 22.342 0.015 {built-in method _heapq.heapify} + 43876398 10.721 0.000 10.721 0.000 Board.py:37(__lt__) +4695044/79022 10.654 0.000 211.468 0.003 copy.py:236(_deepcopy_dict) +105670251 10.594 0.000 10.594 0.000 {built-in method builtins.id} + 14663778 7.589 0.000 10.837 0.000 copy.py:252(_keep_alive) + 47712449 5.137 0.000 5.137 0.000 {method 'append' of 'list' objects} + 49489374 4.713 0.000 4.713 0.000 copy.py:190(_deepcopy_atomic) + 4695044 4.655 0.000 4.655 0.000 {method '__reduce_ex__' of 'object' objects} + 9390088 4.175 0.000 4.175 0.000 {built-in method builtins.getattr} + 5026161 3.711 0.000 17.685 0.000 copy.py:220(<listcomp>) + 4695047 3.074 0.000 3.074 0.000 {built-in method builtins.hasattr} + 9390088 2.572 0.000 9.921 0.000 copy.py:273(<genexpr>) + 4695044 2.319 0.000 3.128 0.000 copyreg.py:87(__newobj__) + 9397928 1.886 0.000 1.886 0.000 {built-in method builtins.isinstance} + 7745 1.809 0.000 215.417 0.028 game2.py:206(getNeighbors) + 1 1.714 1.714 241.036 241.036 game2.py:58(A_Star) + 4695044 1.467 0.000 1.467 0.000 {method 'update' of 'dict' objects} + 4695044 0.810 0.000 0.810 0.000 {built-in method __new__ of type object at 0x9e3d20} + 4695044 0.804 0.000 0.804 0.000 {built-in method builtins.issubclass} + 4695044 0.778 0.000 0.778 0.000 {method 'items' of 'dict' objects} + 1010061 0.714 0.000 0.922 0.000 Board.py:71(distance) + 37241 0.425 0.000 1.346 0.000 game2.py:177(heuristic) + 201026 0.268 0.000 0.268 0.000 Board.py:64(move) + 3030183 0.207 0.000 0.207 0.000 {built-in method builtins.abs} + 7745 0.202 0.000 0.214 0.000 Board.py:41(getMoves) + 1 0.103 0.103 241.139 241.139 game2.py:16(main) + 7746 0.056 0.000 0.122 0.000 {built-in method _heapq.heappop} + 35731 0.047 0.000 0.076 0.000 {built-in method _heapq.heappush} + 187282 0.042 0.000 0.042 0.000 {built-in method builtins.len} + 7746 0.004 0.000 0.004 0.000 game2.py:188(checkGoal) + 2206 0.001 0.000 0.001 0.000 {method 'remove' of 'list' objects} + 1 0.000 0.000 0.000 0.000 {built-in method io.open} + 1 0.000 0.000 0.000 0.000 game2.py:258(print_board) + 16 0.000 0.000 0.000 0.000 {built-in method builtins.print} + 1 0.000 0.000 0.000 0.000 game2.py:195(retrace) + 1 0.000 0.000 0.000 0.000 game2.py:245(make_bdict) + 1 0.000 0.000 0.000 0.000 game2.py:328(<listcomp>) + 1 0.000 0.000 0.000 0.000 decoder.py:345(raw_decode) + 15 0.000 0.000 0.000 0.000 {method 'insert' of 'list' objects} + 1 0.000 0.000 0.000 0.000 {method 'read' of '_io.TextIOWrapper' objects} + 3 0.000 0.000 0.000 0.000 copyreg.py:96(_slotnames) + 1 0.000 0.000 0.000 0.000 __init__.py:274(load) + 1 0.000 0.000 0.000 0.000 {method 'format' of 'str' objects} + 2 0.000 0.000 0.000 0.000 {method 'match' of '_sre.SRE_Pattern' objects} + 1 0.000 0.000 0.000 0.000 __init__.py:302(loads) + 1 0.000 0.000 0.000 0.000 decoder.py:334(decode) + 1 0.000 0.000 0.000 0.000 codecs.py:318(decode) + 8 0.000 0.000 0.000 0.000 {method 'center' of 'str' objects} + 1 0.000 0.000 0.000 0.000 {built-in method _locale.nl_langinfo} + 3 0.000 0.000 0.000 0.000 {method 'get' of 'mappingproxy' objects} + 4 0.000 0.000 0.000 0.000 Piece.py:2(__init__) + 4 0.000 0.000 0.000 0.000 Block.py:2(__init__) + 1 0.000 0.000 0.000 0.000 codecs.py:308(__init__) + 1 0.000 0.000 0.000 0.000 _bootlocale.py:23(getpreferredencoding) + 2 0.000 0.000 0.000 0.000 {method 'end' of '_sre.SRE_Match' objects} + 1 0.000 0.000 0.000 0.000 {built-in method _codecs.utf_8_decode} + 1 0.000 0.000 0.000 0.000 {method 'startswith' of 'str' objects} + 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} + 1 0.000 0.000 0.000 0.000 codecs.py:259(__init__) + +