From 90fbd75a8943ebbfc9bee05db2cebb1d21793be0 Mon Sep 17 00:00:00 2001 From: Joe Anderson Date: Wed, 24 Feb 2016 10:11:14 -0800 Subject: add edges into ooPuzzle, create set_data methods --- oo.py | 146 ++++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 43 deletions(-) diff --git a/oo.py b/oo.py index ebfceda..ae50189 100644 --- a/oo.py +++ b/oo.py @@ -19,8 +19,9 @@ class ooPuzzle: get_edge_pair INITIALIZATION - set_pieces_from_game_id - set_pieces_from_edges + set_data_from_game_id + set_data_from_edges + set_data_from_pieces The following are all the user interface methods. For more description, see their documentation. @@ -65,6 +66,24 @@ class ooPuzzle: if toroidal: in range(2**( 2*X*Y )) if not toroidal: in range(2**( (X-1)*Y + X*(Y-1) )) + A solution is stored in vert_edges and horiz_edges knowing this: + Adjacent edges in a solution must be + either both filled or both unfilled, + and so a bit of data is assigned to each pair. + + vert_edges is the dictionary for vertical pairs + key: (x, row) + x: the usual x-coordinate of the piece + row: the y-coordinate or y+1, depending on whether + you want the pair above or below the piece + : row == 0 and row == self.Y are border edges + so it's good to think of row as 1-indexed + + horiz_edges is the dictionary for horizontal pairs + key: (col, y) + col: the x-coord or x+1, same as row but left or right + y: the usual y-coord + pieces is a dictionary mapping: each position of form (x in range(self.X), y in range(self.Y)) @@ -96,6 +115,8 @@ class ooPuzzle: self.game_id = game_id self.toroidal = toroidal + self.horiz_edges = {} + self.vert_edges = {} self.pieces = {} self.orients = {} self.set_data_from_game_id(random_game_id = (game_id == None)) @@ -287,42 +308,86 @@ class ooPuzzle: # #### - def set_pieces_from_edges(self, horiz_edges, vert_edges): - """Convert edge dictionaries into a puzzle state. + def set_data_from_edges(self, data='pieces and game_id'): + """Update pieces and/or game_id from edges. - Adjacent edges in a solution must be - either both filled or both unfilled, - and so a bit of data is assigned to each pair. - - vert_edges is the dictionary for vertical pairs - key: (x, row) - x: the usual x-coordinate of the piece - row: the y-coordinate or y+1, depending on whether - you want the pair above or below the piece - : row == 0 and row == self.Y are border edges - so it's good to think of row as 1-indexed + data is an input in case you want to suppress calculation + It should be one of ['pieces', 'game_id', 'pieces and game_id'] + """ + if 'pieces' in data: + + for x in range(self.X): + for y in range(self.Y): + + left = self.horiz_edges[x , y] + right = self.horiz_edges[x+1, y] + up = self.vert_edges[x, y ] + down = self.vert_edges[x, y+1] + + piece, orient = \ + self.EDGES_TO_PIECE_ORIENT[left, up, right, down] + + self.pieces [x, y] = piece + self.orients[x, y] = orient + + if 'game_id' in data: + + game_id = 0 + exp = 0 + + # compute: + # n_horiz, the number of horizontal edge pairs + # n_vert, the number of vertical edge pairs + + shift = -int(not self.toroidal) + n_col = self.X + shift + n_row = self.Y + shift + n_horiz = n_col * self.Y + n_vert = self.X * n_row + + # get the edges determined by game_id + + for i in range(n_vert): + row, x = divmod(i, self.X) + bit = self.vert_edges[x, row+1] + game_id += 2**exp * bit + exp += 1 + + for i in range(n_horiz): + col, y = divmod(i, self.Y) + bit = self.horiz_edges[col+1, y] + game_id += 2**exp * bit + exp += 1 + + self.game_id = game_id + + def set_data_from_pieces(self): + """Update edges and game_id with current pieces. - horiz_edges is the dictionary for horizontal pairs - key: (col, y) - col: the x-coord or x+1, same as row but left or right - y: the usual y-coord + pieces must be in a solution state, i.e., + self.is_solved() must return True """ - for x in range(self.X): - for y in range(self.Y): + if not self.is_solved(): + raise ValueError("puzzle is not in a solved state") - left = horiz_edges[x , y] - right = horiz_edges[x+1, y] - up = vert_edges[x, y ] - down = vert_edges[x, y+1] + for x, y in self.pieces: - piece, orient = \ - self.EDGES_TO_PIECE_ORIENT[left, up, right, down] - self.pieces [x, y] = piece - self.orients[x, y] = orient + piece = self.pieces [x, y] + orient = self.orients[x, y] - def set_pieces_from_game_id(self, random_game_id=False): - """Convert game_id value into a solution puzzle state. + left, right, up, down = \ + self.PIECE_ORIENT_TO_EDGES[piece, orient] + self.horiz_edges[x , y] = left + self.horiz_edges[x+1, y] = right + self.vert_edges[x, y ] = up + self.vert_edges[x, y+1] = down + + set_data_from_edges(data='game_id') + + def set_data_from_game_id(self, random_game_id=False): + """Update edges and pieces with current game_id. + if random_game_id, then a random game_id is chosen from the appropriate range, and pieces are set from that @@ -343,19 +408,14 @@ class ooPuzzle: if random_game_id: self.game_id = random.randrange(0, 2**(n_horiz + n_vert)) - # prepare to record edges for self.set_pieces_from_edges - - vert_edges = {} - horiz_edges = {} - # set the right and bottom border edges # if toroidal, these will be overwritten in the next step for x in range(self.X): - vert_edges[x, self.Y] = 0 + self.vert_edges[x, self.Y] = 0 for y in range(self.Y): - horiz_edges[self.X, y] = 0 + self.horiz_edges[self.X, y] = 0 # set the edges determined by game_id @@ -364,24 +424,24 @@ class ooPuzzle: for i in range(n_vert): row, x = divmod(i, self.X) game_id, bit = divmod(game_id, 2) - vert_edges[x, row+1] = bit + self.vert_edges[x, row+1] = bit for i in range(n_horiz): col, y = divmod(i, self.Y) game_id, bit = divmod(game_id, 2) - horiz_edges[col+1, y] = bit + self.horiz_edges[col+1, y] = bit # make the left and top border edges match the opposite sides for y in range(self.Y): - horiz_edges[0, y] = horiz_edges[self.X, y] + self.horiz_edges[0, y] = self.horiz_edges[self.X, y] for x in range(self.X): - vert_edges[x, 0] = vert_edges[x, self.Y] + self.vert_edges[x, 0] = self.vert_edges[x, self.Y] # set the pieces from the edges - self.set_pieces_from_edges(horiz_edges, vert_edges) + self.set_data_from_edges(data='pieces') #### # -- cgit v1.2.3-54-g00ecf