Advertisement
CSenshi

OOP - HW2 Milestone: B (Board.java)

Apr 13th, 2020
599
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.51 KB | None | 0 0
  1. // Board.java
  2. package tetris;
  3.  
  4. import java.util.Arrays;
  5.  
  6. /**
  7.  * CS108 Tetris Board.
  8.  * Represents a Tetris board -- essentially a 2-d grid
  9.  * of booleans. Supports tetris pieces and row clearing.
  10.  * Has an "undo" feature that allows clients to add and remove pieces efficiently.
  11.  * Does not do any drawing or have any idea of pixels. Instead,
  12.  * just represents the abstract 2-d board.
  13.  */
  14. public class Board {
  15.     // Some ivars are stubbed out for you:
  16.     private int width;
  17.     private int height;
  18.     private boolean[][] grid;
  19.     private boolean DEBUG = true;
  20.     boolean committed;
  21.  
  22.     // variables for current state
  23.     private int[] widths;
  24.     private int[] heights;
  25.     private int maxHeight;
  26.  
  27.     // variables needed for backups
  28.     private boolean[][] backupGrid;
  29.     private int[] backupWidths;
  30.     private int[] backupHeights;
  31.     private int backupMaxHeight;
  32.  
  33.     // Here a few trivial methods are provided:
  34.  
  35.     /**
  36.      * Creates an empty board of the given width and height
  37.      * measured in blocks.
  38.      */
  39.     public Board(int width, int height) {
  40.         this.width = width;
  41.         this.height = height;
  42.         this.grid = new boolean[width][height];
  43.         this.committed = true;
  44.  
  45.         // init helper arrays
  46.         this.widths = new int[height];
  47.         this.heights = new int[width];
  48.  
  49.         // backups
  50.         this.backupGrid = this.grid;
  51.         this.backupWidths = this.widths;
  52.         this.backupHeights = this.heights;
  53.     }
  54.  
  55.  
  56.     /**
  57.      * Returns the width of the board in blocks.
  58.      */
  59.     public int getWidth() {
  60.         return width;
  61.     }
  62.  
  63.  
  64.     /**
  65.      * Returns the height of the board in blocks.
  66.      */
  67.     public int getHeight() {
  68.         return height;
  69.     }
  70.  
  71.  
  72.     /**
  73.      * Returns the max column height present in the board.
  74.      * For an empty board this is 0.
  75.      */
  76.     public int getMaxHeight() {
  77.         return maxHeight;
  78.     }
  79.  
  80.  
  81.     /**
  82.      * Checks the board for internal consistency -- used
  83.      * for debugging.
  84.      */
  85.     public void sanityCheck() {
  86.         if (DEBUG) {
  87.             // YOUR CODE HERE
  88.         }
  89.     }
  90.  
  91.     /**
  92.      * Given a piece and an x, returns the y
  93.      * value where the piece would come to rest
  94.      * if it were dropped straight down at that x.
  95.      *
  96.      * <p>
  97.      * Implementation: use the skirt and the col heights
  98.      * to compute this fast -- O(skirt length).
  99.      */
  100.     public int dropHeight(Piece piece, int x) {
  101.         int[] pieceSkirt = piece.getSkirt();
  102.  
  103.         int maxHeightDif = 0;
  104.         for (int i = 0; i < pieceSkirt.length; i++)
  105.             maxHeightDif = Math.max(getColumnHeight(x + i) - pieceSkirt[i], maxHeightDif);
  106.  
  107.         return maxHeightDif;
  108.     }
  109.  
  110.  
  111.     /**
  112.      * Returns the height of the given column --
  113.      * i.e. the y value of the highest block + 1.
  114.      * The height is 0 if the column contains no blocks.
  115.      */
  116.     public int getColumnHeight(int x) {
  117.         return this.heights[x];
  118.     }
  119.  
  120.  
  121.     /**
  122.      * Returns the number of filled blocks in
  123.      * the given row.
  124.      */
  125.     public int getRowWidth(int y) {
  126.         return this.widths[y];
  127.     }
  128.  
  129.  
  130.     /**
  131.      * Returns true if the given block is filled in the board.
  132.      * Blocks outside of the valid width/height area
  133.      * always return true.
  134.      */
  135.     public boolean getGrid(int x, int y) {
  136.         if (x >= 0 && y >= 0 && x < width && y < height)
  137.             return this.grid[x][y];
  138.         return true;
  139.     }
  140.  
  141.  
  142.     public static final int PLACE_OK = 0;
  143.     public static final int PLACE_ROW_FILLED = 1;
  144.     public static final int PLACE_OUT_BOUNDS = 2;
  145.     public static final int PLACE_BAD = 3;
  146.  
  147.     /**
  148.      * Attempts to add the body of a piece to the board.
  149.      * Copies the piece blocks into the board grid.
  150.      * Returns PLACE_OK for a regular placement, or PLACE_ROW_FILLED
  151.      * for a regular placement that causes at least one row to be filled.
  152.      *
  153.      * <p>Error cases:
  154.      * A placement may fail in two ways. First, if part of the piece may falls out
  155.      * of bounds of the board, PLACE_OUT_BOUNDS is returned.
  156.      * Or the placement may collide with existing blocks in the grid
  157.      * in which case PLACE_BAD is returned.
  158.      * In both error cases, the board may be left in an invalid
  159.      * state. The client can use undo(), to recover the valid, pre-place state.
  160.      */
  161.     public int place(Piece piece, int x, int y) {
  162.         // flag !committed problem
  163.         if (!committed) throw new RuntimeException("place commit problem");
  164.  
  165.         this.committed = false;
  166.         updateBackup();
  167.  
  168.         int resultPlace = PLACE_OK;
  169.  
  170.         // for each part of piece do validation
  171.         for (TPoint tPoint : piece.getBody()) {
  172.             // evaluate where given piece's part should be placed in board
  173.             TPoint newPoint = new TPoint(x + tPoint.x, y + tPoint.y);
  174.  
  175.             // check if new coordinates satisfy boarders
  176.             if (newPoint.x >= 0 && newPoint.y >= 0 && newPoint.x < width && newPoint.y < height) {
  177.                 // check if given part is not already filled
  178.                 if (!this.grid[newPoint.x][newPoint.y]) {
  179.  
  180.                     // update grid value at (x,y) coordinates
  181.                     this.grid[newPoint.x][newPoint.y] = true;
  182.  
  183.                     // increase counter for current y coordinate in widths array
  184.                     this.widths[newPoint.y]++;
  185.  
  186.                     // check if height at current x coordinate has changed
  187.                     this.heights[newPoint.x] = Math.max(this.heights[newPoint.x], newPoint.y + 1);
  188.  
  189.                     // check if max height of whole board has changed
  190.                     this.maxHeight = Math.max(this.maxHeight, this.heights[newPoint.x]);
  191.  
  192.                     // if one row in board has been filled up return PLACE_ROW_FILLED
  193.                     if (this.widths[newPoint.y] == this.width) {
  194.                         resultPlace = PLACE_ROW_FILLED;
  195.                     }
  196.                 } else {
  197.                     // return PLACE_BAD if board has some piece part at (x,y) coordinates
  198.                     return PLACE_BAD;
  199.                 }
  200.             } else {
  201.                 // return PLACE_OUT_BOUNDS if new coordinates are out of bounds
  202.                 return PLACE_OUT_BOUNDS;
  203.             }
  204.         }
  205.  
  206.         sanityCheck();
  207.         return resultPlace;
  208.     }
  209.  
  210.  
  211.     /**
  212.      * Deletes rows that are filled all the way across, moving
  213.      * things above down. Returns the number of rows cleared.
  214.      */
  215.     public int clearRows() {
  216.         this.committed = false;
  217.         int rowsCleared = 0;
  218.         updateBackup();
  219.  
  220.         for (int i = 0; i < this.maxHeight; i++) {
  221.             // if current row is not filled up just continue
  222.             if (this.widths[i] != width)
  223.                 continue;
  224.  
  225.             // at this point we know we should delete row at index i
  226.             // iterate from index i till the end and change grids
  227.             for (int j = i; j < this.maxHeight - 1; j++) {
  228.                 // copy upper grid elements to current element
  229.                 for (int k = 0; k < this.width; k++) grid[k][j] = grid[k][j + 1];
  230.                 // update widths array at each index
  231.                 this.widths[j] = this.widths[j + 1];
  232.             }
  233.  
  234.             // update last grid element to all false values
  235.             for (int k = 0; k < this.width; k++) grid[k][this.maxHeight - 1] = false;
  236.             // update last widths element and set it to 0
  237.             this.widths[this.maxHeight - 1] = 0;
  238.  
  239.             rowsCleared++;
  240.             i--;
  241.         }
  242.  
  243.         // recalculation of maxheight and heights array
  244.         this.maxHeight = 0;
  245.         Arrays.fill(this.heights, 0);
  246.  
  247.         // iterate over all (x,y) coordinates of grid
  248.         for (int i = 0; i < this.width; i++)
  249.             for (int j = 0; j < this.height; j++)
  250.                 if (getGrid(i, j)) {
  251.                     this.heights[i] = j + 1;
  252.                     this.maxHeight = Math.max(this.maxHeight, this.heights[i]);
  253.                 }
  254.  
  255.  
  256.         sanityCheck();
  257.         return rowsCleared;
  258.     }
  259.  
  260.  
  261.     /**
  262.      * Reverts the board to its state before up to one place
  263.      * and one clearRows();
  264.      * If the conditions for undo() are not met, such as
  265.      * calling undo() twice in a row, then the second undo() does nothing.
  266.      * See the overview docs.
  267.      */
  268.     public void undo() {
  269.         if (committed)
  270.             return;
  271.  
  272.         loadBackup();
  273.         this.committed = true;
  274.     }
  275.  
  276.  
  277.     /**
  278.      * Puts the board in the committed state.
  279.      */
  280.     public void commit() {
  281.         committed = true;
  282.     }
  283.  
  284.  
  285.     /*
  286.      Renders the board state as a big String, suitable for printing.
  287.      This is the sort of print-obj-state utility that can help see complex
  288.      state change over time.
  289.      (provided debugging utility)
  290.      */
  291.     public String toString() {
  292.         StringBuilder buff = new StringBuilder();
  293.         for (int y = height - 1; y >= 0; y--) {
  294.             buff.append('|');
  295.             for (int x = 0; x < width; x++) {
  296.                 if (getGrid(x, y)) buff.append('+');
  297.                 else buff.append(' ');
  298.             }
  299.             buff.append("|\n");
  300.         }
  301.         for (int x = 0; x < width + 2; x++) buff.append('-');
  302.         return (buff.toString());
  303.     }
  304.  
  305.     /*
  306.     Backups given state of board
  307.      */
  308.     private void updateBackup() {
  309.         // copy widths array to backup array
  310.         System.arraycopy(this.widths, 0, this.backupWidths, 0, this.widths.length);
  311.         // copy heights array to backup array
  312.         System.arraycopy(this.heights, 0, this.backupHeights, 0, this.heights.length);
  313.         // Deep copy of nested 2D array into backup
  314.         for (int i = 0; i < this.grid.length; i++)
  315.             System.arraycopy(this.grid[i], 0, this.backupGrid[i], 0, this.grid[i].length);
  316.         // copy maxheight value
  317.         this.backupMaxHeight = this.maxHeight;
  318.     }
  319.  
  320.     /*
  321.     load Changes from backup
  322.      */
  323.     private void loadBackup() {
  324.         // load widths from backup
  325.         System.arraycopy(this.backupWidths, 0, this.widths, 0, this.widths.length);
  326.         // load heights from backup
  327.         System.arraycopy(this.backupHeights, 0, this.heights, 0, this.heights.length);
  328.         // Deep copy of nested 2D array of backup
  329.         for (int i = 0; i < this.grid.length; i++)
  330.             System.arraycopy(this.backupGrid[i], 0, this.grid[i], 0, this.grid[i].length);
  331.         // copy maxheight value
  332.         this.maxHeight = this.backupMaxHeight;
  333.     }
  334. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement