//
import java.awt.*;
public class test extends BufferedApplet
{
// DATA FIELDS IN EACH TILE
final int TYPE = 0;
final int STATE = 1;
final int BUG = 2;
// TYPES OF TILES
final int NIL = 0;
final int NW = 1;
final int SW = 2;
final int SE = 3;
final int NE = 4;
final int AND = 5;
final int OR = 6;
final int NTYPES = 7;
// STATES OF LOGIC TILES
final int N = 1;
final int S = 2;
final int E = 3;
final int W = 4;
final int P = 5;
final int NSTATES = 6;
// BUG DIRECTIONS
final int BN = 1;
final int BW = 2;
final int BS = 4;
final int BE = 8;
int w = 0, h = 0, ni, nj;
Color buttonColor = new Color(255,200,160);
Color feltColor = new Color(90,130,90);
Color tileColor = new Color(190,150,115);
Color bugColor = tileColor.brighter();
int tiles[][][], newTiles[][][];
int mx, my;
Rectangle stepRect, runRect;
double startTime = 0;
public boolean keyUp(Event e, int key) {
int i = x2i(mx);
int j = y2j(my);
int tile[] = tiles[i][j];
int ANDStates[] = {E,W,P}, ORStates[] = {N,S,P};
switch (key) {
case '\u03EC': tile[BUG] = BN; break; // UP ARROW
case '\u03ED': tile[BUG] = BS; break; // DOWN ARROW
case '\u03EE': tile[BUG] = BW; break; // LEFT ARROW
case '\u03EF': tile[BUG] = BE; break; // RIGHT ARROW
case 127 : tile[BUG] = 0; break; // DELETE
case '|' : tile[TYPE] = OR ; tile[STATE] = 0; break;
case '-' : tile[TYPE] = AND; tile[STATE] = 0; break;
case ' ' : tile[TYPE] = tile[STATE] = 0; break;
case '?':
for (i = 0 ; i < ni ; i++)
for (j = 0 ; j < nj ; j++) {
tile = tiles[i][j];
tile[TYPE] = tile[STATE] = tile[BUG] = 0;
if ((i+j) % 2 == 0) {
tile[TYPE] = AND + random(2);
tile[STATE] = (tile[TYPE]==AND ? ANDStates : ORStates)[random(3)];
tile[BUG] = 0;
}
if (tile[TYPE] == 0 && (i+j) % 2 == 0)
tile[TYPE] = 1 + random(4);
if (tile[TYPE] == 0)
tile[BUG] = 1 + random(4);
}
break;
}
damage = true;
return true;
}
java.util.Random R = new java.util.Random();
int random(int n) { return Math.abs(R.nextInt()) % n; }
public boolean mouseMove(Event e, int x, int y) {
mx = x;
my = y;
return true;
}
final int STEP = 0;
final int RUN = 1;
final int TILES = 2;
final int DOWN = 3;
final int UP = 4;
int mouseState = UP;
boolean isRunning = false;
public boolean mouseDown(Event e, int x, int y) {
if (stepRect.inside(x,y))
mouseState = STEP;
else if (runRect.inside(x,y))
mouseState = RUN;
else if (x < h)
mouseState = TILES;
else
mouseState = DOWN;
damage = true;
return true;
}
public boolean mouseUp(Event e, int x, int y) {
switch (mouseState) {
case STEP:
isRunning = false;
step();
break;
case RUN:
isRunning = ! isRunning;
break;
case TILES:
int i = x2i(x);
int j = y2j(y);
int type = tiles[i][j][TYPE];
switch (type) {
case NIL: type = NE ; break;
case NE : type = SE ; break;
case SE : type = SW ; break;
case SW : type = NW ; break;
default : type = NIL; break;
}
tiles[i][j][TYPE] = type;
break;
}
damage = true;
mouseState = UP;
return true;
}
void step() {
// IF BUG IS ON A NEGATION, THEN TURN IT 90 DEGREES
for (int i = 0 ; i < ni ; i++)
for (int j = 0 ; j < nj ; j++) {
int tile[] = tiles[i][j];
int bug = tile[BUG];
if (bug != 0) {
switch (tile[TYPE]) {
case NW: if ((bug&BS)!=0) {bug&=~BS;bug|=BW;} if ((bug&BE)!=0) {bug&=~BE;bug|=BN;} break;
case NE: if ((bug&BS)!=0) {bug&=~BS;bug|=BE;} if ((bug&BW)!=0) {bug&=~BW;bug|=BN;} break;
case SW: if ((bug&BN)!=0) {bug&=~BN;bug|=BW;} if ((bug&BE)!=0) {bug&=~BE;bug|=BS;} break;
case SE: if ((bug&BN)!=0) {bug&=~BN;bug|=BE;} if ((bug&BW)!=0) {bug&=~BW;bug|=BS;} break;
}
tile[BUG] = bug;
}
}
for (int i = 0 ; i < ni ; i++)
for (int j = 0 ; j < nj ; j++) {
newTiles[i][j][TYPE ] = tiles[i][j][TYPE];
newTiles[i][j][STATE] = tiles[i][j][STATE];
newTiles[i][j][BUG ] = tiles[i][j][BUG];
}
// MOVE BUG TO THE NEXT TILE OVER
for (int i = 0 ; i < ni ; i++)
for (int j = 0 ; j < nj ; j++) {
int tile[] = tiles[i][j];
int newTile[] = newTiles[i][j];
int bug = tile[BUG];
if ((bug&BN)!=0) {newTile[BUG] &= ~BN; setBug(i,j-1, BN);}
if ((bug&BS)!=0) {newTile[BUG] &= ~BS; setBug(i,j+1, BS);}
if ((bug&BW)!=0) {newTile[BUG] &= ~BW; setBug(i-1,j, BW);}
if ((bug&BE)!=0) {newTile[BUG] &= ~BE; setBug(i+1,j, BE);}
}
for (int i = 0 ; i < ni ; i++)
for (int j = 0 ; j < nj ; j++) {
tiles[i][j][STATE] = newTiles[i][j][STATE];
tiles[i][j][BUG ] = newTiles[i][j][BUG ];
}
}
void setBug(int i, int j, int bug) {
i = (i + ni) % ni;
j = (j + nj) % nj;
int tile[] = newTiles[i][j];
int state = tile[STATE];
bug = tile[BUG] | bug;
switch (tile[TYPE]) {
case OR:
switch (state) {
case 0:
switch (bug) {
case BN: state = N; bug = 0; break;
case BS: state = S; bug = 0; break;
case BE: state = P; bug = 0; break;
case BW: state = P; bug = 0; break;
case BN|BE: case BN|BW: case BS|BE: case BS|BW: bug = BN|BS; break;
case BN|BS|BE: case BN|BE|BW: state = N; bug = BN|BS; break;
case BN|BS|BW: case BS|BE|BW: state = S; bug = BN|BS; break;
}
break;
case N:
case S:
if (bug != 0 && bug != (BN|BS|BE|BW))
state = 0;
switch (bug) {
case BN: case BS: case BE: case BW: bug = BN|BS; break;
case BN|BS: case BN|BE: case BS|BE: bug = BN|BS|BE; break;
case BE|BW: case BN|BW: case BS|BW: bug = BN|BS|BW; break;
case BN|BS|BE: case BN|BS|BW: case BN|BE|BW: case BS|BE|BW: bug = BN|BS|BE|BW; break;
}
break;
case P:
if (bug != 0 && bug != (BN|BS|BE|BW))
state = 0;
switch (bug) {
case BN: case BS: bug = BN|BS; break;
case BE: case BW: bug = BE|BW; break;
case BN|BS: case BN|BE: case BS|BE: bug = BN|BS|BE; break;
case BN|BW: case BS|BW: bug = BN|BS|BW; break;
case BE|BW: bug = BE|BW|BN; break;
case BN|BS|BE: case BN|BS|BW: case BN|BE|BW: case BS|BE|BW: bug = BN|BS|BE|BW; break;
}
break;
}
break;
case AND:
switch (state) {
case 0:
switch (bug) {
case BN: case BS: state = P; bug = 0; break;
case BE: state = E; bug = 0; break;
case BW: state = W; bug = 0; break;
}
break;
case P:
switch (bug) {
case BN: case BS: state = 0; bug = BN|BS; break;
case BE: case BW: state = 0; bug = BE|BW; break;
}
break;
case E:
case W:
switch (bug) {
case BN: case BS:
case BE: case BW: state = 0; bug = BE|BW; break;
}
break;
}
break;
// IF ANOTHER BUG IS ALSO COMING IN, SQUEEZE THEM BOTH INTO THIS TILE
default:
switch (tile[BUG]) {
case BE: switch (bug) { case BW: bug = BE|BW; break; case BN: bug = BN|BE; break; case BS: bug = BS|BE; break; }
case BW: switch (bug) { case BE: bug = BE|BW; break; case BN: bug = BN|BW; break; case BS: bug = BS|BW; break; }
case BN: switch (bug) { case BS: bug = BN|BS; break; case BE: bug = BN|BE; break; case BW: bug = BN|BW; break; }
case BS: switch (bug) { case BN: bug = BN|BS; break; case BE: bug = BS|BE; break; case BW: bug = BS|BW; break; }
}
break;
}
tile[STATE] = state;
tile[BUG] = bug;
}
int clicks = 0;
public void render(Graphics g) {
if (w == 0) {
w = bounds().width;
h = bounds().height;
ni = h/32;
nj = h/32;
tiles = new int[ni][nj][3];
newTiles = new int[ni][nj][3];
stepRect = new Rectangle(w - 16 - 40, 16, 40, 20);
runRect = new Rectangle(stepRect.x, stepRect.y + stepRect.height + 16, stepRect.width, stepRect.height);
}
if (isRunning) {
double time = System.currentTimeMillis() / 1000.;
if (startTime == 0)
startTime = time;
int newClicks = (int)(4 * (time - startTime));
if (newClicks > clicks) {
step();
clicks = newClicks;
}
}
g.setColor(feltColor);
g.fillRect(0,0,w,h);
g.setColor(buttonColor);
g.fill3DRect(stepRect.x, stepRect.y, stepRect.width, stepRect.height, mouseState != STEP);
g.setColor(Color.black);
g.drawString("STEP", stepRect.x + 4, stepRect.y + 15);
g.setColor(buttonColor);
g.fill3DRect(runRect.x, runRect.y, runRect.width, runRect.height, mouseState != RUN);
g.setColor(Color.black);
g.drawString(isRunning ? "STOP" : "RUN", runRect.x + 4, runRect.y + 15);
g.setColor(Color.black);
for (int i = 0 ; i <= ni ; i++)
g.drawLine(i2x(i)-16,0,i2x(i)-16,h);
for (int j = 0 ; j <= nj ; j++)
g.drawLine(0,j2y(j)-16,h,j2y(j)-16);
for (int i = 0 ; i < ni ; i++)
for (int j = 0 ; j < nj ; j++) {
int tile[] = tiles[i][j];
int type = tile[TYPE];
int state = tile[STATE];
int bug = tile[BUG];
drawTile(g, type, state, i2x(i), j2y(j));
switch (type) {
case NW: if (bug==BS) bug = BS|BW; else if (bug==BE) bug = BN|BE; break;
case NE: if (bug==BS) bug = BS|BE; else if (bug==BW) bug = BN|BW; break;
case SW: if (bug==BN) bug = BN|BW; else if (bug==BE) bug = BS|BE; break;
case SE: if (bug==BN) bug = BN|BE; else if (bug==BW) bug = BS|BW; break;
}
drawBug(g, bug, i2x(i), j2y(j));
}
animating = isRunning;
}
int i2x(int i) { return 16 + 32 * i; }
int j2y(int j) { return 16 + 32 * j; }
int x2i(int x) { return x / 32; }
int y2j(int y) { return y / 32; }
void drawTile(Graphics g, int type, int state, int x, int y) {
g.setColor(tileColor.darker());
g.fillRect(x - 13, y - 13, 29, 29);
g.setColor(tileColor.brighter());
g.fillRect(x - 15, y - 15, 30, 30);
g.setColor(tileColor);
g.fillRect(x - 14, y - 14, 29, 29);
g.setColor(Color.black);
switch (type) {
case NE: g.fillRect(x-5,y+2, 8,3); g.fillRect(x-5,y-3, 3,8); break;
case NW: g.fillRect(x-3,y+2, 8,3); g.fillRect(x+2,y-3, 3,8); break;
case SE: g.fillRect(x-5,y-5, 8,3); g.fillRect(x-5,y-5, 3,8); break;
case SW: g.fillRect(x-3,y-5, 8,3); g.fillRect(x+2,y-5, 3,8); break;
case AND:
switch (state) {
case 0: g.fillRect(x-7,y-1,15,3); break;
case E: drawTriangle(g,x-7,y-7,x-7,y+7,x+7,y); break;
case W: drawTriangle(g,x+7,y-7,x+7,y+7,x-7,y); break;
case P: g.drawLine(x-4,y,x+4,y); break;
}
break;
case OR:
switch (state) {
case 0: g.fillRect(x-1,y-7,3,15); break;
case S: drawTriangle(g,x-7,y-7,x+7,y-7,x,y+7); break;
case N: drawTriangle(g,x-7,y+7,x+7,y+7,x,y-7); break;
case P: g.drawLine(x,y-4,x,y+4); break;
}
break;
}
}
void drawTriangle(Graphics g, int ax,int ay,int bx,int by,int cx,int cy) {
int X[] = {ax,bx,cx}, Y[] = {ay,by,cy};
g.drawPolygon(X,Y,3);
}
void drawBug(Graphics g, int bug, int x, int y) {
switch (bug) {
case BE|BW|BN:
case BN: drawBug(g,x-8,y+9,x+8,y+9,x,y-9); break;
case BE|BW|BS:
case BS: drawBug(g,x-8,y-9,x+8,y-9,x,y+9); break;
case BN|BS|BE:
case BE: drawBug(g,x-9,y-8,x-9,y+8,x+9,y); break;
case BN|BS|BW:
case BW: drawBug(g,x+9,y-8,x+9,y+8,x-9,y); break;
case BN|BE: drawBug(g,x-10,y-2,x+2,y+10,x+8,y-8); break;
case BS|BE: drawBug(g,x-10,y+2,x+2,y-10,x+8,y+8); break;
case BN|BW: drawBug(g,x+10,y-2,x-2,y+10,x-8,y-8); break;
case BS|BW: drawBug(g,x+10,y+2,x-2,y-10,x-8,y+8); break;
case BN|BS: drawBug(g,x-8,y-1,x+8,y-1,x,y-10);
drawBug(g,x-8,y+1,x+8,y+1,x,y+10); break;
case BE|BW: drawBug(g,x+1,y-8,x+1,y+8,x+10,y);
drawBug(g,x-1,y-8,x-1,y+8,x-10,y); break;
}
}
void xdrawBug(Graphics g, int ax,int ay,int bx,int by,int cx,int cy) {
int x = (ax+bx+cx) / 3, y = (ay+by+cy) / 3;
x = x / 32 * 32 + 16;
y = y / 32 * 32 + 16;
g.setColor(tileColor.brighter());
g.fill3DRect(x-12,y-12,24,24,true);
int X[] = {ax,bx,cx}, Y[] = {ay,by,cy};
g.setColor(Color.black);
g.fillPolygon(X,Y,3);
g.drawPolygon(X,Y,3);
}
void drawBug(Graphics g, int ax,int ay,int bx,int by,int cx,int cy) {
int x = (2*ax+2*bx+cx)/5, y = (2*ay+2*by+cy)/5;
int X[] = {ax,x,bx,cx}, Y[] = {ay,y,by,cy};
draw(g, X,Y, 1, 1,Color.black);
draw(g, X,Y,-1,-1,bugColor.brighter());
draw(g, X,Y, 0, 0,bugColor);
}
void draw(Graphics g, int X[], int Y[], int dx, int dy, Color color) {
for (int i = 0 ; i < X.length ; i++) {
X[i] += dx;
Y[i] += dy;
}
g.setColor(color);
g.fillPolygon(X,Y,X.length);
g.drawPolygon(X,Y,Y.length);
for (int i = 0 ; i < X.length ; i++) {
X[i] -= dx;
Y[i] -= dy;
}
}
}