Robotic Pigeon v2.3
/*Robert Knepher
*
*/
package robotrobot;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Enumeration;
import java.util.Random;
import java.util.Vector;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class RobotBoard extends JPanel
implements KeyListener
{
private static final long serialVersionUID = 1L;
public static final int NUMBER_OF_COLUMNS = 6;
public static final int NUMBER_OF_ROWS = 12;
RobotFrame robotFrame;
/**
* Indicates whether we are displaying the active pair of descending
* RobotIcons.
*/
boolean displayingActivePair = false;
public static final int UPDATES_BETWEEN_NEW_PAIR = 3;
/**
* Acts to create a pause between activePairs.
*/
int updateCounter = 0;
RobotPair activePair;
RobotPair onDeckPair;
RobotIcon[][] iconArray = new RobotIcon[NUMBER_OF_COLUMNS][NUMBER_OF_ROWS];
/** Creates a new instance of RobotBoard */
public RobotBoard( RobotFrame parentFrame )
{
robotFrame = parentFrame;
setSize(new Dimension(192, 384));
setBackground(Color.white);
for(int x = 0; x < NUMBER_OF_COLUMNS; x++)
{
for(int y = 0; y < NUMBER_OF_ROWS; y++)
{
iconArray[x][y] = new RobotIcon(x, y, RobotIcon.TYPE_BLANK, this);
}
}
}
public Vector
findHorizontalBasedMatch()
{
Vector vector = new Vector();
int typeToMatch;
int thisType;
int matches = 0;
int x;
int y;
int subX;
for (y = NUMBER_OF_ROWS-1; y >= 0; y--)
{
// Reset at the beginning of each row
typeToMatch = RobotIcon.TYPE_BLANK;
for (x = 0; x < NUMBER_OF_COLUMNS; x++)
{
if (typeToMatch == RobotIcon.TYPE_BLANK)
{
// Traverse to the 1st non-blank icon.
typeToMatch = iconArray[x][y].getType();
if (typeToMatch != RobotIcon.TYPE_BLANK)
{
matches = 1;
}
continue;
}
// typeToMatch != TYPE_BLANK, matches < 3
thisType = iconArray[x][y].getType();
if (thisType != typeToMatch)
{
typeToMatch = thisType;
if (typeToMatch != RobotIcon.TYPE_BLANK)
{
matches = 1;
}
continue;
}
else
{
matches++;
}
if (matches != 3)
{
continue;
}
// We have found 3 in a row horizontally. Try to find the additional
// icon to have a "MATCH!"
// Try 4 in a row
if (x < NUMBER_OF_COLUMNS-1)
{
thisType = iconArray[x+1][y].getType();
if (thisType == typeToMatch)
{
// We've found 4 in a row.
vector.add( iconArray[x-2][y] );
vector.add( iconArray[x-1][y] );
vector.add( iconArray[x ][y] );
vector.add( iconArray[x+1][y] );
return vector;
}
}
// Try L upper left, T upper, and L upper right
if (y > 0)
{
for (subX = x-2; subX <= x; subX++)
{
thisType = iconArray[subX][y-1].getType();
if (thisType == typeToMatch)
{
// We've found a T or an L.
vector.add( iconArray[x-2][y] );
vector.add( iconArray[x-1][y] );
vector.add( iconArray[x ][y] );
vector.add( iconArray[subX][y-1] );
return vector;
}
}
}
// Try L lower left, T lower, and L lower right
if (y < NUMBER_OF_ROWS-1)
{
for (subX = x-2; subX <= x; subX++)
{
thisType = iconArray[subX][y+1].getType();
if (thisType == typeToMatch)
{
// We've found a T or an L.
vector.add( iconArray[x-2][y] );
vector.add( iconArray[x-1][y] );
vector.add( iconArray[x ][y] );
vector.add( iconArray[subX][y+1] );
return vector;
}
}
}
// 3 in a row, but no matches
typeToMatch = RobotIcon.TYPE_BLANK;
} // for x... (end of row)
} // for y... (end of board
return null;
}
public Vector
findVerticalBasedMatch()
{
Vector vector = new Vector();
int typeToMatch;
int thisType;
int matches = 0;
int x;
int y;
int subY;
for (x = NUMBER_OF_COLUMNS-1; x >= 0; x--)
//for (x = 0; x <= NUMBER_OF_COLUMNS-1; x++)
{
// Reset at the beginning of each column
typeToMatch = RobotIcon.TYPE_BLANK;
for (y = 0; y < NUMBER_OF_ROWS; y++)
{
if (typeToMatch == RobotIcon.TYPE_BLANK)
{
// Traverse to the 1st non-blank icon.
typeToMatch = iconArray[x][y].getType();
if (typeToMatch != RobotIcon.TYPE_BLANK)
{
matches = 1;
}
continue;
}
// typeToMatch != TYPE_BLANK, matches < 3
thisType = iconArray[x][y].getType();
if (thisType != typeToMatch)
{
typeToMatch = thisType;
if (typeToMatch != RobotIcon.TYPE_BLANK)
{
matches = 1;
}
continue;
}
else
{
matches++;
}
if (matches != 3)
{
continue;
}
// We have found 3 in a row VERTICALLY. Try to find the additional
// icon to have a "MATCH!"
// Try 4 in a row
if (y < NUMBER_OF_ROWS-1)
{
thisType = iconArray[x][y+1].getType();
if (thisType == typeToMatch)
{
// We've found 4 in a row.
vector.add( iconArray[x][y-2] );
vector.add( iconArray[x][y-1] );
vector.add( iconArray[x ][y] );
vector.add( iconArray[x][y+1] );
return vector;
}
}
// Try L upper left, T left, and L lower left
if (x > 0) //y>0
{
for (subY = y-2; subY <= y; subY++)
{
thisType = iconArray[x-1][subY].getType();
if (thisType == typeToMatch)
{
// We've found a T or an L.
vector.add( iconArray[x][y-2] );
vector.add( iconArray[x][y-1] );
vector.add( iconArray[x][y] );
vector.add( iconArray[x-1][subY] );
return vector;
}
}
}
// Try L upper right, T right, and L lower right
if (x < NUMBER_OF_COLUMNS-1)
{
for (subY = y-2; subY <= y; subY++)
{
thisType = iconArray[x+1][subY].getType();
if (thisType == typeToMatch)
{
// We've found a T or an L.
vector.add( iconArray[x][y-2] );
vector.add( iconArray[x][y-1] );
vector.add( iconArray[x ][y] );
vector.add( iconArray[x+1][subY] );
return vector;
}
}
}
// 3 in a row, but no matches
typeToMatch = RobotIcon.TYPE_BLANK;
} // for x... (end of row)
} // for y... (end of board
return null;
}
public Vector
findMatch()
{
Vector returnValue = findHorizontalBasedMatch();
if (returnValue == null)
{
returnValue = findVerticalBasedMatch();
}
return returnValue;
}
/*
* KeyListener Method
*/
public void
keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
switch(keyCode)
{
case KeyEvent.VK_UP:
case KeyEvent.VK_KP_UP:
rotateCounterClockwise();
break;
case KeyEvent.VK_DOWN:
case KeyEvent.VK_KP_DOWN:
rotateClockwise();
break;
case KeyEvent.VK_LEFT:
case KeyEvent.VK_KP_LEFT:
moveLeft();
break;
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_KP_RIGHT:
moveRight();
break;
default:
break;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
RobotIcon icon;
for(int x = 0; x < 6; x++)
{
for(int y = 0; y < 12; y++)
{
icon = iconArray[x][y];
icon.paintBoard(g);
}
}
}
/**
* This method creates a new random RobotPair.
*/
RobotPair
createNewRobotPair()
{
Random random = new Random();
int x1 = random.nextInt( NUMBER_OF_COLUMNS-1 );
int x2 = x1 + 1;
int type1 = random.nextInt( RobotIcon.TYPE_BLANK );
int type2 = random.nextInt( RobotIcon.TYPE_BLANK );
RobotIcon firstIcon = new RobotIcon( x1, 0, type1, this );
RobotIcon secondIcon = new RobotIcon( x2, 0, type2, this );
RobotPair returnValue = new RobotPair( firstIcon, secondIcon );
return returnValue;
}
private void
moveLeft()
{
if (!displayingActivePair)
{
// nothing to do
return;
}
int minX = activePair.getMinX();
if (minX == 0)
{
// Pair is as far to the left as it can go.
return;
}
// if orientation is ORIENTATION_HORIZONTAL
// minY and maxY should be the same.
int minY = activePair.getMinY();
int maxY = activePair.getMaxY();
int typeMinY = iconArray[minX-1][minY].getType();
int typeMaxY = iconArray[minX-1][maxY].getType();
if ( (typeMinY != RobotIcon.TYPE_BLANK) ||
(typeMaxY != RobotIcon.TYPE_BLANK) )
{
// There is a non-blank RobotIcon in the way. Can't move.
return;
}
int type1 = activePair.getFirstType();
int type2 = activePair.getSecondType();
int orientation = activePair.getOrientation();
switch (orientation)
{
case RobotPair.ORIENTATION_HORIZONTAL:
{
// minY should be equal to maxY
// Before:
// | | A | B |
//
// After:
// | A | B | |
//
iconArray[minX-1][minY].setType(type1);
iconArray[minX] [minY].setType(type2);
iconArray[minX+1][minY].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon (iconArray[minX-1][minY]);
activePair.setSecondIcon(iconArray[minX] [minY]);
activePair.update();
repaint();
break;
}
case RobotPair.ORIENTATION_VERTICAL:
{
// maxX (no variable) should be equal to minX
// Before:
// | | A |
// | | B |
//
// After:
// | A | |
// | B | |
//
iconArray[minX-1][minY].setType(type1);
iconArray[minX-1][maxY].setType(type2);
iconArray[minX] [minY].setType(RobotIcon.TYPE_BLANK);
iconArray[minX] [maxY].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon (iconArray[minX-1][minY]);
activePair.setSecondIcon(iconArray[minX-1][maxY]);
activePair.update();
repaint();
}
break;
}
}
private void
moveRight()
{
if (!displayingActivePair)
{
// nothing to do
return;
}
int maxX = activePair.getMaxX();
if (maxX == NUMBER_OF_COLUMNS-1)
{
// Pair is as far to the right as it can go.
return;
}
// if orientation is ORIENTATION_HORIZONTAL
// minY and maxY should be the same.
int minY = activePair.getMinY();
int maxY = activePair.getMaxY();
int typeMinY = iconArray[maxX+1][minY].getType();
int typeMaxY = iconArray[maxX+1][maxY].getType();
if ( (typeMinY != RobotIcon.TYPE_BLANK) ||
(typeMaxY != RobotIcon.TYPE_BLANK) )
{
// There is a non-blank RobotIcon in the way. Can't move.
return;
}
int type1 = activePair.getFirstType();
int type2 = activePair.getSecondType();
int orientation = activePair.getOrientation();
switch (orientation)
{
case RobotPair.ORIENTATION_HORIZONTAL:
{
// minY should be equal to maxY
// Before:
// | A | B | |
//
// After:
// | | A | B |
//
iconArray[maxX+1][minY].setType(type2);
iconArray[maxX] [minY].setType(type1);
iconArray[maxX-1][minY].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon (iconArray[maxX][minY]);
activePair.setSecondIcon(iconArray[maxX+1][minY]);
activePair.update();
repaint();
break;
}
case RobotPair.ORIENTATION_VERTICAL:
{
// minX (no variable) should be equal to maxX
// Before:
// | A | |
// | B | |
//
// After:
// | | A |
// | | B |
//
iconArray[maxX+1][minY].setType(type1);
iconArray[maxX+1][maxY].setType(type2);
iconArray[maxX] [minY].setType(RobotIcon.TYPE_BLANK);
iconArray[maxX] [maxY].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon (iconArray[maxX+1][minY]);
activePair.setSecondIcon(iconArray[maxX+1][maxY]);
activePair.update();
repaint();
}
break;
}
}
private void
rotateCounterClockwise()
{
if (!displayingActivePair)
{
// nothing to do
return;
}
int orientation = activePair.getOrientation();
int minX = activePair.getMinX();
int maxX = activePair.getMaxX();
int minY = activePair.getMinY();
int maxY = activePair.getMaxY();
int type1 = activePair.getFirstType();
int type2 = activePair.getSecondType();
int type;
// Assume orientation != ORIENTATION_ERROR
if (orientation == RobotPair.ORIENTATION_HORIZONTAL)
{
// maxY should be equal to minY
// Before:
// | A | B |
// | | |
//
// After:
// | B | |
// | A | |
//
if (maxY == (NUMBER_OF_ROWS-1))
{
// There's not room to rotate counter-clockwise.
return;
}
type = iconArray[minX][maxY+1].getType();
if (type != RobotIcon.TYPE_BLANK)
{
// There is a non-blank RobotIcon in the way. Can't move.
return;
}
// Let's do it. activePair will become VERTICAL
iconArray[minX][maxY+1].setType(type1);
iconArray[minX][maxY] .setType(type2);
iconArray[maxX][maxY] .setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon (iconArray[minX][maxY]);
activePair.setSecondIcon(iconArray[minX][maxY+1]);
activePair.update();
repaint();
return;
}
if (orientation == RobotPair.ORIENTATION_VERTICAL)
{
// maxX should be equal to minX
// Before:
// | A | |
// | B | |
//
// After:
// | A | B |
// | | |
//
if (maxX == (NUMBER_OF_COLUMNS-1))
{
// There's not room to rotate counter-clockwise.
return;
}
type = iconArray[maxX+1][minY].getType();
if (type != RobotIcon.TYPE_BLANK)
{
// There is a non-blank RobotIcon in the way. Can't move.
return;
}
// Let's do it. activePair will become HORIZONTAL
// Note: firstIcon stays put.
iconArray[maxX+1][minY].setType(type2);
iconArray[maxX] [maxY].setType(RobotIcon.TYPE_BLANK);
activePair.setSecondIcon(iconArray[maxX+1][minY]);
activePair.update();
repaint();
return;
}
}
private void
rotateClockwise()
{
if (!displayingActivePair)
{
// nothing to do
return;
}
int orientation = activePair.getOrientation();
int minX = activePair.getMinX();
int maxX = activePair.getMaxX();
int minY = activePair.getMinY();
int maxY = activePair.getMaxY();
int type1 = activePair.getFirstType();
int type2 = activePair.getSecondType();
int type;
if (orientation == RobotPair.ORIENTATION_HORIZONTAL)
{
// maxY should be equal to minY
// Before:
// | A | B |
// | | |
//
// After:
// | A | |
// | B | |
//
if (maxY == (NUMBER_OF_ROWS-1))
{
// There's not room to rotate counter-clockwise.
return;
}
type = iconArray[minX][maxY+1].getType();
if (type != RobotIcon.TYPE_BLANK)
{
// There is a non-blank RobotIcon in the way. Can't move.
return;
}
// Let's do it. activePair will become VERTICAL
// Note: firstIcon stays put.
iconArray[minX][maxY+1].setType(type2);
iconArray[maxX][maxY] .setType(RobotIcon.TYPE_BLANK);
activePair.setSecondIcon(iconArray[minX][maxY+1]);
activePair.update();
repaint();
return;
}
if (orientation == RobotPair.ORIENTATION_VERTICAL)
{
// maxX should be equal to minX
// Before:
// | A | |
// | B | |
//
// After:
// | B | A |
// | | |
//
if (maxX == (NUMBER_OF_COLUMNS-1))
{
// There's not room to rotate counter-clockwise.
return;
}
type = iconArray[maxX+1][minY].getType();
if (type != RobotIcon.TYPE_BLANK)
{
// There is a non-blank RobotIcon in the way. Can't move.
return;
}
// Let's do it. activePair will become HORIZONTAL
iconArray[minX] [minY].setType(type2);
iconArray[minX+1][minY].setType(type1);
iconArray[minX] [maxY].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon (iconArray[minX] [minY]);
activePair.setSecondIcon(iconArray[minX+1][minY]);
activePair.update();
repaint();
return;
}
}
/*
* This method is called periodically by RobotThread.run().
*
*/
public void
update()
{
int minX;
int maxX;
int maxY;
int orientation;
int type1;
int type2;
// System.out.println("RobotBoard.update()");
RobotPreview robotPreview = robotFrame.getRobotPreview();
if (onDeckPair == null)
{
onDeckPair = createNewRobotPair();
robotPreview.setRobotPair( onDeckPair );
}
if (!displayingActivePair)
{
updateCounter++;
if (updateCounter < UPDATES_BETWEEN_NEW_PAIR)
{
// We're resting before the next pair.
return;
}
// Rest is over - time to display activePair and update onDecPair.
displayingActivePair = true;
activePair = onDeckPair;
onDeckPair = createNewRobotPair();
robotPreview.setRobotPair( onDeckPair );
minX = activePair.getMinX();
type1 = iconArray[minX][0].getType();
type2 = iconArray[minX+1][0].getType();
if ( (type1 != RobotIcon.TYPE_BLANK) ||
(type2 != RobotIcon.TYPE_BLANK) )
{
// No room for new pair. Game over.
gameOver();
return;
}
type1 = activePair.getFirstType();
type2 = activePair.getSecondType();
iconArray[minX] [0].setType( type1 );
iconArray[minX+1][0].setType( type2 );
// Replacing RobotIcons in activePair with RobotIcons in iconArray.
// Current pair in activePair will be garbage collected.
activePair.setFirstIcon ( iconArray[minX] [0] );
activePair.setSecondIcon( iconArray[minX+1][0] );
activePair.update();
repaint();
return;
}
// Lower activePair. If activePair can't be lowered, check for matches.
maxY = activePair.getMaxY();
if (maxY == NUMBER_OF_ROWS-1)
{
// Can't move, check for matches, finish processing.
checkForMatches();
return;
}
orientation = activePair.getOrientation();
if (orientation == RobotPair.ORIENTATION_HORIZONTAL)
{
// Check icons below.
minX = activePair.getMinX();
type1 = iconArray[minX] [maxY+1].getType();
type2 = iconArray[minX+1][maxY+1].getType();
if ( type1 == RobotIcon.TYPE_BLANK )
{
if ( type2 == RobotIcon.TYPE_BLANK )
{
// Both RobotIcons below are blank. OK to lower pair.
// Before:
// | A | B |
// | | |
//
// After:
// | | |
// | A | B |
//
iconArray[minX] [maxY+1].setType(activePair.getFirstType());
iconArray[minX+1][maxY+1].setType(activePair.getSecondType());
iconArray[minX] [maxY ].setType(RobotIcon.TYPE_BLANK);
iconArray[minX+1][maxY ].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon ( iconArray[minX] [maxY+1] );
activePair.setSecondIcon( iconArray[minX+1][maxY+1] );
activePair.update();
repaint();
}
else
{
// Can move first RobotIcon, can't move second RobotIcon.
// orientation will become ORIENTATION_BLOCKED.
// Before:
// | A | B |
// | | |
//
// After:
// | | B |
// | A | |
//
iconArray[minX] [maxY+1].setType(activePair.getFirstType());
iconArray[minX] [maxY ].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon ( iconArray[minX] [maxY+1] );
activePair.update();
repaint();
}
}
else
{
if ( type2 == RobotIcon.TYPE_BLANK )
{
// Can't move first RobotIcon, can move second RobotIcon.
// orientation will become ORIENTATION_BLOCKED.
// Before:
// | A | B |
// | | |
//
// After:
// | A | |
// | | B |
//
iconArray[minX+1][maxY+1].setType(activePair.getSecondType());
iconArray[minX+1][maxY ].setType(RobotIcon.TYPE_BLANK);
activePair.setSecondIcon( iconArray[minX+1][maxY+1] );
activePair.update();
repaint();
}
else
{
// Can't move either RobotIcon. Check for matches, finish processing.
checkForMatches();
}
}
} // if (orientation == RobotPair.ORIENTATION_HORIZONTAL)
else
if (orientation == RobotPair.ORIENTATION_VERTICAL)
{
// Check icon below.
minX = activePair.getMinX();
type2 = iconArray[minX][maxY+1].getType();
if (type2 == RobotIcon.TYPE_BLANK)
{
// There's a blank icon below.
// Before:
// | A |
// | B |
// | |
//
// After:
// | |
// | A |
// | B |
//
iconArray[minX][maxY+1].setType(activePair.getSecondType());
iconArray[minX][maxY ].setType(activePair.getFirstType());
iconArray[minX][maxY-1].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon ( iconArray[minX][maxY] );
activePair.setSecondIcon( iconArray[minX][maxY+1] );
activePair.update();
repaint();
}
else
{
// Can't move. Check for matches, finish processing.
checkForMatches();
}
} // if (orientation == RobotPair.ORIENTATION_VERTICAL)
else
if (orientation == RobotPair.ORIENTATION_BLOCKED)
{
// orientation was ORIENTATION_HORIZONTAL, but now one of the
// RobotIcons are blocked, so only one can descend.
int blockStatus = activePair.getBlockStatus();
if (blockStatus == RobotPair.FIRST_ICON_BLOCKED)
{
// Only the 2nd RobotIcon can be lowered.
maxX = activePair.getMaxX();
type2 = iconArray[maxX][maxY+1].getType();
if (type2 == RobotIcon.TYPE_BLANK)
{
// There's a blank icon below.
// Before:
// | A | |
// | * | B |
// | | |
//
// After:
// | A | |
// | * | |
// | | B |
//
iconArray[maxX][maxY+1].setType(activePair.getSecondType());
iconArray[maxX][maxY ].setType(RobotIcon.TYPE_BLANK);
activePair.setSecondIcon( iconArray[maxX][maxY+1] );
activePair.update();
repaint();
}
else
{
// Can't move. Check for matches, finish processing.
checkForMatches();
}
} // if (blockStatus == RobotPair.FIRST_ICON_BLOCKED)
else
if (blockStatus == RobotPair.SECOND_ICON_BLOCKED)
{
// Only the 1st RobotIcon can be lowered.
minX = activePair.getMinX();
type1 = iconArray[minX][maxY+1].getType();
if (type1 == RobotIcon.TYPE_BLANK)
{
// There's a blank icon below.
// Before:
// | | B |
// | A | * |
// | | |
//
// After:
// | | B |
// | | * |
// | A | |
//
iconArray[minX][maxY+1].setType(activePair.getFirstType());
iconArray[minX][maxY ].setType(RobotIcon.TYPE_BLANK);
activePair.setFirstIcon( iconArray[minX][maxY+1] );
activePair.update();
repaint();
}
else
{
// Can't move. Check for matches, finish processing.
checkForMatches();
}
} // if (blockStatus == RobotPair.SECOND_ICON_BLOCKED)
} // if (orientation == RobotPair.ORIENTATION_BLOCKED)
}
void
gameOver()
{
int playAgainOption = JOptionPane.NO_OPTION;
// Reset variables.
displayingActivePair = false;
updateCounter = 0;
System.out.println("Game Over");
RobotThread robotThread = robotFrame.getRobotThread();
robotThread.pauseThread();
playAgainOption =
JOptionPane.
showConfirmDialog( this,
"Play again?",
"Game Over",
JOptionPane.YES_NO_OPTION );
if (playAgainOption == JOptionPane.NO_OPTION)
{
System.exit(0);
}
for(int x = 0; x < NUMBER_OF_COLUMNS; x++)
{
for(int y = 0; y < NUMBER_OF_ROWS; y++)
{
iconArray[x][y].setType( RobotIcon.TYPE_BLANK );
}
}
repaint();
robotThread.resumeThread();
}
/**
* This method is called when the current active pair of RobotIcons can
* descend no lower. It resets variables so that a new active pair will
* appear. It also checks for matches. If so, it updates the board.
*/
void
checkForMatches()
{
RobotIcon tempIcon;
Vector matches;
int firstBlankIndex;
int totalBlanks;
int type;
// Reset variables.
displayingActivePair = false;
updateCounter = 0;
matches = findMatch();
if (matches == null)
{
// Finished processing.
return;
}
// Retrieve the RobotIcon elements, set their type to BLANK, then
// update iconArray, moving elements down as need be.
Enumeration enumeration = matches.elements();
while (enumeration.hasMoreElements())
{
tempIcon = (RobotIcon) enumeration.nextElement();
tempIcon.setType( RobotIcon.TYPE_BLANK );
}
// Update iconArray.
for (int col = 0; col < NUMBER_OF_COLUMNS; col++)
{
// Reset the blank count for this row.
firstBlankIndex = -1;
totalBlanks = 0;
for (int row = NUMBER_OF_ROWS-1; row >= 0; row--)
{
// Travel up the column, looking for blanks below a non-blank.
type = iconArray[col][row].getType();
if (type == RobotIcon.TYPE_BLANK)
{
if (totalBlanks == 0)
{
// This is the first blank we've come to.
firstBlankIndex = row;
}
totalBlanks++;
}
else
{
// This icon is a non-blank.
if (totalBlanks == 0)
{
// No problem. All icons below are non-blank
continue;
}
// We have found a non-blank icon, with blank icons below.
// First lower the icons.
for (int i = firstBlankIndex; i >= totalBlanks; i--)
{
iconArray[col][i].setType( iconArray[col][i-totalBlanks].getType());
}
// Make the top icons of the column blank
for (int i = 0; i < totalBlanks; i++)
{
iconArray[col][i].setType( RobotIcon.TYPE_BLANK);
}
// We're done with this column.
break;
}
} // for (int row...)
} // for (int col...)
repaint();
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
}
package robotrobot;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* Robert Knepher
*
*/
public class RobotFrame extends JFrame
{
/**
*
*/
private static final long serialVersionUID = -7091286611323587347L;
private JPanel contentPane;
private JPanel jPanelMain = new JPanel();
private BorderLayout borderLayoutContent = new BorderLayout();
private JPanel jPanelInstructions = new JPanel();
private JPanel jPanelPreview = new JPanel();
private JPanel jPanelBoard = new JPanel();
private JLabel jLabelInstructions = new JLabel();
private BorderLayout borderLayoutBoard = new BorderLayout();
private BorderLayout borderLayoutPreview = new BorderLayout();
RobotBoard robotBoard;
RobotPreview robotPreview;
RobotThread robotThread;
//Construct the frame
public RobotFrame()
{
// System.out.println("RobotFrame.RobotFrame()");
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
}
// Component initialization
private void jbInit() throws Exception
{
robotBoard = new RobotBoard( this );
robotPreview = new RobotPreview( this );
// robotThread = new RobotThread( RobotThread.DEFAULT_INTERVAL, robotBoard );
robotThread = new RobotThread( 500, robotBoard );
robotThread.startThread();
addKeyListener( robotBoard );
//setIconImage(Toolkit.getDefaultToolkit().createImage(OverlayFrame.class.getResource("[Your Icon]")));
contentPane = (JPanel) this.getContentPane();
this.setSize(new Dimension(232, 442)); //226 416
this.setTitle("The Game of RobotRobot");
this.setResizable(false);
contentPane.setLayout(borderLayoutContent);
jPanelMain.setLayout(null);
jPanelInstructions.setBounds(new Rectangle(0, 0, 226, 32));
jPanelPreview.setBackground(Color.white);
jPanelPreview.setBounds(new Rectangle(0, 32, 34, 410));
jPanelPreview.setLayout(borderLayoutPreview);
jPanelPreview.add(robotPreview, BorderLayout.CENTER);
jPanelBoard.setBackground(Color.white);
jPanelBoard.setBounds(new Rectangle(34, 32, 198, 410));
jPanelBoard.setLayout(borderLayoutBoard);
jPanelBoard.add(robotBoard, BorderLayout.CENTER);
jLabelInstructions.setFont(new java.awt.Font("Dialog", 1, 14));
jLabelInstructions.setText("Please use arrow keys");
contentPane.add(jPanelMain, BorderLayout.CENTER);
jPanelMain.add(jPanelInstructions, null);
jPanelInstructions.add(jLabelInstructions, null);
jPanelMain.add(jPanelPreview, null);
jPanelMain.add(jPanelBoard, null);
}
public RobotBoard
getRobotBoard()
{
return robotBoard;
}
public RobotPreview
getRobotPreview()
{
return robotPreview;
}
public RobotThread
getRobotThread()
{
return robotThread;
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e)
{
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING)
{
System.exit(0);
}
}
}
/*
* RobotGuiApp.java
*
* Created on March 13, 2006, 10:52 PM
*
* Robert Knepher
*
*/
package robotrobot;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
/**
*
*/
public class RobotGuiApp
{
private boolean packFrame = false;
private RobotFrame robotFrame;
/** Creates a new instance of RobotGuiApp */
public RobotGuiApp()
{
JFrame.setDefaultLookAndFeelDecorated(true);
robotFrame = new RobotFrame();
JFrame frame = robotFrame;
//Validate frames that have preset sizes
//Pack frames that have useful preferred size info, e.g. from their layout
if (packFrame)
{
frame.pack();
}
else
{
frame.validate();
}
//Center the window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height)
{
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width)
{
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public RobotFrame
getRobotFrame()
{
return robotFrame;
}
// Main method
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e)
{
e.printStackTrace();
}
RobotGuiApp robotGuiApp = new RobotGuiApp();
// Give time to initialize.
try
{
Thread.sleep(1000);
}
catch (InterruptedException ie)
{
}
RobotFrame frame = robotGuiApp.getRobotFrame();
RobotBoard robotBoard = frame.getRobotBoard();
Vector vector = robotBoard.findMatch();
if (vector != null)
{
System.out.println("Found a match!!");
System.out.println("Coordinates are: ");
Enumeration enumeration = vector.elements();
while (enumeration.hasMoreElements())
{
RobotIcon icon = (RobotIcon) enumeration.nextElement();
System.out.println( "x = " + icon.getXOffset() + ", " +
"y = " + icon.getYOffset() );
}
}
}
}
/**
* Robert Knepher
*
*/
package robotrobot;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.ImageIcon;
/**
*
*
*/
public class RobotIcon
{
public static final int IMAGE_WIDTH = 32;
public static final int IMAGE_HEIGHT = 32;
boolean useBlankIcon = true;
public static final int TYPE_RED = 0;
public static final int TYPE_GREEN = 1;
public static final int TYPE_BLUE = 2;
public static final int TYPE_YELLOW = 3;
public static final int TYPE_BLANK = 4;
private static final ImageIcon robotRed = new ImageIcon("images/robot_red.png");
private static final ImageIcon robotGreen = new ImageIcon("images/robot_green.png");
private static final ImageIcon robotBlue = new ImageIcon("images/robot_blue.png");
private static final ImageIcon robotYellow = new ImageIcon("images/robot_yellow.png");
private static final ImageIcon robotBlank = new ImageIcon("images/robot_blank.png");
/**
* contains the X location of the icon ( 0 to 5 ) in the parent robotBoard
*/
int xOffset = 0;
/**
* contains the Y location of the icon ( 0 to 11 ) in the parent robotBoard
*/
int yOffset = 0;
/**
* contains the type of the icon ( TYPE_RED, TYPE_GREEN, etc. )
*/
int type = 0;
/**
* contains the ImageIcon used by paint()
*/
ImageIcon imageIcon = null;
/**
* contains the parent RobotBoard
*/
RobotBoard robotBoard;
/**
* Creates a new instance of RobotIcon
*/
public RobotIcon( int inputX,
int inputY,
int inputType,
RobotBoard inputBoard )
{
xOffset = inputX;
yOffset = inputY;
type = inputType;
robotBoard = inputBoard;
imageIcon = getImageIcon( type );
}
public int
getXOffset()
{
return xOffset;
}
public int
getYOffset()
{
return yOffset;
}
public int
getType()
{
return type;
}
/**
* Sets the X offset. Probably will never call.
*/
public void
setXOffset( int inputX )
{
xOffset = inputX;
}
/**
* Sets the Y offset. Probably will never call.
*/
public void
setYOffset( int inputY )
{
yOffset = inputY;
}
public ImageIcon
getImageIcon(int type)
{
switch(type){
case TYPE_RED:
return robotRed;
case TYPE_GREEN:
return robotGreen;
case TYPE_BLUE:
return robotBlue;
case TYPE_YELLOW:
return robotYellow;
case TYPE_BLANK:
return robotBlank;
default:
return null;
}
}
public void
setType(int inputType)
{
//update both RobotIcon.type and RobotIcon.imageIcon
type = inputType;
imageIcon = getImageIcon( type );
}
// Called by:
// RobotBoard.paintComponent()
public void
paintBoard( Graphics g )
{
// System.out.println("RobotIcon[" + xOffset + "," + yOffset + "].paint()");
if ((type == TYPE_BLANK) && (!useBlankIcon))
{
g.clearRect( (xOffset * IMAGE_WIDTH),
(yOffset * IMAGE_HEIGHT),
IMAGE_WIDTH,
IMAGE_HEIGHT );
}
else
{
imageIcon.paintIcon( (Component) robotBoard,
g,
(xOffset * IMAGE_WIDTH),
(yOffset * IMAGE_HEIGHT) );
}
}
// Called by:
// RobotPreview.paintComponent()
public void
paintPreview( Graphics g,
Component robotPreview,
int x,
int y )
{
// System.out.println("RobotIcon.paintPreview()");
if ((type == TYPE_BLANK) && (!useBlankIcon))
{
g.clearRect( x,
y,
IMAGE_WIDTH,
IMAGE_HEIGHT );
}
else
{
imageIcon.paintIcon( robotPreview,
g,
x,
y );
}
}
}
/**
* Robert Knepher
*
*/
package robotrobot;
/**
* A RobotPair holds a pair of RobotIcons. When the RobotPair is first created,
* the RobotIcons that it holds are not elements of RobotBoard.iconArray
. Once the RobotPair is displayed (and descending) on the screen,
*
* it is updated via the set() methods, and its elements are elements of
* RobotBoard.iconArray
. There is minimal error checking on the
* elements. If the RobotIcons are horizontally side-by-side, we count on the
* programmer to always place the first RobotIcon on the left. If the RobotIcons
* are vertically on top of one another, we count on the programmer to always
* place the first RobotIcon above the second.
*/
public class RobotPair
{
private RobotIcon firstIcon;
private RobotIcon secondIcon;
/**
* Indicates whether one of the RobotIcons is "blocked". This can only occur
* if the icons were previously oriented horizontally. The blocked RobotIcon
* is directly above a non-blank RobotIcon (not a member of this pair),
* and therefore cannot descend any further.
*/
private int blockStatus = NO_ICONS_BLOCKED;
// Values of blockStatus
/**
* Indicates the first RobotIcon is "blocked" (cannot descend further).
*/
public static final int FIRST_ICON_BLOCKED = 1;
/**
* Indicates the second RobotIcon is "blocked" (cannot descend further).
*/
public static final int SECOND_ICON_BLOCKED = 2;
/**
* Indicates neither RobotIcon is "blocked" (both can descend further).
*/
public static final int NO_ICONS_BLOCKED = 3;
private int orientation;
// Values of orientation
/**
* Indicates the first icon is left of the second.
*/
public static final int ORIENTATION_HORIZONTAL = 1;
/**
* Indicates the first icon is above the the second.
*/
public static final int ORIENTATION_VERTICAL = 2;
/**
* Indicates the first icon is left of the second, and one of the icons
* is blocked (cannot descend further).
*/
public static final int ORIENTATION_BLOCKED = 3;
/**
* Indicates there is an error in the orientation of the RobotIcons.
* (They are not in the same column or adjacent columns).
*/
public static final int ORIENTATION_ERROR = 4;
private int minX;
private int maxX;
private int minY;
private int maxY;
// Values of orientation
public RobotPair( RobotIcon icon1, RobotIcon icon2 )
{
firstIcon = icon1;
secondIcon = icon2;
update();
}
public void
setFirstIcon( RobotIcon inputIcon )
{
if (inputIcon == null)
{
return;
}
firstIcon = inputIcon;
}
public RobotIcon
getFirstIcon()
{
return firstIcon;
}
public int
getFirstType()
{
return firstIcon.getType();
}
public int
getFirstX()
{
return firstIcon.getXOffset();
}
public int
getFirstY()
{
return firstIcon.getYOffset();
}
public void
setSecondIcon( RobotIcon inputIcon )
{
if (inputIcon == null)
{
return;
}
secondIcon = inputIcon;
}
public RobotIcon
getSecondIcon()
{
return secondIcon;
}
public int
getSecondType()
{
return secondIcon.getType();
}
public int
getSecondX()
{
return secondIcon.getXOffset();
}
public int
getSecondY()
{
return secondIcon.getYOffset();
}
public int
getMinX()
{
return minX;
}
public int
getMaxX()
{
return maxX;
}
public int
getMinY()
{
return minY;
}
public int
getMaxY()
{
return maxY;
}
public int
getBlockStatus()
{
return blockStatus;
}
public int
getOrientation()
{
return orientation;
}
public void
update()
{
boolean switchIcons = false;
int x1 = getFirstX();
int y1 = getFirstY();
int x2 = getSecondX();
int y2 = getSecondY();
if (x1 < x2)
{
minX = x1;
maxX = x2;
orientation = ORIENTATION_HORIZONTAL;
}
else if (x1 > x2 )
{
minX = x2;
maxX = x1;
orientation = ORIENTATION_HORIZONTAL;
switchIcons = true;
}
else if (y1 < y2)
{
// x1 == x2
minY = y1;
maxY = y2;
orientation = ORIENTATION_VERTICAL;
}
else if (y1 > y2)
{
// x1 == x2
minY = y2;
maxY = y1;
orientation = ORIENTATION_VERTICAL;
switchIcons = true;
}
else
{
// x1 == x2
// y1 == y2
minX = maxX = x1;
minY = maxY = y1;
orientation = ORIENTATION_ERROR;
}
switch (orientation)
{
case ORIENTATION_HORIZONTAL:
{
// minX, maxX set, set minY, maxY
if (y1 < y2)
{
// x1 != x2: must be blocked.
minY = y1;
maxY = y2;
orientation = ORIENTATION_BLOCKED;
}
else if (y1 > y2)
{
// x1 != x2: must be blocked.
minY = y2;
maxY = y1;
orientation = ORIENTATION_BLOCKED;
}
else
{
// x1 != x2: still horizontal.
minY = maxY = y1;
}
if ((maxX-minX) > 1)
{
// Can't have RobotIcons apart by more than one column.
orientation = ORIENTATION_ERROR;
}
break;
}
case ORIENTATION_VERTICAL:
{
// minY, maxY set, set minX, maxX
minX = maxX = x1;
if ( (maxY - minY) > 1 )
{
// Can't have vertical RobotIcons that are not adjacent.
orientation = ORIENTATION_ERROR;
}
break;
}
} // switch
if (switchIcons)
{
// Switch icons to either keep 1st left of 2nd or 1st above 2nd.
RobotIcon tempIcon;
tempIcon = firstIcon;
firstIcon = secondIcon;
secondIcon = tempIcon;
}
if (orientation == ORIENTATION_BLOCKED)
{
// RobotIcons could have been switched. Reset y1, y2.
y1 = getFirstY();
y2 = getSecondY();
if (y1 < y2)
{
// secondIcon kept descending, firstIcon is blocked.
blockStatus = FIRST_ICON_BLOCKED;
}
else
{
// firstIcon kept descending, secondIcon is blocked.
blockStatus = SECOND_ICON_BLOCKED;
}
}
if (orientation == ORIENTATION_ERROR)
{
printError( x1, y1, x2, y2 );
}
}
void
printError( int x1,
int y1,
int x2,
int y2 )
{
System.err.println( "RobotPair: (" + x1 + ", " + y1 + "), (" +
x2 + ", " + y2 + ")" );
}
}
/**
* Robert Knepher
*
*/
package robotrobot;
import java.awt.*;
import javax.swing.JPanel;
public class RobotPreview extends JPanel
{
RobotFrame robotFrame;
RobotPair robotPair;
/** Creates a new instance of RobotPreview */
public RobotPreview( RobotFrame parentFrame )
{
robotFrame = parentFrame;
setSize(new Dimension(34, 384));
setBackground(Color.white);
}
public void
setRobotPair( RobotPair inputPair )
{
// System.out.println("RobotPreview.setRobotPair()");
robotPair = inputPair;
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(33, 0, 33, 383);
if (robotPair != null )
{
RobotIcon icon = robotPair.getFirstIcon();
// System.out.println("first icon type = " + icon.getType());
icon.paintPreview( g, this, 0, 0 );
icon = robotPair.getSecondIcon();
// System.out.println("second icon type = " + icon.getType());
icon.paintPreview( g, this, 0, RobotIcon.IMAGE_HEIGHT );
}
}
}
/**
* Robert Knepher
*
*/
package robotrobot;
public class RobotThread
extends Thread
{
/**
* b_keepRunning
* boolean variable. Set this to false to safely stop the Thread.
* Set by:
* stopThread()
* Set and Used by:
* run()
*/
private boolean b_keepRunning = true;
public static final long DEFAULT_INTERVAL = 1000;
long sleepInterval;
RobotBoard robotBoard;
/*
* The following constants are possible values of threadState
*/
public static final int STATE_NOT_STARTED = 0;
public static final int STATE_RUNNING = 1;
public static final int STATE_PAUSED = 2;
public static final int STATE_STOPPED = 3;
/**
* Indicates the state of the Thread.
*/
private int threadState = STATE_NOT_STARTED;
public RobotThread( long interval,
RobotBoard inputBoard )
{
sleepInterval = interval;
robotBoard = inputBoard;
}
public void
setInterval( long interval )
{
sleepInterval = interval;
}
public void run()
{
while (b_keepRunning)
{
// System.out.println("RobotThread.run()");
try
{
if (threadState == STATE_PAUSED)
{
// pauseThread() has been called.
synchronized (this)
{
while (threadState == STATE_PAUSED)
{
wait();
}
// resumeThread() has been called.
}
}
if (!b_keepRunning)
{
// stopThread() has been called
break;
}
robotBoard.update();
sleep(sleepInterval);
}
catch (InterruptedException e)
{
}
}
threadState = STATE_STOPPED;
}
/**
* Starts the Thread
*/
public synchronized void
startThread()
{
if (threadState == STATE_NOT_STARTED)
{
threadState = STATE_RUNNING;
start();
}
}
/**
* Stops the Thread. The specific Thread cannot be restarted.
*/
public synchronized void
stopThread()
{
b_keepRunning = false;
if (threadState == STATE_PAUSED)
{
resumeThread();
}
}
/**
* Pauses the Thread
*/
public synchronized void
pauseThread()
{
if (threadState == STATE_RUNNING) {
threadState = STATE_PAUSED;
}
}
/**
* Resumes the Thread after a pause.
*/
public synchronized void
resumeThread()
{
if (threadState == STATE_PAUSED) {
threadState = STATE_RUNNING;
notify();
}
}
}
0 Comments:
Post a Comment
<< Home