Question
Tetris (Part 1) Overview You will be implementing the game Tetris. If you don't know the game, you can find out about in on the
Tetris (Part 1) Overview You will be implementing the game Tetris. If you don't know the game, you can find out about in on the internet, or come see me. Tetris is a deceptively simple, completely addictive puzzle game. Small pieces fall from the top of the Grid to the bottom. The pieces are comprised of 4 squares arranged into 7 different patterns. Players must rotate the pieces as they fall and fit them together to complete lines. When the player fills an entire line with blocks, that line is removed from the screen. If the player cannot complete lines, the blocks will eventually fill to the top of the screen and the game ends. shapes Concepts The purpose of this assignment is to gain experience with the following concepts: class relationships understanding and modifying provided code 2-dimensional arrays Program Synopsis In the real game of Tetris, a tetris piece, composed of 4 contiguous squares, falls from the top of the grid. The piece can be moved left, right, or down as well as rotate clockwise. When the piece lands on the bottom of the grid or another piece it becomes frozen, that is to say, a part of the grid, and then another piece is created. If an entire row fills up with parts of different pieces, then the entire row is removed and the rows above it are moved down. Play continues until the pieces pile up to the top and a new piece is created on top of already frozen pieces. The starter code for this project implements a simple game that only creates a single L-shaped piece that can move downwards. It uses elementary keyboard input and graphics classes. For Homework #1, you will add specific features to make it a more complete Tetris game. (Homework #2 will ask you to produce a complete Tetris game that uses different shapes.) Download the starter code . Here is a description of the different classes. These first 2 classes have to do with the user interface Tetris.java - class to handle the graphics display. Also contains the main method to start the game. You do not have to modify this class at all. There is a lot of graphics code in here that you probably are not familiar with. Don't worry; we will learn about it as the quarter progresses. GameController.java - class to react to events (like key presses and timer events) and tells the game what to do. You will not add any methods to this class, but you will have to modify an existing method. There is a lot of event handling code in here that you probably are not familiar with. Don't worry; we will learn about it as the quarter progresses. The rest of the classes have to do with modeling the game. Except for the draw(Graphics g) methods, you should be able to read and understand the rest of the code. Game.java - code that keeps track of the current piece and the board. It contains the public methods to actually "play" the game. Grid.java - the grid is actually the board area on the screen where the piece can move. It also keeps track of where previous pieces have "frozen." LPiece.java - the game piece Square.java - the building block for the LPiece and the Grid Read through and become familiar with the sample code provided. Determine what the different relations are between different classes and what the different methods do. Drawings would come in handy here. For this homework, you will modify the game so that it will produce another piece once the current one has stopped moving. In addition, you will add the ability for the L-shaped piece to move LEFT and RIGHT . Finally, you will implement removal of solid rows from the Grid. lshape Program Details 1.In order to get another piece to appear on the screen, the Game class needs to be able to create a new piece after the previous piece has been frozen. Read through the starter code and find the correct place to make that happen (I have it commented). The new piece should have the same starting state as the piece created in the Game constructor. 2.Currently, the piece moves DOWN if the space key is pressed (this will move it faster than it normally falls). Modify the GameController class so that the piece moves down if the down arrow key is pressed as well. The game piece also needs to be able to move LEFT and RIGHT if the corresponding arrow keys are pressed. In order to handle these keys, you will need to modify the method keyPressed(keyEvent e). You will find the correct constant names for the associated keys in the KeyEvent class in the Java API. In addition, you will have to modify other methods of one of the provided classes in order to get the correct behavior. Reading the code and understanding the flow of method calls will make it clear which class you need to change. 3.ROW-REMOVAL: Implement the method checkRows() in the Grid class. This method should look through the grid and determine if there is a completely filled in row (a row of all non EMPTY Squares). If such a row is found, it should be removed and all the rows above it should be moved down. All such rows should be found and removed in one call to checkRows. See the figure to understand the operation. (Note that at this point, you only have the L-shaped piece to work with. The example below shows what can happen when the other pieces have been implemented.) You may find it useful to define a couple of private methods to help. row removal Notice here that the bottom 2 rows are filled. They are removed and the rows above are moved down. Questions? Please feel free to ask questions at the beginning of class. Also, the forum is a great place to ask questions about the requirements for this assignment. You might also check occasionally to see what questions other people have asked -- perhaps someone has thought of something that didn't occur to you. Written Report This quarter, all of your assignments will include a typed, written report. Since this first assignment is more of a review, this report will be brief, just a few questions: 1.Testing: How did you test your code? What sort of bugs did you encounter? Are there any unresolved problems in the code? Be sure to list any ways in which the program falls short of the specification. 2.Evaluate this project. What did you learn from it, or what did it help you remember? Was it worth the effort? This could include things you learned about specifications and interfaces, design issues, Java language issues, debugging, etc.
/** * Create and control the game Tetris. * * NOTE: when putting a Tetris object in a top-level container, make sure the Tetris * object has the focus (use requestFocus()) * * @author CSC 143 Based on a C++ version written by the * University of Washington CSE department */ import javax.swing.*; import java.awt.*; import java.awt.event.*;
public class Tetris extends JPanel { private Game theGame; /** Set up the parts for the Tetris game, display and user control */ public Tetris() { theGame = new Game(this); GameController ec = new GameController(theGame); addKeyListener(ec); setBackground(Color.yellow); } /** * Update the display */ public void update() { repaint(); } /** * Paint the current state of the game */ public void paintComponent(Graphics g) { super.paintComponent(g); theGame.draw(g); if (theGame.isGameOver() ) { g.setFont(new Font("Palatino", Font.BOLD, 40)); g.setColor(Color.BLACK); g.drawString("GAME OVER", 80, 300); } } /* Create a game and play it*/ public static void play() { JFrame f = new JFrame("The Tetris Game"); Tetris t = new Tetris(); f.getContentPane().add(t); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(400,600); f.validate(); f.setVisible(true); t.requestFocus(); // so that Tetris (the JPanel) fires the keyboard events. } /** * To be able to run from the command line or desktop */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { play(); } }); } }
import java.awt.*; /** * One Square on our Tetris Grid or one square in our Tetris game piece * * @author csc143 */ public class Square { private Grid theGrid; // the environment where this Square is private int row, col; // the grid location of this Square private boolean ableToMove; // true if this Square can move private Color color; // the color of this Square // possible move directions are defined by the Game class // dimensions of a Square public static final int WIDTH = 20; public static final int HEIGHT = 20; /** * Constructor for objects of class Square * @param g the Grid for this Square * @param row the row of this Square in the Grid * @param col the column of this Square in the Grid * @param c the Color of this Square * @param mobile true if this Square can move * * @throws IllegalArgumentException if row and col not within the Grid */ public Square(Grid g, int row, int col, Color c, boolean mobile){ if (row < 0 || row > g.HEIGHT-1) throw new IllegalArgumentException("Invalid row =" + row); if (col < 0 || col > g.WIDTH-1) throw new IllegalArgumentException("Invalid column = " + col); // initialize instance variables theGrid = g; this.row = row; this.col = col; color = c; ableToMove = mobile; }
/** * Return the row for this Square */ public int getRow() { return row; } /** * Return the column for this Square */ public int getCol() { return col; } /** * Return true if this Square can move 1 spot in direction d * @param direction the direction to test for possible move * @throws IllegalArgumentException if direction is not valid */ public boolean canMove(int direction){ if (!ableToMove) return false; boolean move = true; // if the given direction is blocked, we can't move // remember to check the edges of the grid switch(direction) { case Game.DOWN: if (row == (theGrid.HEIGHT -1) || theGrid.isSet(row + 1, col)) move = false; break; //currently doesn't support checking LEFT or RIGHT //MODIFY so that it correctly returns if it can move left or right case Game.LEFT: case Game.RIGHT: move = false; break; default: throw new IllegalArgumentException("Bad direction to Square.canMove()"); } return move; } /** move Square in the given direction if possible * Square will not move if direction is blocked, or Square is unable to move * If attempt to move DOWN and it can't, the Square is frozen * and cannot move anymore * @param direction the direction to move */ public void move(int direction) { if (canMove(direction)) { switch(direction) { case Game.DOWN: row = row + 1; break; // currently doesn't support moving LEFT or RIGHT // MODIFY so that the Square moves appropriately } } } /** Change the color of the Square * @param c the new color */ public void setColor(Color c) { color = c; } /** Get the color of this Square */ public Color getColor() { return color; } /** * Draw this square on the given Graphics context */ public void draw(Graphics g) { // calculate the upper left (x,y) coordinate of this square int actualX = theGrid.LEFT + col * WIDTH; int actualY = theGrid.TOP + row * HEIGHT; g.setColor(color); g.fillRect(actualX, actualY, WIDTH, HEIGHT); } }
import java.awt.*; /** * An LPiece item in the Tetris Game. * * This piece is made up of 4 squares in the following configuration * Sq * Sq * Sq Sq * * The game piece "floats above" the Grid. The (row, col) coordinates * are the location of the middle Square on the side within the Grid * * @author CSC 143 */ public class LPiece { private boolean ableToMove; // can this piece move private Square[] square; // the Squares that make up this piece // Made up of PIECE_COUNT squares private Grid theGrid; // the board this piece is on // number of squares in 1 Tetris game piece private static final int PIECE_COUNT = 4; /** * Create an L-Shape piece. See class description for actual location * of r and c * @param r row location for this piece * @param c column location for this piece * @param g the grid for this game piece * */ public LPiece(int r, int c, Grid g) { theGrid = g; square = new Square[PIECE_COUNT]; ableToMove = true; // Create the squares square[0] = new Square(g, r - 1, c, Color.magenta, true); square[1] = new Square(g, r, c , Color.magenta, true); square[2] = new Square(g, r + 1, c, Color.magenta, true); square[3] = new Square(g, r + 1, c + 1, Color.magenta, true); } /** * Draw the piece on the given Graphics context */ public void draw(Graphics g){ for (int i = 0; i < PIECE_COUNT; i++) square[i].draw(g); } /** * Move the piece if possible * Freeze the piece if it cannot move down anymore * @param direction the direction to move * @throws IllegalArgumentException if direction is not Square.DOWN, * Square.LEFT, or Square.RIGHT */ public void move(int direction){ if (canMove(direction)){ for (int i = 0; i < PIECE_COUNT; i++) square[i].move(direction); } // if we couldn't move, see if because we're at the bottom else if (direction == Game.DOWN){ ableToMove = false; } }
/** Return the (row,col) grid coordinates occupied by this Piece * @return an Array of (row,col) Points */ public Point[] getLocations(){ Point[] points = new Point[PIECE_COUNT]; for(int i = 0; i < PIECE_COUNT; i++) { points[i] = new Point(square[i].getRow(), square[i].getCol()); } return points; } /** * Return the color of this piece */ public Color getColor() { // all squares of this piece have the same color return square[0].getColor(); } /** * Returns if this piece can move in the given direction * @throws IllegalArgumentException if direction is not Square.DOWN, * Square.LEFT, or Square.RIGHT */ public boolean canMove(int direction) { if (!ableToMove) return false; //Each square must be able to move in that direction boolean answer = true; for (int i = 0; i < PIECE_COUNT; i++) { answer = answer && square[i].canMove(direction); } return answer; } }
import java.awt.*; /** * This is the Tetris board represented by a (HEIGHT - by - WIDTH) matrix of Squares * The upper left Square is at (0,0) The lower right Square is at (HEIGHT -1, WIDTH -1) * Given a Square at (x,y) the square to the left is at (x-1, y) * the square below is at (x, y+1) * * Each Square has a color. A white Square is EMPTY; any other color means that spot is * occupied (i.e. a piece cannot move over/to an occupied square). A grid will also remove * completely full rows. * * @author CSC 143 */ public class Grid { private Square[][] board; // Width and Height of Grid in number of squares public static final int HEIGHT = 20; public static final int WIDTH = 10; private static final int BORDER = 5; public static final int LEFT = 100; // pixel position of left of grid public static final int TOP = 75; // pixel position of top of grid private static final Color EMPTY = Color.white; /** * Create the Grid */ public Grid() { board = new Square[HEIGHT][WIDTH]; //put squares in the board for (int row = 0; row < HEIGHT; row++) for(int col = 0; col < WIDTH; col++) board[row][col] = new Square(this, row, col, EMPTY, false);
}
/** * Returns true if the location (row, col) on the grid is occupied * @param row the row in the grid * @param col the column in the grid */ public boolean isSet( int row, int col){ boolean isEmpty = board[row][col].getColor().equals(EMPTY); return !isEmpty; } /** * Change the color of the Square at the given location * @param row the row of the Square in the Grid * @param col the column of the Square in the Grid * @param c the color to set the Square * @throws IndexOutOfBoundsException if row < 0 || row>= WIDTH || col < 0 || col >= HEIGHT */ public void set(int row, int col, Color c) { board[row][col].setColor(c); } /** * Check for and remove all solid rows of squares * If a solid row is found and removed, all rows above * it are moved down and the top row set to empty */ public void checkRows() { } /** * Draw the grid on the given Graphics context */ public void draw(Graphics g){ // draw the edges as rectangles: left, right in blue then bottom in red g.setColor(Color.blue); g.fillRect(LEFT - BORDER, TOP, BORDER, HEIGHT * Square.HEIGHT); g.fillRect(LEFT + WIDTH * Square.WIDTH, TOP, BORDER, HEIGHT * Square.HEIGHT); g.setColor(Color.red); g.fillRect(LEFT - BORDER, TOP + HEIGHT * Square.HEIGHT, WIDTH * Square.WIDTH + 2 * BORDER, BORDER); // draw all the squares in the grid for (int r = 0; r < HEIGHT; r++) for(int c = 0; c < WIDTH; c++) board[r][c].draw(g); } }
/** * Handles events for the Tetris Game. User events (key strokes) as well as periodic timer * events. * * @author CSC 143 */ import java.awt.event.*; import javax.swing.*;
public class GameController extends KeyAdapter implements ActionListener { private Game theGame; private Timer timer; private static final double PIECE_MOVE_TIME = 0.8; //controls time between //piece moving down //increase to slow it down private boolean gameOver; /** * Constructor for objects of class EventController * @param g the game this is controlling */ public GameController(Game g) { theGame = g; gameOver = false; double delay = 1000 * PIECE_MOVE_TIME; // in milliseconds timer = new Timer((int)delay, this); timer.setCoalesce(true); // if multiple events pending, bunch them to 1 event timer.start(); }
/* * Respond to special keys being pressed * Currently just responds to the space key */ public void keyPressed(KeyEvent e) { if (!gameOver) { switch(e.getKeyCode()) { case KeyEvent.VK_SPACE : handleMove(Game.DOWN); break; // HANDLE other keystrokes here } } } /** Update the game periodically based on a timer event*/ public void actionPerformed(ActionEvent e) { handleMove(Game.DOWN); } /** Update the game by moving in the given direction */ private void handleMove(int direction){ theGame.movePiece(direction); gameOver = theGame.isGameOver(); if (gameOver) timer.stop(); } }
import java.awt.*; /** * Manages the game Tetris. Keeps track of the current piece and the grid. * Updates the display whenever the state of the game has changed. * * @author CSC 143 */ public class Game { private Grid theGrid; // the grid that makes up the Tetris board private Tetris theDisplay; // the visual for the Tetris game private LPiece piece; // the current piece that is dropping private boolean isOver; // has the game finished? // possible move directions public static final int LEFT = 0; public static final int RIGHT = 1; public static final int DOWN = 2; /** * Create a Tetris game * @param Tetris the display */ public Game(Tetris display) { theGrid = new Grid(); theDisplay = display; piece = new LPiece(1, Grid.WIDTH/2 -1, theGrid); isOver = false; }
/** Draw the current state of the game * @param g the Graphics context on which to draw */ public void draw(Graphics g) { theGrid.draw(g); if (piece != null) piece.draw(g); } /** Move the piece in the given direction * @param the direction to move * @throws IllegalArgumentException if direction is not legal */ public void movePiece(int direction){ if (piece != null) piece.move(direction); updatePiece(); theDisplay.update(); theGrid.checkRows(); } /** * Returns true if the game is over */ public boolean isGameOver() { // game is over if the piece occupies the same space as some non-empty // part of the grid. Usually happens when a new piece is made if (piece == null) return false; // check if game is already over if (isOver) return true; // check every part of the piece Point[] p = piece.getLocations(); for (int i = 0; i
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started