diff options
author | Joe Anderson <jandew+dev@gmail.com> | 2016-02-10 10:55:09 -0800 |
---|---|---|
committer | Joe Anderson <jandew+dev@gmail.com> | 2016-02-10 10:55:09 -0800 |
commit | 9e00a1dcd2e63407c24c0b8e2003b53b7a98dd14 (patch) | |
tree | 618fcb2c32a1acac58e76a5cb5cdf6eb8cd5b0d9 /oo.py | |
download | oo-9e00a1dcd2e63407c24c0b8e2003b53b7a98dd14.tar.gz oo-9e00a1dcd2e63407c24c0b8e2003b53b7a98dd14.zip |
implemented ooPuzzle generation from seed
Diffstat (limited to 'oo.py')
-rw-r--r-- | oo.py | 191 |
1 files changed, 191 insertions, 0 deletions
@@ -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) |