import java.awt.*; /** This class is a single cell used in a Tetris board. It knows how to paint * itself, who its neighbors are, and whether it is occupied. * * @author Russell Young tetrii@young-0.com * @version 1.0 */ /* Feel free to use, distribute, or change, with the only restriction that you * should not remove my name from the original code, and you should document * your changes so there is no confusion about whose bugs they are. */ public class Cell implements Constants { /** This is used as a marker for all neighbors off the array. Originally I * used null, but then all the directional operations had to check for * null. This way they just fall into the sink. */ static Cell none = new Cell(); Cell neighbors[] = new Cell[4]; /** These must be indirect to make it easy to manipulate rows and columns.*/ variableInt X, Y; private boolean filled; private Color color = null; /** This constructor is used to make a Cell that is off the board, used * as a neighbor to every Cell that is on the edge. */ protected Cell() { neighbors[0] = neighbors[1] = neighbors[2] = neighbors[3] = this; X = Y = null; filled = true; } /** For left-to-right, top-to-bottom creation, just require the left neighbor */ protected Cell(variableInt xx, variableInt yy, Cell n0) { this(xx, yy, n0, n0.up().right());} protected Cell(variableInt xx, variableInt yy, Cell left, Cell up) { this(xx, yy, left, up, none);} /** The most general constructor, used to add cells above or below in the * current grid. (right can easily be filled in as well, if right-to-left * is ever needed) */ protected Cell(variableInt xx, variableInt yy, Cell left, Cell up, Cell down) { X = xx; Y = yy; neighbors[0] = neighbors[1] = neighbors[2] = neighbors[3] = none; Cell right = none; // For now assume left-to-right creation if (left != null) (neighbors[LEFT] = left).right(this); if (up != null) (neighbors[UP] = up).down(this); if (down != null) (neighbors[DOWN] = down).up(this); if (right != null) (neighbors[RIGHT] = right).left(this); clear(); } /** Initializes a rectangular array of Cells of the deisred size, with * all neighbors filled in properly, and `filled ' set to false * * @param width the int number of Cells across in the array * @param height the int number of Cells down in the array * @return the Cell at the upper left of the array */ public static Cell initializeArray(int width, int height) { Cell nextUp, up, left = none; variableInt xx[], yy; int i, j; xx = new variableInt[width]; for (i = 0; i < width; i++) xx[i] = new variableInt(i); for (nextUp = none, i = 0; i < height; i++) { up = nextUp; yy = new variableInt(i); for (j = 0, left = none; j < width; j++) { left = new Cell(xx[j], yy, left, up); if (j == 0) nextUp = left; up = up.right(); } } return(left.up(height - 1).left(width - 1)); } /** Set the neighbor in the given direction to be the given Cell * @param dir an int giving the direction (LEFT, UP, RIGHT, DOWN) * @param c the Cell to set it to */ void set(int dir, Cell c) { if (this != none) neighbors[dir] = ((c == null) ? none : c);} /** Set the left neighbor to be the given Cell * @param c the Cell to set it to */ void left(Cell c) {set(LEFT, c);} /** Set the up neighbor to be the given Cell * @param c the Cell to set it to */ void up(Cell c) {set(UP, c);} /** Set the right neighbor to be the given Cell * @param c the Cell to set it to */ void right(Cell c) {set(RIGHT, c);} /** Set the down neighbor to be the given Cell * @param c the Cell to set it to */ void down(Cell c) {set(DOWN, c);} /** Gets the neighbor in the given direction. * @param dir an int giving the direction (LEFT, UP, RIGHT, DOWN) * @return the Cell in the given direction */ public Cell get(int dir) {return(neighbors[dir]);} /** Gets the left neighbor * @return the Cell in the given direction */ public Cell left() {return(left(1));} /** Gets the up neighbor * @return the Cell in the given direction */ public Cell up() {return(up(1));} /** Gets the right neighbor * @return the Cell in the given direction */ public Cell right() {return(right(1));} /** Gets the down neighbor * @return the Cell in the given direction */ public Cell down() {return(down(1));} /** Gets the Cell i steps away in direction dir * @param dir an int giving the direction (UP, DOWN, LEFT, RIGHT) * @param i an int telling how far to go * @return the desired Cell, or none if a border is hit */ public Cell get(int dir, int i) { if ((this == none) || (i <= 0)) return(this); return(neighbors[dir].get(dir, i - 1)); } /** Gets the Cell i steps away to the left * @param i an int telling how far to go * @return the desired Cell, or none if a border is hit */ public Cell left(int i) {return(get(LEFT, i));} /** Gets the Cell i steps away up * @param i an int telling how far to go * @return the desired Cell, or none if a border is hit */ public Cell up(int i) {return(get(UP, i));} /** Gets the Cell i steps away to the right * @param i an int telling how far to go * @return the desired Cell, or none if a border is hit */ public Cell right(int i) {return(get(RIGHT, i));} /** Gets the Cell i steps away down * @param i an int telling how far to go * @return the desired Cell, or none if a border is hit */ public Cell down(int i) {return(get(DOWN, i));} /** tells if this cell is on the board * @return true if it is */ public boolean on() {return(this != none);} /** Clears out a Cell that might be filled in */ void clear() { filled = false; color = null; } /** Tells if a Cell is permanently occupied * @return boolean true if yes */ public boolean occupied() {return(filled);} /** Sets the occupied property of a Cell * @param the boolean new value to set */ void occupied(boolean yorn) {filled = yorn;} /** Gets the color of a Cell * @return the Color of the Cell (null for none) */ Color getColor() {return(color);} /** Sets the color of a Cell * @return the Color of the Cell (null for none) */ void setColor(Color c) {color = c;} /** Checks to see if there is a free cell in the given direction * @return boolean true if there is */ boolean check(int dir) {return(!neighbors[dir].occupied());} /** Paints the cell, after first setting the color * @param color a Color * @param g the Graphics context to draw in */ public void paint(Color color, Graphics g) { setColor(color); paint(g); } /** Paints the cell, after first setting the color * @param g the Graphics context to draw in */ public void paint(Graphics g) { try { int i, j; i = X.value() * CELL_WIDTH; j = Y.value() * CELL_HEIGHT; if (color == null) g.clearRect(i, j, CELL_WIDTH - 1, CELL_HEIGHT - 1); else { g.setColor(color); g.fillRect(i, j, CELL_WIDTH - 1, CELL_HEIGHT - 1); } } catch (Exception e) {show(); } } // Debugging functions /** Replaces the Object definition * @return a String giving the Cell, or `none' if it is the none value */ public String toString() { if (this == none) return("none"); return(super.toString()); } /** Prints out the Cell state, for debugging */ public void show() { System.out.println(toString() + " at " + X + ", " + Y + " " + occupied() + " " + getColor() + " " + neighbors[0] + " " + neighbors[1] + " " + neighbors[2] + " " + neighbors[3]);} }