Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Board.java
- package tetris;
- import java.util.Arrays;
- /**
- * CS108 Tetris Board.
- * Represents a Tetris board -- essentially a 2-d grid
- * of booleans. Supports tetris pieces and row clearing.
- * Has an "undo" feature that allows clients to add and remove pieces efficiently.
- * Does not do any drawing or have any idea of pixels. Instead,
- * just represents the abstract 2-d board.
- */
- public class Board {
- // Some ivars are stubbed out for you:
- private int width;
- private int height;
- private boolean[][] grid;
- private boolean DEBUG = true;
- boolean committed;
- // variables for current state
- private int[] widths;
- private int[] heights;
- private int maxHeight;
- // variables needed for backups
- private boolean[][] backupGrid;
- private int[] backupWidths;
- private int[] backupHeights;
- private int backupMaxHeight;
- // Here a few trivial methods are provided:
- /**
- * Creates an empty board of the given width and height
- * measured in blocks.
- */
- public Board(int width, int height) {
- this.width = width;
- this.height = height;
- this.grid = new boolean[width][height];
- this.committed = true;
- // init helper arrays
- this.widths = new int[height];
- this.heights = new int[width];
- // backups
- this.backupGrid = this.grid;
- this.backupWidths = this.widths;
- this.backupHeights = this.heights;
- }
- /**
- * Returns the width of the board in blocks.
- */
- public int getWidth() {
- return width;
- }
- /**
- * Returns the height of the board in blocks.
- */
- public int getHeight() {
- return height;
- }
- /**
- * Returns the max column height present in the board.
- * For an empty board this is 0.
- */
- public int getMaxHeight() {
- return maxHeight;
- }
- /**
- * Checks the board for internal consistency -- used
- * for debugging.
- */
- public void sanityCheck() {
- if (DEBUG) {
- // YOUR CODE HERE
- }
- }
- /**
- * Given a piece and an x, returns the y
- * value where the piece would come to rest
- * if it were dropped straight down at that x.
- *
- * <p>
- * Implementation: use the skirt and the col heights
- * to compute this fast -- O(skirt length).
- */
- public int dropHeight(Piece piece, int x) {
- int[] pieceSkirt = piece.getSkirt();
- int maxHeightDif = 0;
- for (int i = 0; i < pieceSkirt.length; i++)
- maxHeightDif = Math.max(getColumnHeight(x + i) - pieceSkirt[i], maxHeightDif);
- return maxHeightDif;
- }
- /**
- * Returns the height of the given column --
- * i.e. the y value of the highest block + 1.
- * The height is 0 if the column contains no blocks.
- */
- public int getColumnHeight(int x) {
- return this.heights[x];
- }
- /**
- * Returns the number of filled blocks in
- * the given row.
- */
- public int getRowWidth(int y) {
- return this.widths[y];
- }
- /**
- * Returns true if the given block is filled in the board.
- * Blocks outside of the valid width/height area
- * always return true.
- */
- public boolean getGrid(int x, int y) {
- if (x >= 0 && y >= 0 && x < width && y < height)
- return this.grid[x][y];
- return true;
- }
- public static final int PLACE_OK = 0;
- public static final int PLACE_ROW_FILLED = 1;
- public static final int PLACE_OUT_BOUNDS = 2;
- public static final int PLACE_BAD = 3;
- /**
- * Attempts to add the body of a piece to the board.
- * Copies the piece blocks into the board grid.
- * Returns PLACE_OK for a regular placement, or PLACE_ROW_FILLED
- * for a regular placement that causes at least one row to be filled.
- *
- * <p>Error cases:
- * A placement may fail in two ways. First, if part of the piece may falls out
- * of bounds of the board, PLACE_OUT_BOUNDS is returned.
- * Or the placement may collide with existing blocks in the grid
- * in which case PLACE_BAD is returned.
- * In both error cases, the board may be left in an invalid
- * state. The client can use undo(), to recover the valid, pre-place state.
- */
- public int place(Piece piece, int x, int y) {
- // flag !committed problem
- if (!committed) throw new RuntimeException("place commit problem");
- this.committed = false;
- updateBackup();
- int resultPlace = PLACE_OK;
- // for each part of piece do validation
- for (TPoint tPoint : piece.getBody()) {
- // evaluate where given piece's part should be placed in board
- TPoint newPoint = new TPoint(x + tPoint.x, y + tPoint.y);
- // check if new coordinates satisfy boarders
- if (newPoint.x >= 0 && newPoint.y >= 0 && newPoint.x < width && newPoint.y < height) {
- // check if given part is not already filled
- if (!this.grid[newPoint.x][newPoint.y]) {
- // update grid value at (x,y) coordinates
- this.grid[newPoint.x][newPoint.y] = true;
- // increase counter for current y coordinate in widths array
- this.widths[newPoint.y]++;
- // check if height at current x coordinate has changed
- this.heights[newPoint.x] = Math.max(this.heights[newPoint.x], newPoint.y + 1);
- // check if max height of whole board has changed
- this.maxHeight = Math.max(this.maxHeight, this.heights[newPoint.x]);
- // if one row in board has been filled up return PLACE_ROW_FILLED
- if (this.widths[newPoint.y] == this.width) {
- resultPlace = PLACE_ROW_FILLED;
- }
- } else {
- // return PLACE_BAD if board has some piece part at (x,y) coordinates
- return PLACE_BAD;
- }
- } else {
- // return PLACE_OUT_BOUNDS if new coordinates are out of bounds
- return PLACE_OUT_BOUNDS;
- }
- }
- sanityCheck();
- return resultPlace;
- }
- /**
- * Deletes rows that are filled all the way across, moving
- * things above down. Returns the number of rows cleared.
- */
- public int clearRows() {
- this.committed = false;
- int rowsCleared = 0;
- updateBackup();
- for (int i = 0; i < this.maxHeight; i++) {
- // if current row is not filled up just continue
- if (this.widths[i] != width)
- continue;
- // at this point we know we should delete row at index i
- // iterate from index i till the end and change grids
- for (int j = i; j < this.maxHeight - 1; j++) {
- // copy upper grid elements to current element
- for (int k = 0; k < this.width; k++) grid[k][j] = grid[k][j + 1];
- // update widths array at each index
- this.widths[j] = this.widths[j + 1];
- }
- // update last grid element to all false values
- for (int k = 0; k < this.width; k++) grid[k][this.maxHeight - 1] = false;
- // update last widths element and set it to 0
- this.widths[this.maxHeight - 1] = 0;
- rowsCleared++;
- i--;
- }
- // recalculation of maxheight and heights array
- this.maxHeight = 0;
- Arrays.fill(this.heights, 0);
- // iterate over all (x,y) coordinates of grid
- for (int i = 0; i < this.width; i++)
- for (int j = 0; j < this.height; j++)
- if (getGrid(i, j)) {
- this.heights[i] = j + 1;
- this.maxHeight = Math.max(this.maxHeight, this.heights[i]);
- }
- sanityCheck();
- return rowsCleared;
- }
- /**
- * Reverts the board to its state before up to one place
- * and one clearRows();
- * If the conditions for undo() are not met, such as
- * calling undo() twice in a row, then the second undo() does nothing.
- * See the overview docs.
- */
- public void undo() {
- if (committed)
- return;
- loadBackup();
- this.committed = true;
- }
- /**
- * Puts the board in the committed state.
- */
- public void commit() {
- committed = true;
- }
- /*
- Renders the board state as a big String, suitable for printing.
- This is the sort of print-obj-state utility that can help see complex
- state change over time.
- (provided debugging utility)
- */
- public String toString() {
- StringBuilder buff = new StringBuilder();
- for (int y = height - 1; y >= 0; y--) {
- buff.append('|');
- for (int x = 0; x < width; x++) {
- if (getGrid(x, y)) buff.append('+');
- else buff.append(' ');
- }
- buff.append("|\n");
- }
- for (int x = 0; x < width + 2; x++) buff.append('-');
- return (buff.toString());
- }
- /*
- Backups given state of board
- */
- private void updateBackup() {
- // copy widths array to backup array
- System.arraycopy(this.widths, 0, this.backupWidths, 0, this.widths.length);
- // copy heights array to backup array
- System.arraycopy(this.heights, 0, this.backupHeights, 0, this.heights.length);
- // Deep copy of nested 2D array into backup
- for (int i = 0; i < this.grid.length; i++)
- System.arraycopy(this.grid[i], 0, this.backupGrid[i], 0, this.grid[i].length);
- // copy maxheight value
- this.backupMaxHeight = this.maxHeight;
- }
- /*
- load Changes from backup
- */
- private void loadBackup() {
- // load widths from backup
- System.arraycopy(this.backupWidths, 0, this.widths, 0, this.widths.length);
- // load heights from backup
- System.arraycopy(this.backupHeights, 0, this.heights, 0, this.heights.length);
- // Deep copy of nested 2D array of backup
- for (int i = 0; i < this.grid.length; i++)
- System.arraycopy(this.backupGrid[i], 0, this.grid[i], 0, this.grid[i].length);
- // copy maxheight value
- this.maxHeight = this.backupMaxHeight;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement