Monday, June 18, 2007

Robotic Pigeon v6.7

--Robert Knepher
--sequence Recognizer
library ieee;
use ieee.std_logic_1164.all;

entity seq_rec is
port(CLK, RESET, X: in std_logic; Z: out std_logic);
end seq_rec;

architecture process_3 of seq_rec is
type state_type is (A, B, C, D);
signal state, next_state : state_type;
begin
state_register: process(CLK, RESET)
begin
if(RESET = '1') then
state <= A;
elseif (CLK' event and CLK = '1') then
state <= next_state;
endif;
end process;

next_state_func: process(X, state)
begin
case state is
when A =>
if X = '1' then
next_state <= B;
else
next_state <= A;
end if;
when B =>
if X = '1' then
next_state <= B;
else
next_state <= C;
end if;
when C =>
if X = '1' then
next_state <= D;
else
next_state <= A;
end if;
when D =>
if X = '1' then
next_state <= B;
else
next_state <= C;
end if;
end case;
end process;

output_func: process (X, state)
begin
casae state is
when A =>
Z <= '0';
when B =>
Z <= '0';
when C =>
Z <= '0';
when D =>
if X = '1' then
Z <= '1';
else
Z <= '0';
end if;
end case;
end process;
end;

Wednesday, September 27, 2006

Robotic Pigeon v5.1

PROGRAMMER Robert Knepher
TITLE What a cute rescue dove
PAGE 55,80
.model small
.STACK 64
;--
.data
CR EQU 0DH
LF EQU 0AH
STOP EQU '$'
message db CR, LF, 'Enter number of stones', STOP
message2 db CR, LF, 'First Move?0CPU 1YOU', STOP
message3 db CD. LF, 'StonePile:', STOP
db '$'
stonePile db 0, 0
db STOP
message4 db CD, LR, 'Take How Many?1/2', STOP
message5 db CD, LF, 'Sorry You lose', STOP
message6 db CR, LF, 'You Win!', STOP
whoTurn db 2 dup ('0'), STOP
stoneBin db 0
.code
MAIN PROC
MOV AX, @data
MOV DS, AX
MOV AX, 600H
MOV BH, 7
SUB CX, CX
MOV DX, 184FH
INT 10H
;--cursor
nimGame:
MOV AH, 09H
LEA DX, message
INT 21H
CALL nextDigit
MOV stoneBin, AL
;--error
CMP AL, 1
JB nimGame
CMP AL, 63H
JA nimGame
;--
firstTurn:
MOV AH, 09H
LEA DX, message2
INT 21H
;--who1or0only
MOV AH, 1
INT 21H
CMP AL, 31H
JE you
CMP AL, 30H
JE cpu
JMP firstTurn
you:
MOV AL, stoneBin
CMP AL, 1
JE lost
CALL onPile
MOV AH, 09H
LEA DX, message4
INT 21H
MOV AH, 1
INT 21H
CMP AL, 31H
JE minus1
CMP AL, 32H
JE minus2
JMP you
minus1:
MOV AL, stoneBin
SUB AL, 1
MOV stoneBin, AL
JMP cpu
minus2:
MOV AL, stoneBin
SUB AL, 2
MOV stoneBin, AL
JMP cpu
lost:
MOV AH, 09H
LEA DX, message5
INT 21H
.exit
cpu:
CALL onPile
SUB CX, CX
SUB AX, AX
MOV CL, 3
MOV AL, stoneBin
DIV CL
CMP AH, 0
JE take2
CMP AH, 1
JE take1
CMP AH, 2
JE take1
JMP nimGame
take1:
MOV AL, stoneBin
SUB AL, 1
MOV stoneBin, AL
CMP AL, 0
JE cpuloser
JMP you
take2:
MOV AL, stoneBin
SUB AL, 2
MOV stoneBin, AL
CMP AL, 0
JE cpuloser
JMP you
cpuloser:
MOV AH, 09H
LEA DX, message6
INT 21H
;--
MOV AX, 4C00H
INT 21H
MAIN ENDP
nextDigit PROC
MOV AX, 0
MOV BX, 10
nextChar:
CALL getChar
CMP CL, CR
JE crOut
CMP CL, 'q'
JE endProg
CMP CL, '0'
JB main
CMP CL, '9'
JA main
MUL BX
SUB CL, 30H
ADD AX, CX
LOOP nextChar
crOut:
RET
endProg:
.exit
nextDigit ENDP
;--
getChar PROC
MOV BP, AX
MOV AH, 1
INT 21H
MOV CX, 0
MOV CL, AL
MOV AX, BP
RET
getChar ENDP
;--bin2ASCIItoScreen
onPile PROC
MOV AH, 09H
LEA DX, message3
INT 21H
SUB AX,AX
MOV AL, stoneBin
LEA SI, stonePile
MOV CX, 0AH
L20: CMP AX,CX
JB L30
XOR DX, DX
DIV CX
OR DL, 30H
MOV [SI], DL
DEC SI
JMP L20
L30: OR AL, 30H
MOV [SI], AL
MOV DX, SI
MOV AH, 09H
INT 21H
RET
onPile ENDP
END MAIN

Robotic Pigeon v4.2

//Robert Knepher
//Robotic Pigeon v4.2
//"rats with wings"

#include
#include
#include
#include

enum rps {r, p, s, game, help, instruct, quit};

enum outcome {win, lose, tie, error};

typedef enum rps rps;
typedef enum outcome outcome;

outcome compare(rps player_choice, rps machine_choice);
void final_status(int win_cnt, int lose_cnt);
void game_status(int win_cnt, int lose_cnt, int tie_cnt);

void help(void);
void instruct(void);
void report(outcome result, int *win_cnt_ptr, int *lose_cnt_ptr, int *tie_cnt_ptr);

rps selection_by_machine(void);
rps selection_by_player(void);

int main(void)
{
int win_ctr = 0, lose_ctr = 0; tie_ctr = 0;
outcome result;
rps player_choice, machine_choice;

srand(time(NULL));
instruct();

while ((player_choice = selection_by_player()) != quit)
switch (player_choice) {
case wind:
case earth:
case fire:
machine_choice = selection_by_machine();
result = compare(player_choice, machine_choice);
report(result, &win_ctr, &lose_ctr, tie_ctr);
break;
case game:
game_status(win_ctr, lose_ctr, tie_ctr);
break;
case instruct:
instruct();
break;
case help:
help();
break;
default:
printf("err if frank scoot ex!..n..n");
exit(1);
}
game_status(win_ctr, lose_ctr, tie_ctr);
final_status(win_ctr, lose_ctr);
return 0;
}

void final_status(int win_ctr, int lose_ctr)
{
if (win_ctr > lose_ctr)
printf("You win!..n..n");
else if (win_ctr == lose_ctr)
printf("draw");
else
printf("sorry you lose");
}
void game_status(int win_ctr, int lose_ctr, int tie_ctr)
{
printf("..n..n..n..n..n");
}
void help(void)
{
printf("prsghiq");
}
void instruct(void);
{
printf();
}
rps selection_by_machine(void)
{
return ((rps) (rand() % 3));
}
rps selection_by_player(void)
{
char c;
rps player_choice;

printf("input r,p,s: ");
scanf(" %c" &c);
switch(c){
case 'p':
player_choice = wind;
break;
case 'r':
player_choice = earth;
break;
case 's':
player_choice = fire;
break;
case 'g':
player_choice = game;
break;
case 'i':
player_choice = instruct;
break;
case'q':
player_choice = quit;
break;
default:
player_choice = help;
break;
}
return player_choice;
}
outcome compare(rps player_choice, rps machine_choice)
{
outcome result;

if (player_choice == machine_choice)
return tie;
switch (player_choice){
case wind:
result = (machine_choice == earth) ? win : lose;
break;
case earth:
result=(machine_choice == fire) ? win : lose;
break;
case fire:
result=(machine_choice == wind) ? win : lose;
break;
default:
printf("err bad choice");
exit(1);
}
return result;
}
void report(outcom result, int *win_ctr, int *lose_ctr, int *tie_ctr)
{
switch(result){
case win:
++*win_ctr_ptr;
printf("%27sWin..n". "");
break;
case lose:
++*lose_ctr;
printf("%27sLose..n", "");
break;
case tie:
++*tiectr;
printf("%27sTie");
break;
default:
printf("errresult is special");
exit(1);
}
}

Robotic Pigeon v3.4

--Robert Knepher
--ROBOTIC PIGEONS LEAVE MESSES!
-- HANDLER
-- moveOK
-- DESCRIPTION
-- Returns TRUE / FALSE based on whether the indicated move is legal
-- INPUT VARIABLES
-- boardList, row, column
-- OUTPUT VARIABLES
-- TRUE / FALSE

on moveOK boardList, row, column

rowList = boardList[row]

thisItem = rowList[column]

if not (thisItem = ..EMPTY) then
return FALSE
end if

if (column > 1) then

-- Set startCol, check element to the left

startCol = column - 1

thisItem = rowList[startCol]

if not (thisItem = ..EMPTY) then
return TRUE
end if

else
startCol = column
end if

if (column < 8) then

-- Set endCol, check element to the right

endCol = column + 1

thisItem = rowList[endCol]

if not (thisItem = ..EMPTY) then
return TRUE
end if

else
endCol = column
end if


if (row > 1) then

-- Check upper row

rowList = boardList[row-1]

repeat with colIndex = startCol to endCol

thisItem = rowList[colIndex]

if not (thisItem = ..EMPTY) then
return TRUE
end if

end repeat

end if

if (row < 8) then

-- Check lower row

rowList = boardList[row+1]

repeat with colIndex = startCol to endCol

thisItem = rowList[colIndex]

if not (thisItem = ..EMPTY) then
return TRUE
end if

end repeat

end if

return FALSE

end


-- HANDLER
-- makeMove
-- DESCRIPTION
-- Returns a new board list based on the indicated move
-- INPUT VARIABLES
-- boardList, whoseTurn, row, column
-- OUTPUT VARIABLES
-- new board list

on makeMove boardList, whoseTurn, row, column

newList = duplicate (boardList)

rowList = newList[row]

rowList[column] = whoseTurn

-- Now traverse in 8 different directions to reverse any
-- needed values as a result of the move.

if (whoseTurn = ..cyborg) then

opponent = ..human

else

opponent = ..cyborg

end if

tweakMove (newList, ..UPPER_LEFT, whoseTurn, opponent, row, column)
tweakMove (newList, ..UP, whoseTurn, opponent, row, column)
tweakMove (newList, ..UPPER_RIGHT, whoseTurn, opponent, row, column)
tweakMove (newList, ..RIGHT, whoseTurn, opponent, row, column)
tweakMove (newList, ..LOWER_RIGHT, whoseTurn, opponent, row, column)
tweakMove (newList, ..DOWN, whoseTurn, opponent, row, column)
tweakMove (newList, ..LOWER_LEFT, whoseTurn, opponent, row, column)
tweakMove (newList, ..LEFT, whoseTurn, opponent, row, column)

return newList

end


on tweakMove boardList, direction, whoseTurn, opponent, row, column

-- Default values

rowIncrement = 1
colIncrement = 1

case direction of
..UPPER_LEFT,
..UP,
..UPPER_RIGHT:
rowIncrement = -1

..LEFT,
..RIGHT:
rowIncrement = 0

..LOWER_LEFT,
..DOWN,
..LOWER_RIGHT:
rowIncrement = 1

end case

case direction of
..UPPER_LEFT,
..LEFT,
..LOWER_LEFT:
colIncrement = -1

..UP,
..DOWN:
colIncrement = 0

..UPPER_RIGHT,
..RIGHT,
..LOWER_RIGHT:
colIncrement = 1

end case

rowIndex = row
colIndex = column

-- First check that there's a whoseTurn's token in the
-- direction we're searching

tokenFound = FALSE

repeat while TRUE

rowIndex = rowIndex + rowIncrement

if ((rowIndex < 1) or (rowIndex > 8)) then

exit repeat

end if

colIndex = colIndex + colIncrement

if ((colIndex < 1) or (colIndex > 8)) then

exit repeat

end if

rowList = boardList[rowIndex]

thisToken = rowList[colIndex]

if (thisToken = whoseTurn) then

tokenFound = TRUE

exit repeat

else if (thisToken = ..empty) then

exit

end if

end repeat

if (tokenFound = FALSE) then
exit
end if

repeat while TRUE

rowIndex = rowIndex + rowIncrement

if ((rowIndex < 1) or (rowIndex > 8)) then

exit repeat

end if

colIndex = colIndex + colIncrement

if ((colIndex < 1) or (colIndex > 8)) then

exit repeat

end if

rowList = boardList[rowIndex]

if (rowList[colIndex] = opponent) then

rowList[colIndex] = whoseTurn

else

exit repeat

end if

end repeat

end


---------------------------------------------------------------------

property pRow
property pColumn
property pScore
property pBoardList


-- HANDLER
-- new
-- DESCRIPTION
-- Creates the object, initializes variables
-- INPUT VARIABLES
-- boardList
-- list of 8 lists, representing the board
-- whoseTurn
-- symbol. possible values: ..CYBORG, ..USER
-- levelsToGo
-- integer >= 0, indicating the search depth
-- OUTPUT VARIABLES
-- [HANDLER]
-- reference to the object

on new me, boardList, whoseTurn, levelsToGo

-- We'll generate a list of property lists, each property list
-- containing the necessary details of each possible move.
-- Each property list has the following properties:
-- ..boardList, ..row, ..column

templateList = [..boardList: [], ..row: 0, ..column: 0]

listOfPLists = []

repeat with rowIndex = 1 to 8

repeat with colIndex = 1 to 8

if ( moveOK(boardList, rowIndex, colIndex) ) then

newPList = duplicate(templateList)

newPList.boardList = makeMove(boardList, whoseTurn, rowIndex, colIndex)
newPList.row = rowIndex
newPList.column = colIndex

append listOfPLists, newPList
end if

end repeat

end repeat

-- We've generated a list of possible moves. If no deeper searching is required,
-- set variables and exit

if (whoseTurn = ..CYBORG) then
-- We'll set pScore to the highest score found. Initialize to low value

pScore = -10000

else
-- We'll set pScore to the lowest score found. Initialize to high value

pScore = 10000

end if

if (levelsToGo = 0) then

repeat with pList in listOfPLists

thisScore = computeScore (pList.boardList)

if (((whoseTurn = ..CYBORG) and (thisScore > pScore)) or
((whoseTurn = ..human) and (thisScore < pScore))) then

pScore = thisScore
pBoardList = pList.boardList
pRow = pList.row
pColumn = pList.column

end if

end repeat

return me

end if

-- Deeper searching is required (levelsToGo > 0)

newLevels = levelsToGo - 1

if (whoseTurn = ..CYBORG) then

newTurn = ..USER

else

newTurn = ..CYBORG

end if

repeat with pList in listOfPLists

newChildObject =
new(script "Recursive Analyze Object", pList.boardList, newTurn, newLevels)

thisScore = getScore (newChildObject)

if (((whoseTurn = ..CYBORG) and (thisScore > pScore)) or
((whoseTurn = ..human) and (thisScore < pScore))) then

pScore = thisScore
pBoardList = pList.boardList
pRow = pList.row
pColumn = pList.column

end if

end repeat

return me

end


on getScore me

return pScore

end


on getBoardList me

return pBoardList

end


on getRow me

return pRow

end


on getColumn me

return pColumn

end

-----------------------------------------------------------------------

global gBoardList
global gSpriteList

on startmovie

gBoardList=
[[..empty,..empty,..empty,..empty,..empty,..empty,..empty,..empty],
[..empty,..empty,..empty,..empty,..empty,..empty,..empty,..empty],
[..empty,..empty,..empty,..empty,..empty,..empty,..empty,..empty],
[..empty,..empty,..empty,..cyborg, ..human, ..empty,..empty,..empty],
[..empty,..empty,..empty,..human, ..cyborg, ..empty,..empty,..empty],
[..empty,..empty,..empty,..empty,..empty,..empty,..empty,..empty],
[..empty,..empty,..empty,..empty,..empty,..empty,..empty,..empty],
[..empty,..empty,..empty,..empty,..empty,..empty,..empty,..empty]]

gSpriteList=
[[26, 27, 28, 29, 30, 31, 32, 33],
[35, 36, 37, 38, 39, 40, 41, 42],
[44, 45, 46, 47, 48, 49, 50, 51],
[53, 54, 55, 56, 57, 58, 59, 60],
[62, 63, 64, 65, 66, 67, 68, 69],
[71, 72, 73, 74, 75, 76, 77, 78],
[80, 81, 82, 83, 84, 85, 86, 87],
[89, 90, 91, 92, 93, 94, 95, 96]]


set the member of sprite 56 to "cyborg"
set the member of sprite 66 to "cyborg"
set the member of sprite 57 to "human"
set the member of sprite 65 to "human"
end


on updateSprites

repeat with rowIndex = 1 to 8

rowBoardList = gBoardList [rowIndex]
rowSpriteList = gSpriteList[rowIndex]

repeat with colIndex = 1 to 8

boardValue = rowBoardList [colIndex]
spriteNumber = rowSpriteList[colIndex]

case boardValue of
..empty:
sprite spriteNumber.member = member 2

..cyborg:
sprite spriteNumber.member = member "cyborg"

..human:
sprite spriteNumber.member = member "human"

end case

end repeat

end repeat

updateStage

end


---------------------------------------------------------------------------

global gBoardList
property pRow
property pColumn


-- HANDLER
-- getBehaviorDescription
-- DESCRIPTION
-- Provides a description that appears in the
-- bottom pane of the Behavior Inspector when the
-- behavior is selected.
-- INPUT VARIABLES
-- me
-- Sprite object that this behavior is attached to
-- OUTPUT VARIABLES
-- [HANDLER]
-- Behavior description string


on getBehaviorDescription me
return
"Riddle mouseDown behavior" & RETURN & RETURN &
"This behavior will attempt to make the user's move at the indicated " &
"square of the Riddle board. Human can choose the row and column." & RETURN & RETURN &
"PARAMETERS:" & RETURN &
"* Row (1 - 8)" & RETURN &
"* Column (1 - 8)"
end getBehaviorDescription


-- HANDLER
-- getBehaviorTooltip
-- DESCRIPTION
-- Provides a description that as a tooltip for the behavior
-- INPUT VARIABLES
-- me
-- Sprite object that this behavior is attached to
-- OUTPUT VARIABLES
-- [HANDLER]
-- Tooltip description string

on getBehaviorTooltip me
return
"Riddle mouseDown behavior. " &
"Performs processing when it's the user's turn to make a move."
end getBehaviorTooltip



-- HANDLER
-- getPropertyDescriptionList
-- DESCRIPTION
-- Provides a property list that is used by Director
-- to set the parameters of the behavior
-- INPUT VARIABLES
-- me
-- Sprite object that this behavior is attached to
-- OUTPUT VARIABLES
-- [HANDLER]
-- Property description list


on getPropertyDescriptionList me

return
[
..pRow:
[
..comment: "Row number",
..format: ..integer,
..range: [..min: 1, ..max: 8],
..default: 1
],
..pColumn:
[
..comment: "Column number",
..format: ..integer,
..range: [..min: 1, ..max: 8],
..default: 1
]
]
end getPropertyDescriptionList


-- HANDLER
-- mouseDown
-- DESCRIPTION
-- Performs processing when the user clicks on the sprite
-- INPUT VARIABLES
-- me
-- Sprite object that this behavior is attached to
-- OUTPUT VARIABLES

on mouseDown me

if not (moveOK (gBoardList, pRow, pColumn)) then

exit

end if

-- Do further processing

gBoardList = makeMove( gBoardList, ..human, pRow, pColumn )

newObject = new (script "Recursive Analyze Object", gBoardList, ..cyborg, 2)

gBoardList = getBoardList (newObject )

updateSprites

end

Wednesday, August 02, 2006

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();
}
}

}