From dfb5090f2e31e4e33b9032ed9666bcb693afea27 Mon Sep 17 00:00:00 2001 From: Sean Paeglis <s.paeglis@student.unimelb.edu.au> Date: Wed, 10 Apr 2019 13:59:35 +1000 Subject: [PATCH] New --- Board.py | 14 +- __pycache__/Block.cpython-36.pyc | Bin 409 -> 392 bytes __pycache__/Board.cpython-36.pyc | Bin 2401 -> 2757 bytes __pycache__/Piece.cpython-36.pyc | Bin 413 -> 413 bytes game.cprof | Bin 0 -> 24238 bytes game.py | 77 +++++-- game2.py | 344 +++++++++++++++++++++++++++++++ input6.json | 5 + input7.json | 5 + input8.json | 5 + out4 | 102 +++++++++ 11 files changed, 526 insertions(+), 26 deletions(-) create mode 100644 game.cprof create mode 100644 game2.py create mode 100644 input6.json create mode 100644 input7.json create mode 100644 input8.json create mode 100644 out4 diff --git a/Board.py b/Board.py index 41b1924..d3432ed 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 GIT binary patch delta 165 zcmbQq+`-Ig%*)FacV$tG=S0prO)droh8o5ihIob)hF}IwMn6r)Tg(Od#hOgFSc+3~ z(u$ZE7#LPE6tPU)Z^sH^GfZY-w2Wb6U|=X>K_ys0Tt)^41`sX=spViS0<rxxAv87( Vw>WHa^HWN5Qtd!0iy0Ug7ywP08<GG3 delta 153 zcmeBRp2^H<%*)GlBYsLu^hC}&3jqcOh8o5ihIoc_h8l)=#uSEN22DmkO{QDS1^LCd z*vm4DGfPraG?{L(6sP8-6)`a|Fsx)KVx73bj-7>pfq{XMZQ^H3QFaCfh9Xu}f^D)R dqoNwRAOi!#Ee@O9{FKt1R69ln28LpgDFDbzAJPB- diff --git a/__pycache__/Board.cpython-36.pyc b/__pycache__/Board.cpython-36.pyc index f9e8f3375bc235d21baf8a21e37f29b5d1235765..59ff8c998f3173122c9a776294ea3b006d6e8b36 100644 GIT binary patch delta 1502 zcmaDTbX1hfn3tF9kj|PIN$!bUA@vyy3=F9ZQH&`JQA{a9DIzIiDdOoYDUvDDDY7YY z=`1M<Dat8oDH`c4DXeptqnJ~)Qgl-EQuI>{QjF5sqF7ScQrKG<qF7TnQaD=}qS#Wn zQn*_fqS#Y-Qg~Y!qBv6cQutdKqBv6of*CZ8Z?QV%Cl;l=WM*Jsc*(@Tz%X$ym$oMJ zE#{)slv}LnMX9NIw^)*LN>h^=86W^egH$^+FfbI~n|SXcPdY;lLp*B=h-90*m9dJA zlYxPuh;y<jlQpBz<U%Gd87>9}hFgqTMGy&)EDwm_Wnf?sntYu}pOJ4eJF^lqdlCO+ z9cC%3l6>F%vea8_1&Kwec_o^Rw^)i(bJEas-{Odm&&<m#iI3+8xkLrzI_Ak0%nFmI zF$>p&yaEyd(I5<VEy&UuhAf5}#w><xhF}IwMn6r)B5?)=22G|SDUcgk^Gh;Pi_mRi zi;vGKiH}zW*#k0+fw77Q9Bg_J33%ABF)%Q2GB7YW>w%Q+Vq{=QXQ*YIz*w;kWUULs z1jg7!wM;ckS&TIdSs<EOk|CR|NNe&VX64|F8ip(uu$q`!)*9v-))Yob262WImTZ>d z03<$hHbZeh4NDDc3Nw;Cg3p}IP&A`3poSrfb#erYEZdhF#w@m!$=a;alc%r<*E2UW zGBOmx4NPGZfmp&=gf7OM%~}Mv2t^&#GN>3t9YYq}(GYP-2ACsZ{1k?44vwM#uzT1i z>#$1KgDtONPGOQ@fcO`pG>s_@>dbJ4LcVZ@8pdD-O%A^zR#2(|CB7n1Dl8HLMHypm z5erCI02GbvMWP@v=7Rj<TU@CXnI-WhnK`M&x7d>NbMi}zZn5U(m!%dLiGUQbB^GcL zq~@h)vK2{9-p8t82Z}jJ)PoYrEspfm5>PrU)&xbS94Iw0vM>rT3o)`V@-gx;3NSh_ zGBGJJS}_GMYB73DR$<#`0W!Eq9^?`haDs|rD~V4l%Fm5rDTy!1F9Ib}hz(%7K-Lt2 zQkBDGDfUH-Qj_<xD@cN6zywJ87Dq~EaY<rca;p2}Z|ny3+Ms;;@Bjb*noLFDfY1R6 z{6`Yd1=$Xj1cwqxizZVMh(c)5WGVvbga|;jfGDtlCKDul!4`n@!34DHK_LxR2hy#{ zR0L;3j016DMuXU3TVa-iT>}z@=|dKPv%yAcGC|@Rsu~>cAQh9RbMOj51wj;8l_uBZ zZ5*og3Lv*Bfe2|3AqyhZKm;g+i?l#2aIhi>PyiQ!GBgMmgHjU*6Bi>FqX4@A6NeZF u3x_xdJ6K+mDT*Z|Gba_yL5e`IQ6N)pao7mu=BJeAq}qX;Sqw6egAoAZl^Qqz delta 1176 zcmX>q`cR0=n3tDpSM7qBJdTN6A$}eV3=F9ZQH&`JQA{cPDS|1&DI)1CQOqe~DH17C zDbgu2DRSv-Q7kE}DQqnaQLHKKDI6^fQEVxkDO@cKQS2$)DLgF<Q5-3}!3>)66VFJC zCo?iY0ElL0U|?`&U|=Y|F<FT5B3lYW4MRNZ<oAqKY-|h+3`J~{^O>v}xhJn?@{(a^ zU|_h#m{kOk0LgNK2rdQ&2JXp%%=(PnlO36r0@#XpKnht)GILUkZ?P3*rY5Hr-(pO^ z#h7-Btst=|HLpaI@fJ&QYEBxOQMWka<1_OzOXA}}W)>@fT*)Xh`5?3K<O|F!L41sC zU|7ZHl%H6Xq6bq9_YcTn95DZEU}RuOXQ*YIz*w=Qh9Qf=g<%3??2KBb8m2798ip*U zY_=km$+K9LgHvi4vY5fL5w)x}%r&ejjFJrE3@I$xEX7_(eCBM1Vy_yO8rBqMBzXj% zIh&zqQlVE3Ll(<q0ajU-H#Lk|lZ{#R>Y17u85s)UMy0TdK#XTBLKkDsW-WqSfuas- z4O9%Gjv<Q$<~)eFBm>NOFn$U{Hb;GtR}EtpYYj^ZlLSKzGl)!Mg7UzAfhdN^Kzt7o zNn=WbIz61BkT0B}hB25ylg+P)6%^~BbW;RMKt=o@E(-$#gC<*%5GdxE3-XI^aivyd zmc)b7fMoG4*4+HE)Z!vRkStqbK|yL>iY8l;*yJuY4LeYzLDB&yNSY%(wZs>sS{9Tj z<-kdRg;9W!hmnPmkCBg2fYE`GiAjmkf+>Jei_vZJ2ey3{Aajc(KrUb@5@TRsh+->= zPb<pLjbbT@FUc>G0XY!Wnj(<thLfMMFJcs%+{vLJi7I`IBPFxABrz{J)qL_H4ud3R z1_p+g|Nj5~ugO#d_P7d2;6IXpD#&)IBsf%{0w4+!Odysf6M|g?6#$2(>g0!<GD1)h z5CsloP0q>uT&newAoojw2yqYr3KOvVi$EC!5_G7}FJfX~U;yD_P)_7v<Y5zF<Phc% l;a~&HXfj2ygk<KVf;rgq-{P>z%}*)KNwoucW%52Qb^z{9<&*#b diff --git a/__pycache__/Piece.cpython-36.pyc b/__pycache__/Piece.cpython-36.pyc index 8b7c34fc71bb2295e61485daec010de8badf2e74..328793a07f0c93a3324c29969ba816760fac2bcc 100644 GIT binary patch delta 16 XcmbQsJeQf>n3tC;?aHE!?9&(lC5Qyd delta 16 XcmbQsJeQf>n3tC;W69i&?9&(lBwYlT diff --git a/game.cprof b/game.cprof new file mode 100644 index 0000000000000000000000000000000000000000..f7fc51a35b71419ccf7a62c295e3fee20e9585f5 GIT binary patch literal 24238 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�+-`%>I{t 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 literal 0 HcmV?d00001 diff --git a/game.py b/game.py index d0cb9c0..49e87ca 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 0000000..8de9502 --- /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 0000000..a4cc4c4 --- /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 0000000..1494ac6 --- /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 0000000..c18e924 --- /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 0000000..f95cf7f --- /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__) + + -- GitLab