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)