aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar rcoh <rcoh@mit.edu>2011-08-07 20:14:17 -0700
committerGravatar rcoh <rcoh@mit.edu>2011-08-07 20:14:17 -0700
commita18c2e350f7ae7018900dce9878cc969340d2663 (patch)
tree02ae73c2d506a624c3d16af85be568c94bcdbb0a
parent0dcc566d84f109a6026c60aeaebe4187a34f892d (diff)
These are the base tetris files. They are Leah's.
-rw-r--r--originaltetris/tetris.py278
-rw-r--r--originaltetris/tetris2.py790
-rw-r--r--originaltetris/tetrisGUI.py120
-rw-r--r--originaltetris/tetris_shape.py171
4 files changed, 1359 insertions, 0 deletions
diff --git a/originaltetris/tetris.py b/originaltetris/tetris.py
new file mode 100644
index 0000000..b6b31f4
--- /dev/null
+++ b/originaltetris/tetris.py
@@ -0,0 +1,278 @@
+#!/usr/bin/env python
+"""
+Tetris Tk - A tetris clone written in Python using the Tkinter GUI library.
+
+Controls:
+ Left/a Move left
+ Right/d Move right
+ Down/s Move down
+ Up/w Rotate anti-clockwise (to the left)
+"""
+from Tkinter import *
+from time import sleep
+import random
+import sys
+from tetrisGUI import GUI
+from tetris_shape import *
+
+MAXX = 10
+MAXY = 18
+NO_OF_LEVELS = 10
+
+LEFT = "left"
+RIGHT = "right"
+DOWN = "down"
+direction_d = { "left": (-1, 0), "right": (1, 0), "down": (0, 1) }
+
+COLORS = ["orange", "red", "green", "blue", "purple", "yellow", "magenta"]
+#COLORS = ["gray"]
+
+class Board():
+ """
+ The board represents the tetris playing area. A grid of x by y blocks.
+ """
+ def __init__(self, max_x=10, max_y=20):
+ # blocks are stored in dict of (x,y)->"color"
+ self.landed = {}
+ self.max_x = max_x
+ self.max_y = max_y
+
+ def receive_lines(self, num_lines):
+ #shift lines up
+ for y in range(self.max_y-num_lines):
+ for x in xrange(self.max_x):
+ block_color = self.landed.pop((x,y+num_lines),None)
+ if block_color:
+ self.landed[(x,y)] = block_color
+ #put in new lines
+ for j in range(num_lines):
+ for i in random.sample(xrange(self.max_x), random.choice([6,7])):
+ self.landed[(i,self.max_y-1-j)] = random.choice(COLORS)
+
+ def check_for_complete_row( self, blocks ):
+ """
+ Look for a complete row of blocks, from the bottom up until the top row
+ or until an empty row is reached.
+ """
+ rows_deleted = 0
+
+ # Add the blocks to those in the grid that have already 'landed'
+ for block in blocks:
+ self.landed[ block.coord() ] = block.color
+
+ empty_row = 0
+ # find the first empty row
+ for y in xrange(self.max_y -1, -1, -1):
+ row_is_empty = True
+ for x in xrange(self.max_x):
+ if self.landed.get((x,y), None):
+ row_is_empty = False
+ break;
+ if row_is_empty:
+ empty_row = y
+ break
+
+ # Now scan up and until a complete row is found.
+ y = self.max_y - 1
+ while y > empty_row:
+
+ complete_row = True
+ for x in xrange(self.max_x):
+ if self.landed.get((x,y), None) is None:
+ complete_row = False
+ break;
+
+ if complete_row:
+ rows_deleted += 1
+
+ #delete the completed row
+ for x in xrange(self.max_x):
+ self.landed.pop((x,y))
+
+ # move all the rows above it down
+ for ay in xrange(y-1, empty_row, -1):
+ for x in xrange(self.max_x):
+ block_color = self.landed.pop((x,ay), None)
+ if block_color:
+ dx,dy = direction_d[DOWN]
+ self.landed[(x+dx, ay+dy)] = block_color
+
+ # move the empty row down index down too
+ empty_row +=1
+ # y stays same as row above has moved down.
+ else:
+ y -= 1
+
+ # return the score, calculated by the number of rows deleted.
+ return rows_deleted
+
+ def output( self ):
+ for y in xrange(self.max_y):
+ line = []
+ for x in xrange(self.max_x):
+ if self.landed.get((x,y), None): line.append("X")
+ else: line.append(".")
+ print "".join(line)
+
+ def check_block( self, (x, y) ):
+ """
+ Check if the x, y coordinate can have a block placed there.
+ That is; if there is a 'landed' block there or it is outside the
+ board boundary, then return False, otherwise return true.
+ """
+ if x < 0 or x >= self.max_x or y < 0 or y >= self.max_y:
+ return False
+ elif self.landed.has_key( (x, y) ):
+ return False
+ else:
+ return True
+
+#represents a player. each player has a board and can get new shapes...
+#
+class Player():
+ def __init__(self,parent, gs, myBoard, otherBoard):
+ print "initialize player"
+ self.parent = parent
+ self.board = myBoard
+ self.other_board = otherBoard
+ self.score = 0
+ self.shapes = [square_shape,
+ t_shape,
+ l_shape,
+ reverse_l_shape,
+ z_shape,
+ s_shape,
+ i_shape ]
+ self.gs = gs
+ self.shape = self.get_next_shape()
+
+ def handle_move(self, direction):
+ #if you can't move then you've hit something
+ success = self.shape.move( direction )
+ if not success:
+
+ # if you're heading down then the shape has 'landed'
+ if direction == DOWN:
+ points = self.board.check_for_complete_row(
+ self.shape.blocks)
+ del self.shape
+ self.shape = self.get_next_shape()
+
+ self.score += points
+ if points > 1:
+ self.other_board.receive_lines(points-1)
+
+ # If the shape returned is None, then this indicates that
+ # that the check before creating it failed and the
+ # game is over!
+ if self.shape is None:
+ self.end_game() #loss!
+
+ # do we go up a level?
+ if (self.gs.level < NO_OF_LEVELS and
+ self.score >= self.gs.thresholds[self.gs.level]):
+ self.gs.level+=1
+ self.gs.delay-=100
+
+ # Signal that the shape has 'landed'
+ return False
+ return True
+
+ def left(self):
+ if self.shape:
+ self.handle_move( LEFT )
+
+ def right(self):
+ if self.shape:
+ self.handle_move( RIGHT )
+
+ def down(self):
+ if self.shape:
+ self.handle_move( DOWN )
+
+ def up(self):
+ if self.shape:
+ self.shape.rotate(clockwise=False)
+
+ def move_my_shape( self ):
+ if self.shape:
+ self.handle_move( DOWN )
+
+ def get_next_shape( self ):
+ #Randomly select which tetrominoe will be used next.
+ the_shape = self.shapes[ random.randint(0,len(self.shapes)-1) ]
+ return the_shape.check_and_create(self.board)
+
+#contains variables that are shared between the players:
+#levels, delay time, etc?
+class GameState():
+ def __init__(self, gui):
+ self.level = 1
+ self.delay = 1000
+ self.thresholds = range(10,100,10)
+
+
+#runs the overall game. initializes both player and any displays
+class TwoPlayerGame(object):
+ """
+ Main game loop and receives GUI callback events for keypresses etc...
+ """
+ def __init__(self, parent):
+ print "initialize game"
+ self.parent = parent
+ self.gui = GUI(parent,20,MAXX,MAXY)
+ self.gui.pack(side=BOTTOM)
+ self.gameState = GameState(self.gui)
+
+ board0 = Board(MAXX,MAXY)
+ board1 = Board(MAXX,MAXY)
+ player0 = Player(parent, self.gameState, board0, board1)
+ player1 = Player(parent, self.gameState, board1, board0)
+ self.players = [player0, player1]
+
+ self.parent.bind("<Key>", self.handle_key_press)
+ self.parent.after( self.gameState.delay, self.gravity)
+
+ def gravity(self):
+ for p in self.players:
+ p.move_my_shape()
+ self.update_gui()
+ self.parent.after( self.gameState.delay, self.gravity)
+
+ def handle_key_press(self,event):
+ k = event.keysym
+ if k=="Left":
+ self.players[1].left()
+ elif k=="Right":
+ self.players[1].right()
+ elif k=="Down":
+ self.players[1].down()
+ elif k=="Up":
+ self.players[1].up()
+ elif k=="a":
+ self.players[0].left()
+ elif k=="d":
+ self.players[0].right()
+ elif k=="s":
+ self.players[0].down()
+ elif k=="w":
+ self.players[0].up()
+ self.update_gui()
+
+ def update_gui(self):
+ self.gui.draw_board(self.players)
+
+ def end_game(self):
+ #fix this
+ #show_end_seq()
+ Toplevel().destroy()
+ self.parent.destroy()
+ sys.exit(0)
+
+
+
+if __name__ == "__main__":
+ root = Tk()
+ root.title("Tetris Tk")
+ theGame = TwoPlayerGame( root )
+ root.mainloop()
diff --git a/originaltetris/tetris2.py b/originaltetris/tetris2.py
new file mode 100644
index 0000000..f2d54d3
--- /dev/null
+++ b/originaltetris/tetris2.py
@@ -0,0 +1,790 @@
+
+
+
+
+from graphics import *
+import random
+
+############################################################
+# BLOCK CLASS
+############################################################
+
+class Block(Rectangle):
+ ''' Block class:
+ Implement a block for a tetris piece
+ Attributes: x - type: int
+ y - type: int
+ specify the position on the tetris board
+ in terms of the square grid
+ '''
+ # BLOCK SIZE defined in pixels. So from now on, each coordinate is multiplied by 30
+ # (see below)
+ BLOCK_SIZE = 30
+ OUTLINE_WIDTH = 3
+
+ def __init__(self, pos, color):
+ self.x = pos.x
+ self.y = pos.y
+
+ p1 = Point(pos.x*Block.BLOCK_SIZE + Block.OUTLINE_WIDTH,
+ pos.y*Block.BLOCK_SIZE + Block.OUTLINE_WIDTH)
+ p2 = Point(p1.x + Block.BLOCK_SIZE, p1.y + Block.BLOCK_SIZE)
+
+ Rectangle.__init__(self, p1, p2)
+ self.setWidth(Block.OUTLINE_WIDTH)
+ self.setFill(color)
+ self.color = color
+
+ def can_move(self, board, dx, dy):
+ ''' Parameters: dx - type: int
+ dy - type: int
+
+ Return value: type: bool
+
+ checks if the block can move dx squares in the x direction
+ and dy squares in the y direction
+ Returns True if it can, and False otherwise
+ HINT: use the can_move method on the Board object
+ '''
+
+ if board.can_move(self.x + dx, self.y + dy) == True:
+ return True
+ return False
+
+ def move(self, dx, dy):
+ ''' Parameters: dx - type: int
+ dy - type: int
+
+ moves the block dx squares in the x direction
+ and dy squares in the y direction
+ '''
+
+ self.x += dx
+ self.y += dy
+
+ Rectangle.move(self, dx*Block.BLOCK_SIZE, dy*Block.BLOCK_SIZE)
+
+
+############################################################
+# SHAPE CLASS
+############################################################
+
+class Shape():
+ ''' Shape class:
+ Base class for all the tetris shapes
+ Attributes: blocks - type: list - the list of blocks making up the shape
+ rotation_dir - type: int - the current rotation direction of the shape
+ shift_rotation_dir - type: Boolean - whether or not the shape rotates
+ '''
+
+ def __init__(self, coords, color):
+ # Define empty list
+ self.blocks = []
+ self.rotation_dir = 1
+ ### A boolean to indicate if a shape shifts rotation direction or not.
+ ### Defaults to false since only 3 shapes shift rotation directions (I, S and Z)
+ self.shift_rotation_dir = False
+
+ # for each coordinate, make a block object out of it and append to list
+ for pos in coords:
+ self.blocks.append(Block(pos, color))
+
+
+
+ def get_blocks(self):
+ '''returns the list of blocks
+ '''
+ #return list of blocks
+ return self.blocks
+ pass
+
+ def draw(self, win):
+ ''' Parameter: win - type: CanvasFrame
+
+ Draws the shape:
+ i.e. draws each block
+ '''
+ # For each block in list, draw block
+ for block in self.blocks:
+ block.draw(win)
+
+ def move(self, dx, dy):
+ ''' Parameters: dx - type: int
+ dy - type: int
+
+ moves the shape dx squares in the x direction
+ and dy squares in the y direction, i.e.
+ moves each of the blocks
+ '''
+ for block in self.blocks:
+ block.move(dx, dy)
+
+ def can_move(self, board, dx, dy):
+ ''' Parameters: dx - type: int
+ dy - type: int
+
+ Return value: type: bool
+
+ checks if the shape can move dx squares in the x direction
+ and dy squares in the y direction, i.e.
+ check if each of the blocks can move
+ Returns True if all of them can, and False otherwise
+
+ '''
+
+ #Checks each block to see if it can move dx and dy
+ for blocks in self.blocks:
+ if blocks.can_move(board, dx, dy) == False:
+ return False
+ return True
+ # default implementation (MUST CHANGE)
+ #return True
+
+ def get_rotation_dir(self):
+ ''' Return value: type: int
+
+ returns the current rotation direction
+ '''
+ return self.rotation_dir
+
+ def can_rotate(self, board):
+ ''' Parameters: board - type: Board object
+ Return value: type : bool
+
+ Checks if the shape can be rotated.
+
+ 1. Get the rotation direction using the get_rotation_dir method
+ 2. Compute the position of each block after rotation and check if
+ the new position is valid
+ 3. If any of the blocks cannot be moved to their new position,
+ return False
+
+ otherwise all is good, return True
+ '''
+ #Get rotation direction from other method, and center
+ rotation_direction = self.get_rotation_dir()
+ center = self.center_block
+
+ #For each block in list:
+ for block in self.blocks:
+ # Use these formulas to determine new coordinates (provided for us)
+ x = center.x - rotation_direction*center.y + rotation_direction*block.y
+ y = center.y + rotation_direction*center.x - rotation_direction*block.x
+ # If these posistions are not valid on the board(other piece there
+ #or out of bounds), return False
+ if board.can_move(x, y) == False:
+ return False
+ return True
+
+
+
+
+ def rotate(self, board):
+ ''' Parameters: board - type: Board object
+
+ rotates the shape:
+ 1. Get the rotation direction using the get_rotation_dir method
+ 2. Compute the position of each block after rotation
+ 3. Move the block to the new position
+
+ '''
+
+
+ # For each block defined in shape
+ for block in self.blocks:
+ #Grab rotation direction and center block
+ rotation_direction = self.get_rotation_dir()
+ center = self.center_block
+ #Compute new coordinates and call move method
+ x = center.x - rotation_direction*center.y + rotation_direction*block.y
+ y = center.y + rotation_direction*center.x - rotation_direction*block.x
+ # Use x - block.x for dx, y-block.y for dy
+ block.move(x - block.x, y - block.y)
+
+ ### This should be at the END of your rotate code.
+ ### DO NOT touch it. Default behavior is that a piece will only shift
+ ### rotation direciton after a successful rotation. This ensures that
+ ### pieces which switch rotations definitely remain within their
+ ### accepted rotation positions.
+ if self.shift_rotation_dir:
+ self.rotation_dir *= -1
+
+
+
+############################################################
+# ALL SHAPE CLASSES
+############################################################
+
+# For each shape in the game, we gave the coordinates for each block in the
+# Tetronimo, using the center block as reference. We then initialized a shape
+# object with the list of coords and a color. Self.center_block is used
+# above for rotating; it tells us what the center block is
+
+class I_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x - 2, center.y),
+ Point(center.x - 1, center.y),
+ Point(center.x , center.y),
+ Point(center.x + 1, center.y)]
+ Shape.__init__(self, coords, 'blue')
+ self.shift_rotation_dir = True
+ self.center_block = self.blocks[2]
+
+
+class J_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x - 1, center.y),
+ Point(center.x , center.y),
+ Point(center.x + 1, center.y),
+ Point(center.x + 1, center.y + 1)]
+ Shape.__init__(self, coords, 'orange')
+ self.center_block = self.blocks[1]
+
+
+class L_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x - 1, center.y),
+ Point(center.x , center.y),
+ Point(center.x + 1, center.y),
+ Point(center.x - 1, center.y + 1)]
+ Shape.__init__(self, coords, 'cyan')
+ self.center_block = self.blocks[1]
+
+
+class O_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x , center.y),
+ Point(center.x - 1, center.y),
+ Point(center.x , center.y + 1),
+ Point(center.x - 1, center.y + 1)]
+ Shape.__init__(self, coords, 'red')
+ self.center_block = self.blocks[0]
+
+ def rotate(self, board):
+ # Override Shape's rotate method since O_Shape does not rotate
+ return
+
+
+
+class S_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x , center.y),
+ Point(center.x , center.y + 1),
+ Point(center.x + 1, center.y),
+ Point(center.x - 1, center.y + 1)]
+ Shape.__init__(self, coords, 'green')
+ self.center_block = self.blocks[0]
+ self.shift_rotation_dir = True
+ self.rotation_dir = -1
+
+
+class T_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x - 1, center.y),
+ Point(center.x , center.y),
+ Point(center.x + 1, center.y),
+ Point(center.x , center.y + 1)]
+ Shape.__init__(self, coords, 'yellow')
+ self.center_block = self.blocks[1]
+
+
+class Z_shape(Shape):
+ def __init__(self, center):
+ coords = [Point(center.x - 1, center.y),
+ Point(center.x , center.y),
+ Point(center.x , center.y + 1),
+ Point(center.x + 1, center.y + 1)]
+ Shape.__init__(self, coords, 'magenta')
+ self.shift_rotation_dir = True
+ self.rotation_dir = -1
+ self.center_block = self.blocks[1]
+
+
+
+############################################################
+# BOARD CLASS
+############################################################
+
+class Board():
+ ''' Board class: it represents the Tetris board
+
+ Attributes: width - type:int - width of the board in squares
+ height - type:int - height of the board in squares
+ canvas - type:CanvasFrame - where the pieces will be drawn
+ grid - type:Dictionary - keeps track of the current state of
+ the board; stores the blocks for a given position
+ '''
+
+ def __init__(self, win, width, height):
+ self.width = width
+ self.height = height
+
+ # create a canvas to draw the tetris shapes on
+ self.canvas = CanvasFrame(win, self.width * Block.BLOCK_SIZE,
+ self.height * Block.BLOCK_SIZE)
+ self.canvas.setBackground('black')
+ # Create Scoreboard with same width, but a height of 100 pixels
+ self.scoreboard = Scoreboard(win, width, 100)
+
+ # create an empty dictionary
+ # currently we have no shapes on the board
+ self.grid = {}
+
+ def draw_shape(self, shape):
+ ''' Parameters: shape - type: Shape
+ Return value: type: bool
+
+ draws the shape on the board if there is space for it
+ and returns True, otherwise it returns False
+ '''
+ # If the shape can move function returns True, draw new shape
+ if shape.can_move(self, 0, 0):
+ shape.draw(self.canvas)
+ return True
+ # If not, no shape can be drawn (game over)
+ else:
+ self.game_over()
+
+ def can_move(self, x, y):
+ ''' Parameters: x - type:int
+ y - type:int
+ Return value: type: bool
+
+ 1. check if it is ok to move to square x,y
+ if the position is outside of the board boundaries, can't move there
+ return False
+
+ 2. if there is already a block at that postion, can't move there
+ return False
+
+ 3. otherwise return True
+
+ '''
+ # if this x, y coordinates are within the board and there are no pieces there (aka no keys
+ # with the coordinates in the dictionary), return True
+ if (x >= 0 and x < self.width) and (y >= 0 and y < self.height) and (x, y) not in self.grid.keys():
+ return True
+ return False
+
+ pass
+
+ def add_shape(self, shape):
+ ''' Parameter: shape - type:Shape
+
+ add a shape to the grid, i.e.
+ add each block to the grid using its
+ (x, y) coordinates as a dictionary key
+
+ Hint: use the get_blocks method on Shape to
+ get the list of blocks
+
+ '''
+
+ #For each block in a given shape, add it to the self.grid dictionary
+ for block in shape.get_blocks():
+ self.grid[(block.x, block.y)] = block
+
+
+ def delete_row(self, y):
+ ''' Parameters: y - type:int
+
+ remove all the blocks in row y
+ to remove a block you must remove it from the grid
+ and erase it from the screen.
+ If you dont remember how to erase a graphics object
+ from the screen, take a look at the Graphics Library
+ handout
+
+ '''
+ # If the row is complete (use is_row_complete method)
+ if self.is_row_complete(y) == True:
+ #For every key in the block dictionary,
+ for item in self.grid.keys():
+ # If the y coordinate of that key matches the row that must be removed
+ if item[1] == y:
+ #Undraw the item and delete it from the dictionary
+ self.grid[item].undraw()
+ del self.grid[item]
+
+
+ def is_row_complete(self, y):
+ ''' Parameter: y - type: int
+ Return value: type: bool
+
+ for each block in row y
+ check if there is a block in the grid (use the in operator)
+ if there is one square that is not occupied, return False
+ otherwise return True
+
+ '''
+ # Define empty dictionary to keep track of blocks in row
+ y_list = []
+ # for every block on the board, if it is in this row, append to list
+ for block in self.grid.keys():
+ if block[1] == y:
+ y_list.append(block)
+
+
+ # If the row is full (i.e. length of the list is the same as the width of the board)
+ # empty the list and return True
+ if len(y_list) == self.width:
+ y_list = []
+ return True
+ return False
+
+
+ def move_down_rows(self, y_start):
+ ''' Parameters: y_start - type:int
+
+ for each row from y_start to the top
+ for each column
+ check if there is a block in the grid
+ if there is, remove it from the grid
+ and move the block object down on the screen
+ and then place it back in the grid in the new position
+
+ '''
+ # For each row from y_start to the top
+ for row in range(y_start, 0, -1):
+ # And each column on the board
+ for column in range(0, self.width):
+ # If there is a block there, move it down 1, delete from grid
+ # and add new coordinates to the grid
+ if (column, row) in self.grid.keys():
+ #print "WE MADE IT"
+ self.grid[(column, row)].move(0, 1)
+ block = self.grid[(column, row)]
+ del self.grid[(column, row)]
+ self.grid[(column, row + 1)] = block
+
+ def remove_complete_rows(self):
+ ''' removes all the complete rows
+ 1. for each row, y,
+ 2. check if the row is complete
+ if it is,
+ delete the row
+ move all rows down starting at row y - 1
+
+ '''
+ # Define empty list for keeping track of how many lines deleted(scoring purposes)
+ lines_completed = []
+
+ #For each row in the board, if it is complete, delete, move down rows,
+ #Append the list
+ for row in range(0, self.height):
+ if self.is_row_complete(row) == True:
+ #print "YADDA YADDA"
+ self.delete_row(row)
+ self.move_down_rows(row - 1)
+ lines_completed.append('a')
+ # Call the add_score method in the scoreboard class with the # of completed lines
+ self.scoreboard.add_score(len(lines_completed))
+
+ def game_over(self):
+ ''' display "Game Over !!!" message in the center of the board
+ HINT: use the Text class from the graphics library
+ '''
+ # Displays game_over message on screen
+ game_over_message = Text(Point(150, 250), "GAME OVER \n BEETCHES")
+ game_over_message.setStyle('bold')
+ game_over_message.setSize(25)
+ game_over_message.setTextColor('white')
+ game_over_message.setFace('helvetica')
+ game_over_message.draw(self.canvas)
+
+
+############################################################
+# SCOREBOARD CLASS
+############################################################
+
+class Scoreboard():
+
+
+ def __init__(self, win, width, height):
+ self.width = width
+ self.height = height
+
+ # create a canvas to draw the tetris shapes on
+ self.canvas = CanvasFrame(win, self.width * Block.BLOCK_SIZE,
+ 100)
+ self.canvas.setBackground('black')
+
+ # Start the score off at 0, level off at 1
+ self.current_score = 0
+ self.current_level = 1
+
+ # Text object displaying the Score
+ self.score = Text(Point(75, 25), "Score: " + str(self.current_score))
+ self.score.setStyle('bold')
+ self.score.setSize(18)
+ self.score.setTextColor('white')
+ self.score.setFace('helvetica')
+
+ # Text object displaying the Level
+ self.levels = Text(Point(75, 50), "Level: " + str(self.current_level))
+ self.levels.setStyle('bold')
+ self.levels.setSize(18)
+ self.levels.setTextColor('white')
+ self.levels.setFace('helvetica')
+
+ # Draw the Text objects on the screen
+ self.score.draw(self.canvas)
+ self.levels.draw(self.canvas)
+
+ # Set the current_level = the method defined below
+ self.current_level = self.increase_level()
+
+ # This method is called from remove_complete_rows method, using len(lines_completed) as parameter
+ def add_score(self, lines):
+ # Depending on # of lines completed, add score accordingly
+ if lines == 1:
+ self.current_score += 100
+ elif lines == 2:
+ self.current_score += 300
+ elif lines == 3:
+ self.current_score += 450
+ elif lines == 4:
+ self.current_score += 700
+ #Change Text Object
+ self.score.setText("Score: "+ str(self.current_score))
+
+ def increase_level(self):
+ # Depending on Score, change level and text object
+ while self.current_score <= 1000:
+ self.current_level = 1
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 1000 and self.current_score <= 5000:
+ self.current_level = 2
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 5000 and self.current_score <= 10000:
+ self.current_level = 3
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 10000 and self.current_score <= 15000:
+ self.current_level = 4
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 15000 and self.current_score <= 19000:
+ self.current_level = 5
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 19000 and self.current_score <= 23000:
+ self.current_level = 6
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 23000 and self.current_score <= 27000:
+ self.current_level = 7
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 27000 and self.current_score <= 30000:
+ self.current_level = 8
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 30000 and self.current_score <= 33000:
+ self.current_level = 9
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+ while self.current_score > 33000:
+ self.current_level = 10
+ self.levels.setText("Level: "+ str(self.current_level))
+ return self.current_level
+
+
+############################################################
+# TETRIS CLASS
+############################################################
+
+class Tetris():
+ ''' Tetris class: Controls the game play
+ Attributes:
+ SHAPES - type: list (list of Shape classes)
+ DIRECTION - type: dictionary - converts string direction to (dx, dy)
+ BOARD_WIDTH - type:int - the width of the board
+ BOARD_HEIGHT - type:int - the height of the board
+ board - type:Board - the tetris board
+ win - type:Window - the window for the tetris game
+ delay - type:int - the speed in milliseconds for moving the shapes
+ current_shapes - type: Shape - the current moving shape on the board
+ '''
+
+ SHAPES = [I_shape, J_shape, L_shape, O_shape, S_shape, T_shape, Z_shape]
+ DIRECTION = {'Left':(-1, 0), 'Right':(1, 0), 'Down':(0, 1)}
+ BOARD_WIDTH = 10
+ BOARD_HEIGHT = 20
+
+ def __init__(self, win):
+ self.board = Board(win, self.BOARD_WIDTH, self.BOARD_HEIGHT)
+ self.win = win
+ self.delay = 1000 #ms
+
+ # sets up the keyboard events
+ # when a key is called the method key_pressed will be called
+ self.win.bind_all('<Key>', self.key_pressed)
+
+ # set the current shape to a random new shape
+ self.current_shape = self.create_new_shape()
+
+ # Draw the current_shape on the board (take a look at the
+ # draw_shape method in the Board class)
+ self.board.draw_shape(self.current_shape)
+
+ # For Step 9: animate the shape!
+ self.animate_shape()
+
+
+
+ def create_new_shape(self):
+ ''' Return value: type: Shape
+
+ Create a random new shape that is centered
+ at y = 0 and x = int(self.BOARD_WIDTH/2)
+ return the shape
+ '''
+ # Pick a random number from 0 to 6
+ rand_shape = random.randint(0, 6)
+ # That number corresponds to a shape in SHAPES list. Use coordinates to tell where to draw
+ new_shape = self.SHAPES[rand_shape](Point(int(self.BOARD_WIDTH/2), 0))
+ return new_shape
+
+ pass
+
+ def animate_shape(self):
+ ''' animate the shape - move down at equal intervals
+ specified by the delay attribute
+ '''
+ self.board.scoreboard.increase_level()
+ #Depending onlevel, change the delay for animation to get shorter and shorter
+ # move the shape down
+ if self.board.scoreboard.current_level == 1:
+ self.delay = 1000
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 2:
+ self.delay = 900
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 3:
+ self.delay = 800
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 4:
+ self.delay = 650
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 5:
+ self.delay = 500
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 6:
+ self.delay = 400
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 7:
+ self.delay = 300
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 8:
+ self.delay = 200
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 9:
+ self.delay = 100
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+ elif self.board.scoreboard.current_level == 10:
+ self.delay = 50
+ self.do_move('Down')
+ self.win.after(self.delay, self.animate_shape)
+
+
+ def do_move(self, direction):
+ ''' Parameters: direction - type: string
+ Return value: type: bool
+
+ Move the current shape in the direction specified by the parameter:
+ First check if the shape can move. If it can, move it and return True
+ Otherwise if the direction we tried to move was 'Down',
+ 1. add the current shape to the board
+ 2. remove the completed rows if any
+ 3. create a new random shape and set current_shape attribute
+ 4. If the shape cannot be drawn on the board, display a
+ game over message
+
+ return False
+
+ '''
+ # space bar is hit, move shape down until it can't move anymore
+ if direction == 'space':
+ while self.current_shape.can_move(self.board, self.DIRECTION['Down'][0], self.DIRECTION['Down'][1]) == True:
+ self.current_shape.move(self.DIRECTION['Down'][0], self.DIRECTION['Down'][1])
+ # add new shape to grid, create new shape to draw, and check for completed rows
+ self.board.add_shape(self.current_shape)
+ self.current_shape = self.create_new_shape()
+ self.board.draw_shape(self.current_shape)
+ self.board.remove_complete_rows()
+
+ #if the shape can move in the direction given by DIRECTION list, move it there
+ elif self.current_shape.can_move(self.board, self.DIRECTION[direction][0], self.DIRECTION[direction][1]) == True:
+ self.current_shape.move(self.DIRECTION[direction][0], self.DIRECTION[direction][1])
+ return True
+
+ else:
+ # if the shape can't move any moore
+ if direction == 'Down':
+ # add new shape to grid, create new shape to draw, and check for completed rows
+ self.board.add_shape(self.current_shape)
+ self.current_shape = self.create_new_shape()
+ self.board.draw_shape(self.current_shape)
+ self.board.remove_complete_rows()
+ return False
+
+
+ def do_rotate(self):
+ ''' Checks if the current_shape can be rotated and
+ rotates if it can
+ '''
+
+
+ #If shape can rotate, rotate it
+ if self.current_shape.can_rotate(self.board) == True:
+ self.current_shape.rotate(self.board)
+
+
+
+ def key_pressed(self, event):
+ ''' this function is called when a key is pressed on the keyboard
+ it currenly just prints the value of the key
+
+ Modify the function so that if the user presses the arrow keys
+ 'Left', 'Right' or 'Down', the current_shape will move in
+ the appropriate direction
+
+ if the user presses the space bar 'space', the shape will move
+ down until it can no longer move and is added to the board
+
+ if the user presses the 'Up' arrow key ,
+ the shape should rotate.
+
+ '''
+
+
+ key = event.keysym
+ # If key is up, call do_rotate function
+ if key == 'Up':
+ self.do_rotate()
+
+ # Else, call do_move function
+ else:
+ self.do_move(key)
+
+
+
+################################################################
+# Start the game
+################################################################
+
+win = Window("Tetris")
+game = Tetris(win)
+win.mainloop()
diff --git a/originaltetris/tetrisGUI.py b/originaltetris/tetrisGUI.py
new file mode 100644
index 0000000..8085980
--- /dev/null
+++ b/originaltetris/tetrisGUI.py
@@ -0,0 +1,120 @@
+"""
+This is the class you run to run tetris.
+Handles input and output
+"""
+
+from Tkinter import *
+
+#GUI
+class GUI( Frame ):
+ def __init__(self, parent, scale=20, max_x=10, max_y=20, offset=3):
+ print "initialize gui"
+ """
+ Init and config the tetris computer display
+ """
+ Frame.__init__(self, parent)
+ self.parent = parent
+ self.scale = scale
+ self.max_x = max_x
+ self.max_y = max_y
+ self.offset = offset
+ #height = rows + one blank + score row
+ #width = left board + 4 blank + right board
+ self.canvas = Canvas(parent,
+ height=((max_y+2) * scale)+offset,
+ width= 2*((max_x+2) * scale)+offset)
+ #size of one board plus buffer
+ self.boardsize = ((max_x+4) * scale)+offset
+ self.canvas.pack()
+
+
+ def add_block(self, (x, y), color):
+ """
+ Draw a block on the canvas
+ """
+ shrink = 4
+ rx = (x * self.scale) + self.offset
+ ry = (y * self.scale) + self.offset
+ #self.canvas.create_oval(rx+shrink, ry+shrink, rx+self.scale-shrink,
+ #ry+self.scale-shrink, width=0, fill=color)
+ self.canvas.create_rectangle(
+ rx, ry, rx+self.scale, ry+self.scale, fill=color
+ )
+ """
+ def draw_board(self, color_dict):
+ self.canvas.delete(ALL)
+ #ARRAY or DICT...
+ for b in color_dict:
+ self.add_block(b)
+ """
+ def draw_board(self, players):
+ self.canvas.delete(ALL)
+ x_width = self.max_x*self.scale+3
+ y_width = self.max_y*self.scale+3
+ gap = 4*self.scale
+ self.canvas.create_rectangle(3,2,x_width, y_width)
+ self.canvas.create_rectangle(x_width+gap,2,2*x_width+gap-3, y_width)
+ offset = 0
+ for p in players:
+ landed = p.board.landed
+ for b in landed:
+ self.add_block((b[0]+offset, b[1]), landed[b])
+ for b in p.shape.blocks:
+ self.add_block((b.x+offset, b.y), b.color)
+ offset += (self.max_x + 4)
+
+ self.display_score(players[0].score,0)
+ self.display_score(players[1].score,1)
+
+ def display_score(self, score, player_num):
+ offset = player_num * (self.max_x + 4)
+ for i in range(10):
+ bit = score%2
+ score = score>>1
+ coord = (self.max_x-1-i + offset, self.max_y+1)
+ if bit:
+ self.add_block(coord, "yellow")
+ else:
+ self.add_block(coord, "gray")
+
+"""
+def update_display(player1,player2)
+ nah = process(meh)
+ #debug mode:
+ display_image(nah)
+ #real mode:
+ #update_lights(nah)
+
+
+#waiting
+#press
+start = false
+while (!start)
+if (get_press(p0s)and p0_is_in) or (p1s and p1_is_in):
+ start = true
+if get_press(p0in):
+ game.add_player(0)
+if p1in:
+ game.add_player(1)
+
+animate countdown
+
+#assume 1p
+handle controls...
+p0.left()
+p0.right()
+etc
+
+get state...
+if p0.update()...
+ update_display(p0.board, p0.score)
+
+if p0.died:
+ end
+
+animate end_seq(score)
+
+goto waiting
+
+
+"""
diff --git a/originaltetris/tetris_shape.py b/originaltetris/tetris_shape.py
new file mode 100644
index 0000000..a0ec59e
--- /dev/null
+++ b/originaltetris/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")