summaryrefslogtreecommitdiff
path: root/oo.py
diff options
context:
space:
mode:
authorJoe Anderson <jandew+dev@gmail.com>2016-02-10 10:55:09 -0800
committerJoe Anderson <jandew+dev@gmail.com>2016-02-10 10:55:09 -0800
commit9e00a1dcd2e63407c24c0b8e2003b53b7a98dd14 (patch)
tree618fcb2c32a1acac58e76a5cb5cdf6eb8cd5b0d9 /oo.py
downloadoo-9e00a1dcd2e63407c24c0b8e2003b53b7a98dd14.tar.gz
oo-9e00a1dcd2e63407c24c0b8e2003b53b7a98dd14.zip
implemented ooPuzzle generation from seed
Diffstat (limited to 'oo.py')
-rw-r--r--oo.py191
1 files changed, 191 insertions, 0 deletions
diff --git a/oo.py b/oo.py
new file mode 100644
index 0000000..a947665
--- /dev/null
+++ b/oo.py
@@ -0,0 +1,191 @@
+import curses
+import random
+
+class ooPuzzle:
+ """Encapsulates a oo puzzle state.
+
+ No rendering information is stored or interpreted here.
+
+ Attributes.
+ X,Y : horizontal and vertical size of the puzzle
+ pieces : dictionary mapping (x,y) to range(6)
+ orients : dictionary mapping (x,y) to range(4)
+ """
+ def __init__(self, X, Y, seed=None, inverted=False, toroidal=False):
+ """Create a new ooPuzzle instance.
+
+ Arguments.
+ X,Y : horizontal and vertical size of the puzzle
+ seed : passed to ooPuzzle.set_pieces_from_seed
+ inverted : bool for swapping to "dark mode"
+ toroidal : bool for looping around the end of the puzzle
+
+ NotImplemented: inverted, toroidal
+ """
+ self.X, self.Y = X, Y
+ self.inverted = inverted
+ self.toroidal = toroidal
+ self.pieces = {}
+ self.orients = {}
+ self.set_pieces_from_seed(seed)
+
+ EDGES_TO_PIECE_ORIENT = { (0, 0, 0, 0) : (0, 0),
+
+ (1, 0, 0, 0) : (1, 0),
+ (0, 1, 0, 0) : (1, 1),
+ (0, 0, 1, 0) : (1, 2),
+ (0, 0, 0, 1) : (1, 3),
+
+ (1, 1, 0, 0) : (2, 0),
+ (0, 1, 1, 0) : (2, 1),
+ (0, 0, 1, 1) : (2, 2),
+ (1, 0, 0, 1) : (2, 3),
+
+ (1, 0, 1, 0) : (3, 0),
+ (0, 1, 0, 1) : (3, 1),
+
+ (0, 1, 1, 1) : (4, 0),
+ (1, 0, 1, 1) : (4, 1),
+ (1, 1, 0, 1) : (4, 2),
+ (1, 1, 1, 0) : (4, 3),
+
+ (1, 1, 1, 1) : (5, 0) }
+
+ PIECE_ORIENT_TO_EDGES = { (0, 0) : (0, 0, 0, 0),
+ (0, 1) : (0, 0, 0, 0),
+ (0, 2) : (0, 0, 0, 0),
+ (0, 3) : (0, 0, 0, 0),
+
+ (1, 0) : (1, 0, 0, 0),
+ (1, 1) : (0, 1, 0, 0),
+ (1, 2) : (0, 0, 1, 0),
+ (1, 3) : (0, 0, 0, 1),
+
+ (2, 0) : (1, 1, 0, 0),
+ (2, 1) : (0, 1, 1, 0),
+ (2, 2) : (0, 0, 1, 1),
+ (2, 3) : (1, 0, 0, 1),
+
+ (3, 0) : (1, 0, 1, 0),
+ (3, 1) : (0, 1, 0, 1),
+ (3, 2) : (1, 0, 1, 0),
+ (3, 3) : (0, 1, 0, 1),
+
+ (4, 0) : (1, 1, 1, 1),
+ (4, 1) : (1, 1, 1, 1),
+ (4, 2) : (1, 1, 1, 1),
+ (4, 3) : (1, 1, 1, 1) }
+
+ def set_pieces_from_edges(self, horiz_edges, vert_edges):
+ """Convert edge dictionaries into a puzzle state.
+ """
+ for x in range(self.X):
+ for y in range(self.Y):
+
+ left = horiz_edges[x , y]
+ right = horiz_edges[x+1, y]
+ up = vert_edges[x, y ]
+ down = 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
+
+ def set_pieces_from_seed(self, seed=None):
+ """Convert seed value into a solution puzzle state.
+
+ seed is an integer
+ if toroidal: in range(2**( 2*X*Y ))
+ if not toroidal: in range(2**( (X-1)*Y + X*(Y-1) ))
+ if None, then a random seed is generated
+ """
+
+ # 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
+
+ # generate and record seed
+
+ if seed == None:
+ maxint = 2**(n_horiz + n_vert - 1)
+ seed = random.randint(0, maxint)
+ self.seed = seed
+
+ # prepare to record edges
+
+ vert_edges = {}
+ horiz_edges = {}
+
+ # set the border edges
+ # if toroidal, these will be overwritten
+
+ for x in range(self.X):
+ vert_edges[x, 0] = 0
+ vert_edges[x, self.Y] = 0
+
+ for y in range(self.Y):
+ horiz_edges[ 0, y] = 0
+ horiz_edges[self.X, y] = 0
+
+ # set the edges determined by seed
+
+ for i in range(n_vert):
+ row, x = divmod(i, self.X)
+ seed, bit = divmod(seed, 2)
+ vert_edges[x, row+1] = bit
+
+ for i in range(n_horiz):
+ col, y = divmod(i, self.Y)
+ seed, bit = divmod(seed, 2)
+ horiz_edges[col+1, y] = bit
+
+ # turn edges into pieces
+
+ self.set_pieces_from_edges(horiz_edges, vert_edges)
+
+ def random_state(self):
+ """Randomly rotate the current pieces."""
+ for x in range(self.X):
+ for y in range(self.Y):
+ self.pieces[x, y] = random.randint(4)
+
+ def is_solved(self):
+ """Checks whether the puzzle is in a solved state."""
+ pass
+
+class ooPlay:
+ """Encapsulates a oo game instance.
+
+ Methods.
+ display() : Display the state of the board, refresh screen.
+ keyloop() : Set up screen and wait for keypress.
+ """
+ def __init__(self, scr, inverted=False):
+ """Create a new ooPlay instance.
+
+ Arguments.
+ scr : curses screen object used for display
+ X,Y : horizontal and vertical size of the board
+ inverted : bool for swapping to "dark mode"
+ """
+ self.scr = scr
+ Y, X = self.scr.getmaxyx()
+ self.X, self.Y = X, Y - 2
+ self.piece = {}
+ self.state = {}
+ self.scr.clear()
+
+ # draw the help area
+ border_line = X * "═"
+ self.scr.addstr(self.Y + 1, 0, border_line)
+ self.scr.refresh()
+
+def main():
+ curses.wrapper(ooPlay)