package piece;
import java.awt.*;
import java.util.*;
import board.Tile;
import org.apache.log4j.Logger;
/**
* Abstract class Piece - Any 4-tile game piece
*
* @author Paul Tanenbaum
* @version 0.1 (24 September 2010)
*/
public abstract class Piece
{
// Instance variables
protected int rotation; // Current rotational state
protected Location anchor; // World coords of anchor square
protected Point[] tiles;
// Class variables
protected static Class<?>[] shapeTypes;
private static Random randomStream = // For which subtype to produce
new Random(Calendar.getInstance().getTimeInMillis());
protected static Logger logger = Logger.getLogger(Piece.class);
/**
* Constructs and initializes a piece at (x, y)
*
* @param x x-coord of piece
* @param y y-coord of piece
* @throws IndexOutOfBoundsException
*
* TODO Ensure SOMEBODY checks validity of coords
*/
public Piece (int x, int y)
{
if ((y >= Integer.MAX_VALUE) || (x >= Integer.MAX_VALUE) ||
(y < 0) || (x < 0)) {
throw new IndexOutOfBoundsException(
"Attempt to create piece at (" + x + ", " + y +
") beyond board's limits");
}
rotation = 0;
anchor = new Location(x, y);
tiles = new Point[4];
}
/**
* Constructs and initializes a piece at the origin
*/
public Piece ()
{
this(0, 0);
}
/**
* Produces a new Piece of which the subtype is selected at random
* from among all the known shape types.
*
* @param x
* @param y
* @return the new Piece of randomly-selected subtype
*/
public static Piece randomPiece(int x, int y) {
int i = randomStream.nextInt(Piece.shapeTypes.length);
Piece piece = null;
try {
piece = (Piece) Piece.shapeTypes[i].newInstance();
piece.anchor.setLocation(x, y);
} catch (Exception e) {
logger.fatal("Could not construct a " + Piece.shapeTypes[i]);
}
return piece;
}
public static Piece randomPiece() {
return randomPiece(0, 0);
}
/*
* Initialize some class variables
*/
static {
shapeTypes = new Class<?>[2];
shapeTypes[0] = new Eye().getClass();
shapeTypes[1] = new Square().getClass();
}
public abstract int getOrder();
public Location[] getShape() {
throw new IllegalStateException("Piece.getShape() should have been overriden");
}
public ArrayList<Location> getLocalRotSweep(RotationSense s) {
throw new IllegalStateException("Piece.getLocalRotSweep() should have been overriden");
}
public ArrayList<Location> getLocalStepSweep(LocalDirection d) {
throw new IllegalStateException("Piece.getLocalStepSweep() should have been overriden");
}
/**
* Access this piece's anchor
*/
public Location getAnchor()
{
return anchor;
}
/**
* Specifies the net number of counterclockwise 90-degree rotations experienced
* @param rot Number of rotations
*/
public void setRotation (int rot) {
rotation = rot % getOrder();
}
/**
* Is this piece in a location where it's free to rotate?
*
* @return whether the piece can rotate
*/
public boolean canRotate(RotationSense r) {
Iterator<Location> iter = getRotSweep(r).iterator();
Boolean answer = true;
System.out.println(getClass() + ".canRotate()...");
while (iter.hasNext()) {
Point sweepPoint = (Point) iter.next();
int row = (int) (getAnchor().getY() + sweepPoint.getY());
int col = (int) (getAnchor().getX() + sweepPoint.getX());
System.out.println(" Checking sweep point (" + row + ", " + col + ")");
//Cell cell = board.getCell(row, col);
//if (! cell.isEmpty()) {
//return false;
//}
}
return true;
}
/**
* Rotate this piece 90 degrees
*
* @return whether the rotation succeeded
*/
public boolean rotate(RotationSense r)
{
Iterator<Location> iter = getLocalRotSweep(r).iterator();
switch (r) {
case CLOCKWISE:
rotation = (rotation - 1) % getOrder();
break;
case COUNTERCLOCKWISE:
rotation = (rotation + 1) % getOrder();
break;
}
System.out.println(this.getClass() + ".rotate()...");
System.out.println(" anchor is " + anchor + ", rotation becomes " + rotation);
System.out.printf(" shape will become {");
for (int i = 0; i < 3; ++i) {
Location worldOffset = getShape()[i].rotate(rotation);
Location currentLocation = new Location();
currentLocation.setLocation(anchor);
currentLocation.translate((int) worldOffset.getX(), (int) worldOffset.getY());
System.out.printf(currentLocation.toString());
if (i < 2) {
System.out.printf(", ");
} else {
System.out.printf("\n");
}
}
while (iter.hasNext()) {
Location localOffset = (Location) iter.next();
Location worldOffset = localOffset.rotate(rotation);
Location currentLocation = new Location();
currentLocation.setLocation(this.anchor);
currentLocation.translate((int) worldOffset.getX(), (int) worldOffset.getY());
System.out.println(" Now processing local offset of " + localOffset);
System.out.println(" " + anchor + " + " + worldOffset + " = " + currentLocation);
}
// Highly complicated logic
return true;
}
/**
* List all the cells that would be swept by a 90-degree rotation
*
* @param s The sense of the rotation
* @return The list of the cells swept
*/
public ArrayList<Location> getRotSweep(RotationSense s) {
Iterator<Location> iter = getLocalRotSweep(s).iterator();
ArrayList<Location> rs = new ArrayList<Location>();
System.out.println(getShapeTypeName() + ".getRotSweep(" + s + ") for rotation = " + rotation);
while (iter.hasNext()) {
Location sweepPointLocal = (Location) iter.next();
Location sweepPointGlobal = sweepPointLocal.rotate(rotation);
sweepPointGlobal.translate((int) anchor.getX(), (int) anchor.getY());
rs.add(sweepPointGlobal);
System.out.println(" " + sweepPointLocal + " transforms to " + sweepPointGlobal);
}
return (rs);
}
/**
* List all the cells that would be swept by a one-cell step
*
* @param d The direction of the step
* @return The list of the cells swept
*/
public ArrayList<Location> getStepSweep(LocalDirection d) {
Iterator<Location> iter = getLocalStepSweep(d).iterator();
ArrayList<Location> ss = new ArrayList<Location>();
System.out.println(getShapeTypeName() + ".getStepSweep(" + d.getName() + ") for rotation = " + rotation);
while (iter.hasNext()) {
Location sweepPointLocal = (Location) iter.next();
Location sweepPointGlobal = sweepPointLocal.rotate(rotation);
sweepPointGlobal.translate((int) anchor.getX(), (int) anchor.getY());
ss.add(sweepPointGlobal);
System.out.println(" " + sweepPointLocal + " transforms to " + sweepPointGlobal);
}
return (ss);
}
/**
* List all the cells currently occupied by the Piece
*
* @return The list of the cells occupied
*/
public Location[] getFootprint() {
Location[] shape = new Location[3];
Location[] footprint = new Location[4];
Location pointLocal;
int i;
System.out.println(getShapeTypeName() + ".getFootprint()...");
// Store the anchor in footprint[0]
footprint[0] = new Location(anchor);
System.out.println(" anchor = " + anchor + " transforms to " + footprint[0]);
// Transform the rest of the Piece and store result in footprint[1 .. 3]
shape = getShape();
for (i = 0; i < 3; ++i) {
pointLocal = new Location(shape[i]);
footprint[i + 1] = new Location(pointLocal.rotate(rotation));
footprint[i + 1].translate((int) anchor.getX(), (int) anchor.getY());
System.out.println(" shape[" + i + "] transforms to " + footprint[i + 1]);
}
return footprint;
}
/**
* Break the Piece up into its constituent Tiles
*
* @return The array of Tiles
*/
public Tile[] dissolve() {
Tile[] result = new Tile[4];
Location[] footprint = getFootprint();
System.out.print(getShapeTypeName() + " dissolves into");
for (int i = 0; i < footprint.length; ++i) {
result[i] = new Tile(footprint[i]);
System.out.print(" " + result[i]);
}
System.out.println();
return result;
}
public boolean stepDown() {
return true;
}
public void showQuadrant(int quadNumber) {
if (quadNumber < 0 || quadNumber > 3) {
System.out.println("Invalid quadrant number: " + quadNumber);
} else {
int xSign = quadNumber * (quadNumber - 3) + 1;
int ySign = (int) Math.signum(3/2 - quadNumber);
System.out.println("Quadrant " + quadNumber + " yields coords (" + xSign + ", " + ySign + ")");
}
}
public String toString()
{
return getClass().getName() + ": " + tiles[0].toString()
+ ' ' + tiles[1].toString()
+ ' ' + tiles[2].toString()
+ ' ' + tiles[3].toString();
}
protected String getShapeTypeName() {
return getClass().toString().replaceFirst("class piece.", "");
}
/**
* Dump a pretty-printed summary of this Piece
*/
public void prettyPrint()
{
int i;
Iterator<Location> iter;
// Header line
System.out.println(getShapeTypeName() + " {");
// The order member
System.out.println(" order = " + getOrder());
// The rotation member
System.out.println(" rotation = " + rotation);
// The anchor member
System.out.println(" anchor = " + anchor);
// The shape member
System.out.print(" shape = {");
for (i = 0; i < getShape().length; ++i) {
System.out.print(getShape()[i]);
if (i < getShape().length - 1) {
System.out.print(", ");
}
}
System.out.println("}");
// The rotSweep member
for (RotationSense r : RotationSense.values()) {
iter = getLocalRotSweep(r).iterator();
System.out.print(" " + r.getName() + " rotSweep = {");
while (iter.hasNext()) {
System.out.print(iter.next());
if (iter.hasNext()) {
System.out.print(", ");
} else {
System.out.println("}");
}
}
}
// The stepSweep member
for (LocalDirection ld : LocalDirection.values()) {
iter = getLocalStepSweep(ld).iterator();
System.out.print(" " + ld.getName() + " stepSweep = {");
while (iter.hasNext()) {
System.out.print(iter.next());
if (iter.hasNext()) {
System.out.print(", ");
} else {
System.out.println("}");
}
}
}
System.out.println("}");
}
/**
*
*/
public void exploreShapeTypes() {
System.out.println("----------");
System.out.println("exploreShapeTypes() finds these shape types...");
for (int i = 0; i < Piece.shapeTypes.length; ++i) {
Piece piece;
try {
piece = (Piece) Piece.shapeTypes[i].newInstance();
piece.prettyPrint();
} catch (Exception e) {
}
}
System.out.println("----------");
}
/**
*
*/
public void exploreRotSweep(Piece piece, int rot) {
piece.setRotation(rot);
getRotSweep(RotationSense.COUNTERCLOCKWISE);
}
/**
*
*/
public void exploreStepSweep(Piece piece, int rot) {
piece.setRotation(rot);
getStepSweep(LocalDirection.YNEG);
}
}