scg/ch13/pieces/Piece

From FANG

Jump to: navigation, search

001 package scg.ch13.pieces;
002 
003 import fang2.sprites.CompositeSprite;
004 import fang2.sprites.RectangleSprite;
005 
006 import java.awt.Color;
007 import java.util.ArrayList;
008 
009 import scg.ch13.core.Board;
010 
011 import scg.ch13.util.Position;
012 
013 /**
014  * The Piece abstraction made manifest. This represents a generic piece
015  * as a 5 x 5 grid. The individual piece constructors handle making any
016  * given Tetris piece.
017  */
018 public class Piece
019   extends CompositeSprite {
020   /** number of different kinds of pieces. */
021   public static int PIECE_COUNT = 7;
022 
023   /** size, in CompositeSprite screens, of each square */
024   private static final double squareEdgeSize = 0.20;
025 
026   /** the board this piece is moving on */
027   private Board board;
028 
029   /**
030    * 4 facings * 5 rows * 5 columns: each facing has a 5 x 5 two-dimensional
031    * description of the piece in that facing. Blocks are either null
032    * (empty) or non-null (full), referring to a {@link RectangleSprite}
033    * that goes in that {@link Position}.
034    */
035   private final ArrayList<ArrayList<ArrayList<RectangleSprite>>> blocksByFacing;
036 
037   /** The number of rows (columns) in this {@link Piece}'s grid */
038   private final int rows;
039   private final int columns;
040 
041   /** The current facing [0-3] of the piece */
042   private int facing;
043 
044   /** Current position of this {@link Piece} (in unit-squares) */
045   private final Position position;
046 
047   /**
048    * 4 blocks in a tetramino so there are 4 different lists in this. 4
049    * facings so 4 different positions for each block. These are the only
050    * non-empty locations in the cells for each facing. Note that the
051    * every block appears, by reference, in each facing of cells.
052    * Protected so that subclasses can set the value after calling the
053    {@link Piece} constructor.
054    */
055   protected ArrayList<ArrayList<Position>> blockPositionByFacing;
056 
057   /**
058    * 4 facings so 4 different offsets from a given board location to
059    * place the piece there.
060    */
061   protected ArrayList<Position> initialOffsetByFacing;
062 
063   /**
064    * Construct a new {@link Piece} with the given facing and color.
065    *
066    @param  facing  initial facing; will be taken modulo 4.
067    @param  color   color of regular blocks; pivot will be darker
068    */
069   protected Piece(int facing, Color color{
070     this.rows = 5;
071     this.columns = 5;
072     setColor(color);
073     position = new Position(00);
074     this.facing = facing % 4;// make sure its safe
075     setRotationDegrees(90 this.facing);
076     blocksByFacing =
077       new ArrayList<ArrayList<ArrayList<RectangleSprite>>>();
078     // for each facing, insert an empty blocks grid
079     for (int = 0; f != 4++f{
080       blocksByFacing.add(initBlocks());
081     }
082   }
083 
084   /**
085    * Get the orientation this block would have if it were turned 90
086    * degrees anti-clockwise from the given orientation.
087    *
088    @param   orientation  starting orientation
089    *
090    @return  starting orientation one turn anti-clockwise
091    */
092   public static int turnCCW(int orientation{
093     return (orientation + 3% 4;
094   }
095 
096   /**
097    * Return the block value at the given position. Value depends on
098    * current facing of the {@link Piece}.
099    *
100    @param   row     the row (inside this piece) for which a block
101    *                  value is required.
102    @param   column  column (inside this piece) for which a block value
103    *                  is required.
104    *
105    @return  the block at that location: null if no block, {@link
106    *          RectangleSprite} reference to the block there otherwise
107    */
108   public RectangleSprite blockAt(int row, int column{
109     return getBlocks().get(row).get(column);
110   }
111 
112   /**
113    * Can the piece move down without colliding?
114    *
115    @return  true if it can; false otherwise
116    */
117   public int canMoveDown() {
118     return board.canMoveTo(this, getRow() + 1, getColumn(),
119         getFacing());
120   }
121 
122   /**
123    * Can the piece move left without colliding?
124    *
125    @return  true if it can; false otherwise
126    */
127   public int canMoveLeft() {
128     return board.canMoveTo(this, getRow(), getColumn() 1,
129         getFacing());
130   }
131 
132   /**
133    * Can the piece move right without colliding?
134    *
135    @return  true if it can; false otherwise
136    */
137   public int canMoveRight() {
138     return board.canMoveTo(this, getRow(), getColumn() + 1,
139         getFacing());
140   }
141 
142   /**
143    * Can the piece, in its current orientation, rotate anti-clockwise
144    * safely?
145    *
146    @return  true if the piece can rotate safely; false otherwise
147    */
148   public int canRotateCCW() {
149     return board.canMoveTo(this, getRow(), getColumn(),
150         turnCCW(getFacing()));
151   }
152 
153   /**
154    * Get the current column (offset from the left of the boar) in unit
155    * squares.
156    *
157    @return  current column in unit squares from the left edge of the
158    *          board
159    */
160   public int getColumn() {
161     return position.getColumn();
162   }
163 
164   /**
165    * Get the number of columns in this {@link Piece}
166    *
167    @return  the number of block columns
168    */
169   public int getColumnSize() {
170     return columns;
171   }
172 
173   /**
174    * The current facing of the {@link Piece}
175    *
176    @return  the facing
177    */
178   public int getFacing() {
179     return facing;
180   }
181 
182   /**
183    * Get the initial value for the column. Depends on shape and facing
184    * of the {@link Piece}
185    *
186    @return  initial column number in unit squares from the left
187    */
188   public int getInitialColumn() {
189     return initialOffsetByFacing.get(facing).getColumn();
190   }
191 
192   /**
193    * Get the initial value for the row. Depends on shape and facing of
194    * the {@link Piece}
195    *
196    @return  initial row number in unit squares down from top
197    */
198   public int getInitialRow() {
199     return initialOffsetByFacing.get(facing).getRow();
200   }
201 
202   /**
203    * Get the current row (offset from the top of the board) in unit
204    * squares.
205    *
206    @return  current row in unit squares down from top
207    */
208   public int getRow() {
209     return position.getRow();
210   }
211 
212   /**
213    * Get the number of rows in this {@link Piece}
214    *
215    @return  the number of block rows
216    */
217   public int getRowSize() {
218     return rows;
219   }
220 
221   /**
222    * Is the given position in the piece full in the current facing?
223    *
224    @param   row     the row (inside this piece) for which a block
225    *                  value is required.
226    @param   column  column (inside this piece) for which a block value
227    *                  is required.
228    *
229    @return  true if position is full (!empty); false otherwise
230    */
231   public boolean hasBlock(int row, int column{
232     return hasBlock(row, column, getFacing());
233   }
234 
235   /**
236    * Is the given position in the piece when in the given facing full?
237    *
238    @param   row     the row (inside this piece) for which a block
239    *                  value is required.
240    @param   column  column (inside this piece) for which a block value
241    *                  is required.
242    @param   facing  the hypothetical facing of the {@link Piece}
243    *
244    @return  true if position is full (!empty); false otherwise
245    */
246   public boolean hasBlock(int row, int column, int facing{
247     return (getBlocks(facing).get(row).get(column!= null);
248   }
249 
250   /**
251    * Move the piece down one row. NO ERROR CHECKING!
252    */
253   public void moveDown() {
254     setRow(getRow() + 1);
255   }
256 
257   /**
258    * Move the piece left one column. NO ERROR CHECKING!
259    */
260   public void moveLeft() {
261     setColumn(getColumn() 1);
262   }
263 
264   /**
265    * Move the piece right one column. NO ERROR CHECKING!
266    */
267   public void moveRight() {
268     setColumn(getColumn() + 1);
269   }
270 
271   /**
272    * Rotate the piece in the anti-clockwise direction. Updates facing
273    * and rotates the sprite. NO ERROR CHECKING!
274    */
275   public void rotateCCW() {
276     facing = turnCCW(facing);
277     rotateDegrees(-90);
278   }
279 
280   /**
281    Set the board referred to by this piece.
282    *
283    @param  board  the new {@link Board} reference
284    */
285   public void setBoard(Board board{
286     this.board = board;
287   }
288 
289   /**
290    Set the column value. ALWAYS use this method to update column.
291    *
292    @param  column  the new column value
293    */
294   public void setColumn(int column{
295     position.setColumn(column);
296     board.setPieceLocation(this);
297   }
298 
299   /**
300    Set the row value. ALWAYS use this method to update row.
301    *
302    @param  row  the new row value
303    */
304   public void setRow(int row{
305     position.setRow(row);
306     board.setPieceLocation(this);
307   }
308 
309   /**
310    * Initialize one empty grid representing this piece.
311    *
312    @return  a grid of null locations rows by columns in size
313    */
314   private ArrayList<ArrayList<RectangleSprite>> initBlocks() {
315     ArrayList<ArrayList<RectangleSprite>> grid =
316       new ArrayList<ArrayList<RectangleSprite>>();
317     for (int = 0; r != rows; ++r{
318       grid.add(initRow());
319     }
320     return grid;
321   }
322 
323   /**
324    * Initalize one empty row representing this piece
325    *
326    @return  a row of null locations columns entries long
327    */
328   private ArrayList<RectangleSprite> initRow() {
329     ArrayList<RectangleSprite> row = new ArrayList<RectangleSprite>();
330     for (int = 0; c != columns; ++c{
331       row.add(null);
332     }
333     return row;
334   }
335 
336   /**
337    * Generates the {@link RectangleSprite} objects that appear inside
338    this {@link CompositeSprite}. There are two types of blocks, BLOCK
339    * and PIVOT, each with a slightly different color. The piece is
340    * always constructed in the reference orientation, facing 0.
341    */
342   protected void generateBlocks() {
343     for (int blockNdx = 0
344          blockNdx != blockPositionByFacing.size();
345          ++blockNdx{
346       ArrayList<Position> blockPositions 
347           = blockPositionByFacing.get(blockNdx);
348 
349       // Position block # blockNdx in its 0 facing; rotate sprite
350       // for other views
351       int row = blockPositions.get(0).getRow();
352       int column = blockPositions.get(0).getColumn();
353 
354       // block at position (2, 2) is centered at location (0.0, 0.0)
355       double = (row - 2* squareEdgeSize;
356       double = (column - 2* squareEdgeSize;
357 
358       // create the block
359       RectangleSprite block 
360         = new RectangleSprite(squareEdgeSize, squareEdgeSize);
361       block.setLocation(x, y);
362       
363       // color pivot darker; pivot is center square
364       if ((row == getRowSize() 2&& (column == getColumnSize() 2)) {
365         block.setColor(getColor().darker());
366       } else {
367         block.setColor(getColor());
368       }
369       addSprite(block);
370       
371       // populate all four facings with the new block
372       for (int facingNdx = 0; facingNdx != 4++facingNdx{
373         int facingRowNdx = blockPositions.get(facingNdx).getRow();
374         int facingColNdx = blockPositions.get(facingNdx).getColumn();
375         ArrayList<ArrayList<RectangleSprite>> facingBlocks 
376             = blocksByFacing.get(facingNdx);
377         ArrayList<RectangleSprite> blocksRow = 
378           facingBlocks.get(facingRowNdx);
379         blocksRow.set(facingColNdx, block);
380       }
381     }
382   }
383 
384   /**
385    * Get the blocks grid corresponding to the current facing of the
386    {@link Piece}.
387    *
388    @return  the blocks grid (two-dimensional list of list of {@link
389    *          RectangleSprite} references)
390    */
391   private ArrayList<ArrayList<RectangleSprite>> getBlocks() {
392     return getBlocks(this.facing);
393   }
394 
395   /**
396    * Get the blocks grid corresponding to a given facing.
397    *
398    @return  the blocks grid (two-dimensional list of list of {@link
399    *          RectangleSprite} references)
400    */
401   private ArrayList<ArrayList<RectangleSprite>> getBlocks(int facing{
402     return blocksByFacing.get(facing);
403   }
404 
405   /**
406    Set the facing of the {@link Piece}protected because it is not
407    * part of the interface, just the {@link #rotateCW()} and {@link
408    * #rotateCCW()} methods are exposed.
409    *
410    @param  facing  the new facing value; well be reduced modulus 4.
411    */
412   protected void setFacing(int facing{
413     this.facing = facing % 4;
414   }
415 }
416 
417 //Uploaded on Mon Mar 29 21:40:43 EDT 2010


Download/View scg/ch13/pieces/Piece.java





Views
Personal tools
Add to 
del.icio.usAdd to 
diggAdd to 
FacebookAdd to 
favoritesAdd to 
GoogleAdd to 
MySpaceAdd to 
PrintAdd to 
SlashdotAdd to 
StumbleUponAdd to 
Twitter

Games
Games