diff options
Diffstat (limited to 'tetris_shape.py')
-rw-r--r-- | tetris_shape.py | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/tetris_shape.py b/tetris_shape.py new file mode 100644 index 0000000..e81a0af --- /dev/null +++ b/tetris_shape.py @@ -0,0 +1,171 @@ +LEFT = "left" +RIGHT = "right" +DOWN = "down" +direction_d = { "left": (-1, 0), "right": (1, 0), "down": (0, 1) } + +class Block(object): + def __init__( self, (x, y), color): + self.color = color + self.x = x + self.y = y + + def coord( self ): + return (self.x, self.y) + +class shape(object): + """ + Shape is the Base class for the game pieces e.g. square, T, S, Z, L, + reverse L and I. Shapes are constructed of blocks. + """ + @classmethod + def check_and_create(cls, board, coords, color ): + """ + Check if the blocks that make the shape can be placed in empty coords + before creating and returning the shape instance. Otherwise, return + None. + """ + for coord in coords: + if not board.check_block( coord ): + return None + + return cls( board, coords, color) + + def __init__(self, board, coords, color ): + """ + Initialise the shape base. + """ + self.board = board + self.blocks = [] + + for coord in coords: + self.blocks.append( Block(coord,color) ) + + def move( self, direction ): + """ + Move the blocks in the direction indicated by adding (dx, dy) to the + current block coordinates + """ + d_x, d_y = direction_d[direction] + + for block in self.blocks: + x = block.x + d_x + y = block.y + d_y + if not self.board.check_block( (x, y) ): + return False + + for block in self.blocks: + block.x += d_x + block.y += d_y + + return True + + def rotate(self, clockwise = True): + """ + Rotate the blocks around the 'middle' block, 90-degrees. The + middle block is always the index 0 block in the list of blocks + that make up a shape. + """ + # TO DO: Refactor for DRY + middle = self.blocks[0] + rel = [] + for block in self.blocks: + rel.append( (block.x-middle.x, block.y-middle.y ) ) + + # to rotate 90-degrees (x,y) = (-y, x) + # First check that the there are no collisions or out of bounds moves. + for idx in xrange(len(self.blocks)): + rel_x, rel_y = rel[idx] + if clockwise: + x = middle.x+rel_y + y = middle.y-rel_x + else: + x = middle.x-rel_y + y = middle.y+rel_x + + if not self.board.check_block( (x, y) ): + return False + + for idx in xrange(len(self.blocks)): + rel_x, rel_y = rel[idx] + if clockwise: + x = middle.x+rel_y + y = middle.y-rel_x + else: + x = middle.x-rel_y + y = middle.y+rel_x + + self.blocks[idx].x = x + self.blocks[idx].y = y + + return True + +class shape_limited_rotate( shape ): + """ + This is a base class for the shapes like the S, Z and I that don't fully + rotate (which would result in the shape moving *up* one block on a 180). + Instead they toggle between 90 degrees clockwise and then back 90 degrees + anti-clockwise. + """ + def __init__( self, board, coords, color ): + self.clockwise = True + super(shape_limited_rotate, self).__init__(board, coords, color) + + def rotate(self, clockwise=True): + """ + Clockwise, is used to indicate if the shape should rotate clockwise + or back again anti-clockwise. It is toggled. + """ + super(shape_limited_rotate, self).rotate(clockwise=self.clockwise) + if self.clockwise: + self.clockwise=False + else: + self.clockwise=True + +class square_shape( shape ): + @classmethod + def check_and_create( cls, board ): + coords = [(4,0),(5,0),(4,1),(5,1)] + return super(square_shape, cls).check_and_create(board, coords, "red") + + def rotate(self, clockwise=True): + """ + Override the rotate method for the square shape to do exactly nothing! + """ + pass + +class t_shape( shape ): + @classmethod + def check_and_create( cls, board ): + coords = [(4,0),(3,0),(5,0),(4,1)] + return super(t_shape, cls).check_and_create(board, coords, "yellow" ) + +class l_shape( shape ): + @classmethod + def check_and_create( cls, board ): + coords = [(4,0),(3,0),(5,0),(3,1)] + return super(l_shape, cls).check_and_create(board, coords, "orange") + +class reverse_l_shape( shape ): + @classmethod + def check_and_create( cls, board ): + coords = [(5,0),(4,0),(6,0),(6,1)] + return super(reverse_l_shape, cls).check_and_create( + board, coords, "green") + +class z_shape( shape_limited_rotate ): + @classmethod + def check_and_create( cls, board ): + coords =[(5,0),(4,0),(5,1),(6,1)] + return super(z_shape, cls).check_and_create(board, coords, "purple") + +class s_shape( shape_limited_rotate ): + @classmethod + def check_and_create( cls, board ): + coords =[(5,1),(4,1),(5,0),(6,0)] + return super(s_shape, cls).check_and_create(board, coords, "magenta") + +class i_shape( shape_limited_rotate ): + @classmethod + def check_and_create( cls, board ): + coords =[(4,0),(3,0),(5,0),(6,0)] + return super(i_shape, cls).check_and_create(board, coords, "blue") |