diff options
Diffstat (limited to 'oo.py')
-rw-r--r-- | oo.py | 146 |
1 files changed, 110 insertions, 36 deletions
@@ -185,39 +185,98 @@ class ooPuzzle: for y in range(self.Y): self.orients[x, y] = random.randrange(4) - def check_right(self, x0, y): - """Check the horizontal edge pair right of (x0, y).""" - x1 = (x0 + 1) % self.X - l_piece = self.pieces [x0, y] - l_orient = self.orients[x0, y] - r_piece = self.pieces [x1, y] - r_orient = self.orients[x1, y] - l_edge = self.PIECE_ORIENT_TO_EDGES[l_piece, l_orient][2] - r_edge = self.PIECE_ORIENT_TO_EDGES[r_piece, r_orient][0] - if not self.toroidal and x1 == 0: - return not l_edge and not r_edge - return l_edge == r_edge - - def check_down(self, x, y0): - """Check the vertical edge pair below (x, y0).""" - y1 = (y0 + 1) % self.Y - u_piece = self.pieces [x, y0] - u_orient = self.orients[x, y0] - d_piece = self.pieces [x, y1] - d_orient = self.orients[x, y1] - u_edge = self.PIECE_ORIENT_TO_EDGES[u_piece, u_orient][3] - d_edge = self.PIECE_ORIENT_TO_EDGES[d_piece, d_orient][1] - if not self.toroidal and y1 == 0: - return not u_edge and not d_edge - return u_edge == d_edge + DIRECTIONS = {'LEFT' : 0, + 'UP' : 1, + 'RIGHT': 2, + 'DOWN' : 3} + + DX_DY = [(-1, 0), + ( 0, -1), + ( 1, 0), + ( 0, 1)] + + def position_in_direction(self, x0, y0, direction, return_is_internal=False): + """Returns the position adjacent to (x0, y0) in direction. + + direction may be any string or integer in the dictionary + self.DIRECTIONS (case insensitive) + + If return_is_internal, then a third output is returned, + a bool for whether both edges are internal. + (If false, then the edges are across a border.) + """ + if type(direction) is str: + direction = self.DIRECTIONS[direction.upper()] + dx, dy = self.DX_DY[direction] + x1 = (x0 + dx) % self.X + y1 = (y0 + dy) % self.Y + + if return_is_internal: + is_internal = ( + x0 + dx == x1 and + y0 + dy == y1 ) + return x1, y1, is_internal + + return x1, y1 + + def get_edge_pair(self, x0, y0, direction): + """Returns the edge pair's filled status in direction and is_internal. + + direction may be any string or integer in the dictionary + self.DIRECTIONS (case insensitive) + + The first output is the status of the edge of (x0, y0) in direction. + + The second output is the status of the adjacent edge, + that is, of the piece in direction of (x0, y0), + the status of the edge in the opposite direction. + + The third output is a bool for whether both edges are internal. + (If false, then the edges are across a border.) + """ + if type(direction) is str: + direction = self.DIRECTIONS[direction.upper()] + + piece = self.pieces [x0, y0] + orient = self.orients[x0, y0] + edge0 = self.PIECE_ORIENT_TO_EDGES[piece, orient][direction] + + x1, y1, is_internal = self.position_in_direction(x0, y0, direction, True) + piece = self.pieces [x1, y1] + orient = self.orients[x1, y1] + direction = (direction + 2) % 4 + edge1 = self.PIECE_ORIENT_TO_EDGES[piece, orient][direction] + + return edge0, edge1, is_internal + + def check_edge_pair(self, x, y, direction, if_filled=False): + """Check the edge pair's validity around (x, y) in direction. + + If if_filled, then only check the edge pair if the base edge is filled. + """ + e0, e1, is_internal = self.get_edge_pair(x, y, direction) + if if_filled and not e0: return True + if not is_internal and not self.toroidal: + return not e0 and not e1 + return e0 == e1 + + def check_piece(self, x, y, if_filled=True): + """Check the validity of edge pairs around (x, y). + + if_filled is passed on to check_edge_pair + """ + for direction in self.DIRECTIONS: + if not self.check_edge_pair(x, y, direction, if_filled): + return False + return True def is_solved(self): """Check whether the puzzle is in a solved state.""" for x in range(self.X): for y in range(self.Y): - if not self.check_right(x, y): + if not self.check_edge_pair(x, y, "RIGHT"): return False - if not self.check_down(x, y): + if not self.check_edge_pair(x, y, "DOWN"): return False return True @@ -247,6 +306,7 @@ class ooPlay: # draw the help area and board state self.help_ind = 0 + self.show_errors = False self.write() self.display() @@ -262,24 +322,31 @@ class ooPlay: "┝┯┥┷", "┿┿┿┿"] - def display_pos(self, x, y): - """Update one position on the board, refresh screen.""" + def display_subroutine(self, x, y): + """Update one position on the board.""" piece = self.puzzle.pieces [x, y] orient = self.puzzle.orients[x, y] string = self.PIECE_ORIENT_TO_STRING[piece][orient] - color = curses.color_pair((x + y) % 2) + is_error = False + if self.show_errors: + is_error = not self.puzzle.check_piece(x, y) + color = curses.color_pair((x + y) % 2 + 2*is_error) self.screen.addstr(y, x, string, color) + + def display_pos(self, x, y): + """Update one position on the board, refresh screen.""" + self.display_subroutine(x, y) + if self.show_errors: + for direction in self.puzzle.DIRECTIONS: + x1, y1 = self.puzzle.position_in_direction(x, y, direction) + self.display_subroutine(x1, y1) self.screen.refresh() def display(self): """Update the state of the board, refresh screen.""" for x in range(self.puzzle.X): for y in range(self.puzzle.Y): - piece = self.puzzle.pieces [x, y] - orient = self.puzzle.orients[x, y] - string = self.PIECE_ORIENT_TO_STRING[piece][orient] - color = curses.color_pair((x + y) % 2) - self.screen.addstr(y, x, string, color) + self.display_subroutine(x, y) self.screen.refresh() pause_length = 80 @@ -315,7 +382,7 @@ class ooPlay: centered_string = string.center(width, " ") self.screen.addstr(self.Y - 1, 0, centered_string, color) self.screen.refresh() - if pause: curses.napms(2 * self.pause_length * len(string)) + if pause: curses.napms(self.pause_length * len(string)) curses.ungetch(0) # clear input return @@ -331,6 +398,7 @@ class ooPlay: curses.napms(self.pause_length) if pause: curses.napms(self.pause_length * width) curses.ungetch(0) # clear input + #TODO: ungetch appears to not clear inputs as desired :/ def write_help(self): """Write one of the help messages.""" @@ -341,6 +409,7 @@ class ooPlay: self.write("q: quit game") self.write("n: new game") self.write("r: randomize rotations") + self.write("s: toggle show errors") self.write("t: toggle toroidal mode") self.write("i: toggle inverted mode") self.write("The next help is game explanation.") @@ -401,6 +470,11 @@ class ooPlay: self.write() elif inp in "H": self.write_help() + elif inp in "Ss": + self.write("Do Not "*self.show_errors + "Show Errors") + self.show_errors = not self.show_errors + self.display() + self.write() elif inp in "Ii": self.write("Inverted mode is not implemented.") self.write() |