summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Anderson <jandew+dev@gmail.com>2016-02-16 12:21:09 -0800
committerJoe Anderson <jandew+dev@gmail.com>2016-02-16 12:21:09 -0800
commit43d539df24ef24160706ab425deed0bd8bfe2f98 (patch)
treefaf9483caeb4ca576193c77c168fb15858e896f4
parent8f37393fa64995a3aa500079081f5ead66c2a41c (diff)
downloadoo-43d539df24ef24160706ab425deed0bd8bfe2f98.tar.gz
oo-43d539df24ef24160706ab425deed0bd8bfe2f98.zip
now can show which pieces are in error
-rw-r--r--oo.py146
1 files changed, 110 insertions, 36 deletions
diff --git a/oo.py b/oo.py
index 8ee61a5..73ef21d 100644
--- a/oo.py
+++ b/oo.py
@@ -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()