/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.games.boxworld;
import java.awt.AWTEvent;
import java.awt.CheckboxMenuItem;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Stack;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/**
* @author Levente S\u00e1ntha
*/
public class BoxWorld extends JComponent implements WindowListener, KeyListener,
MouseListener, MouseMotionListener, ActionListener, ItemListener {
private static final long serialVersionUID = 1L;
// ***************** WORLD DATA ****************************
private int[][] vecs = {
{81, -766241563, -831219482, -696967897, -863854201, -896130840,
-661281463, -828168022, -793433846, -758894261, 1073742156,
10, -829120249, 20, -795533048, 1073742122, 19, -862609146,
1073742123, 2382},
// 1
{105, -834465628, -900427516, -765290203, -630843034, -697000793,
-863854169, -729505560, -862543512, -861494039, -860444342,
-659182261, -826068565, -725307124, 50, -865856283,
-796648249, -728455927, -794580631, -660231894, -759943957,
12, -831252250, 11, -661249657, 1582},
// 2
{97, -867003259, -766241563, -731768507, -965338778, -831316857,
-964289273, -829315704, -962189975, -693917558, -860705653,
-759943957, -2147111605, 58, -832366426, -764110586,
-930767545, -763092792, -795728536, -760993463, 1073742154,
20, -729571161, 1073742121, 19, -895277911, 1073742026,
1350},
// 3
{73, -732654331, -798779035, -697066138, -695983896, -795630200,
-660362871, -825873173, -725307124, -2147077780, 26,
-730523354, -694901432, -2147112630, 20, -728456921,
-2147144406, 19, -759943926, -2147111605, 2110},
// 4
{89, -767291164, -732719804, -832170651, -831316602, -663413497,
-796712537, -862543544, -861493911, -827118166, -726356725,
-625595029, 50, -731637467, -697000602, -662331096,
-661314263, -727406326, 1073742218, 12, -693885658, 11,
-828136216, 2094},
// 5
{169, -801927997, -701166301, -935227005, -666693468, -766241691,
-966388411, -664561498, -898523738, -964256441, -628776792,
-694999959, -928929367, -626677462, -927487542, -793531189,
-725470741, -925388436, -825019219, -724257523, -623495827,
-2146978355, 130, -767291164, -933916348, -699198299,
-798812026, -698017498, -797762425, -863886969, -729505560,
-795728504, -895081143, -794580790, -894031542, -659182261,
-859655765, -758894356, -590958196, 20, -796615449,
-2147179287, 19, -796549915, -2147177303, 3678},
// 6
{105, -766241563, -665479867, -832366171, -864642746, -863593145,
-762108504, -928602807, -727504726, -927553142, -893242997,
-792481588, -691719892, 1073742220, 58, -698050298,
-764142361, -796517017, -829021880, -827972247, -726292182,
1073742187, 20, -695951128, -2147210999, 19, -827118421,
-2147177205, 3126},
// 7
{89, -732654331, -631892635, -798779194, -864903770, -629826233,
-595418681, -594107223, -828168022, -727406326, -692769366,
-2147046005, 42, -698017498, -663478906, -662331096,
-661314295, -2147079830, 20, -729538265, -2147113687, 19,
-830267161, -2147244855, 3398},
// 8
{129, -799828795, -699067099, -598305403, -731604794, -596435514,
-729505592, -862510744, -594139895, -794613590, -559470198,
-892883797, -891834004, -791431987, -690670291, -589908595,
1073742317, 82, -698083098, -831088250, -697000697,
-796484217, -627858040, -860444438, -692802293, -859361909,
-758894356, -590991028, 20, -628907705, -625660693, 19,
-694868695, -693819094, 3430},
// 9
{73, -699067099, -598305403, -831055578, -596337401, -828956440,
-827906647, -727406326, -692769366, -2147046005, 34,
-664430266, -762929754, -693885528, 1073742218, 20,
-663380665, -2147179192, 19, -728358552, -2147080855, 2118},
// 10
{105, -865953658, -698017562, -597255802, -831382425, -964223673,
-763092760, -963174072, -928929335, -593057494, -860705653,
-759943957, -659182261, 1073742251, 58, -697099097,
-930701945, -628743992, -695032695, -861754967, -727439126,
1073742218, 20, -862609240, 1073742217, 19, -762043159,
1073742153, 2902},
// 11
{73, -732654331, -865725083, -664528666, -629793593, -862543672,
-627825431, -626644726, -726356725, -2147078805, 42,
-831186650, -830104313, -761913080, -727406199, 1073742186,
20, -728424153, 1073742185, 19, -695951033, 1073742153,
2870},
// 12
{81, -800878396, -700116700, -665643644, -664495930, -863626041,
-661445240, -660297526, -793531189, -692769493, 1073742219,
34, -830104345, -695918328, -828005143, -2147112694, 28,
-764142299, -795565753, -2147146455, 27, -732687131,
-798779035, -2147116730, 2646},
// 20
{113, -868052860, -767291164, -666529468, -967764572, -999910267,
-765224762, -998860474, -997810809, -830267288, -662363864,
-962190231, -861755254, -760993558, -660231862, 66,
-833416027, -699067099, -933127803, -664430426, -764175257,
-929718136, -829217623, -694868695, 20, -697131770,
-2147213144, 19, -797762299, -2147211961, 1086},
// 30
{225, -937326526, -635238238, -534279742, -835515325, -734753533,
-633991837, -968814077, -900622844, -699067163, -531196539,
-698017690, -563701370, -864969210, -562783001, -763256760,
-862902808, -995646039, -794580790, -660264662, -559470166,
-927880117, -726455125, -591187509, -589974323, -656033586,
-856213074, -755745553, -2147107505, 170, -600667005,
-868085277, -767291164, -666529468, -933785148, -766241595,
-932735547, -798779226, -797795034, -596239033, -830267256,
-662331064, -963173976, -829250423, -728455927, -594139799,
-895342486, -759943957, -625595029, -624578228,
-2147043955, 36, -865693532, -697164346, -796745305,
-2147077782, 35, -758894356, -757844755, -790382259,
-2147141330, 798}
};
// ************** DIMENSIONS ********************
private static final int CELL_SIZE = 20;
private static final int X_SIZE = 20;
private static final int Y_SIZE = 20;
private static final int BW_WIDTH = X_SIZE * CELL_SIZE;
private static final int BW_HEIGHT = Y_SIZE * CELL_SIZE;
// *************** MODE CODES *******************
private static final int START_MODE = 0;
private static final int PLAY_MODE = 1;
private static final int END_MODE = 2;
private static final int HELP_MODE = 3;
// *********** MOVE CODES ****************
private static final int LEFT_MOVE = 1;
private static final int RIGHT_MOVE = LEFT_MOVE + 1;
private static final int UP_MOVE = RIGHT_MOVE + 1;
private static final int DOWN_MOVE = UP_MOVE + 1;
private static final int PUSH_BASE = DOWN_MOVE;
private static final int LEFT_PUSH = PUSH_BASE + 1;
private static final int RIGHT_PUSH = LEFT_PUSH + 1;
private static final int UP_PUSH = RIGHT_PUSH + 1;
private static final int DOWN_PUSH = UP_PUSH + 1;
private static final int DRAW_BASE = DOWN_PUSH;
private static final int LEFT_DRAW = DRAW_BASE + 1;
private static final int RIGHT_DRAW = LEFT_DRAW + 1;
private static final int UP_DRAW = RIGHT_DRAW + 1;
private static final int DOWN_DRAW = UP_DRAW + 1;
// **************** STATE CODE *****************
private static final int NULL_ST = 0;
private static final int WALL_ST = 1;
private static final int BACK_ST = 2;
private static final int GOAL_ST = 3;
private static final int BOX_ST = 4;
private static final int FIT_ST = 5;
private static final int MAN_ST = 6;
private static final int MAN_GOAL_ST = 7;
private int gameMode = PLAY_MODE;
// current world ID
private int worldId = 0;
// current world data
private int[] vec = vecs[worldId];
// current world
private int[][] state = new int[X_SIZE][Y_SIZE];
// goals list
private int[] goals;
// suspends the current movement at an obstacle
private boolean repeat = true;
// end state
// private boolean endState = false;
// controlls the speed of animation
private int SLEEP = 5;
// current and previous position of the man
private int x, y, xo, yo;
// popup menu
@SuppressWarnings("unused")
private PopupMenu menu;
@SuppressWarnings("unused")
private CheckboxMenuItem beep;
// **************** APPLET METHODS *************************
// init applet
public void init() {
setBackground(Color.lightGray);
x = xo = 10;
y = yo = 10;
// loading the first wold in the world table
loadWorld();
// registering listeners
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
setFocusable(true);
enableEvents(AWTEvent.FOCUS_EVENT_MASK);
requestFocus();
/*
// building the popup menu
menu = new PopupMenu();
MenuItem start = new MenuItem("Start");
start.addActionListener(this);
start.setActionCommand("start");
menu.add(start);
MenuItem next = new MenuItem("Next");
next.addActionListener(this);
next.setActionCommand("next");
menu.add(next);
MenuItem previous = new MenuItem("Previous");
previous.addActionListener(this);
previous.setActionCommand("previous");
menu.add(previous);
menu.addSeparator();
MenuItem undo = new MenuItem("Undo");
undo.addActionListener(this);
undo.setActionCommand("undo");
menu.add(undo);
MenuItem redo = new MenuItem("Redo");
redo.addActionListener(this);
redo.setActionCommand("redo");
menu.add(redo);
menu.addSeparator();
beep = new CheckboxMenuItem("Beep", beepOn);
beep.addItemListener(this);
beep.setActionCommand("beep");
menu.add(beep);
add(menu);
*/
}
// start applet
public void start() {
requestFocus();
}
private void loadWorld() {
int sh, s, n, xx, yy, ind = 0;
// int len = vec.length;
List<Integer> gv = new ArrayList<Integer>();
for (int i = 0; i < 4; i++) {
s = 0x00000007 & vec[ind];
n = vec[ind] >> 3;
ind++;
for (int j = 0; j < n; j++, ind++) {
sh = 0x00000003 & (vec[ind] >> 30);
// int m = 0xFFFFFFFF;
// int ssh = 0;
int v = vec[ind];
for (int k = 0; k < sh; k++) {
xx = 0x0000001F & v;
v = v >> 5;
yy = 0x0000001F & v;
v = v >> 5;
if (xx < X_SIZE && yy < Y_SIZE) {
if (s == GOAL_ST) {
gv.add(xx | (yy << 16));
}
if (s == BOX_ST && state[xx][yy] == GOAL_ST ||
s == GOAL_ST && state[xx][yy] == BOX_ST) {
state[xx][yy] = FIT_ST;
} else if (s == MAN_ST && state[xx][yy] == GOAL_ST ||
s == GOAL_ST && state[xx][yy] == MAN_ST) {
state[xx][yy] = MAN_GOAL_ST;
} else {
state[xx][yy] = s;
}
}
}
}
}
final int goal_cnt = gv.size();
goals = new int[goal_cnt];
int i = 0;
for (int v : gv) {
goals[i++] = v;
}
int v = vec[ind] >> 3;
xx = 0x0000001F & v;
v = v >> 5;
yy = 0x0000001F & v;
state[xx][yy] = MAN_ST;
x = xx;
y = yy;
// endState = false;
}
// ************************************************************************************
// ******************************* EVENT HANDLING
// *************************************
// ************************************************************************************
// ----------------------------------KEY EVENTS----------------------------------------
public void keyPressed(KeyEvent e) {
if (gameMode == START_MODE) {
controlWorld(KeyEvent.VK_S);
} else if (gameMode == END_MODE) {
controlWorld(KeyEvent.VK_N);
} else {
int key = e.getKeyCode();
int code = key == KeyEvent.VK_LEFT ? LEFT_MOVE :
key == KeyEvent.VK_RIGHT ? RIGHT_MOVE :
key == KeyEvent.VK_UP ? UP_MOVE :
key == KeyEvent.VK_DOWN ? DOWN_MOVE : -1;
if (code > 0) {
if (gameMode == PLAY_MODE) {
changeState(code);
}
} else {
controlWorld(key);
}
}
}
// ----------------------------------MOUSE EVENTS---------------------------------------
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
if (this.contains(e.getX(), e.getY())) {
if (!this.hasFocus() && this.isRequestFocusEnabled()) {
this.requestFocus();
}
}
}
if (gameMode != PLAY_MODE) {
changeMode();
} else {
if (e.isPopupTrigger()) {
// menu.show(this, e.getX(), e.getY());
return;
}
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == 0) {
return;
}
moveTo(e.getX(), e.getY());
}
}
public void mouseClicked(MouseEvent e) { // changeMode() ;
}
public void mouseDragged(MouseEvent e) {
/*
* if(e.isPopupTrigger()){ menu.show(this,e.getX(),e.getY()); return; }
* if((e.getModifiers()& e.BUTTON1_MASK) == 0)
*/
moveTo2(e.getX(), e.getY());
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
// menu.show(this, e.getX(), e.getY());
}
}
// ----------------------------------ACTION EVENTS-------------------------------------
// FROM MENU
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if ("start".equals(command)) {
startWorld();
} else if ("next".equals(command)) {
nextWorld();
} else if ("previous".equals(command)) {
previousWorld();
} else if ("undo".equals(command)) {
undo();
} else if ("redo".equals(command)) {
redo();
}
}
// ----------------------------------ITEM
// EVENTS----------------------------------------
// CHECKBOX MENUITEM
public void itemStateChanged(ItemEvent e) {
toggleBeep();
}
// *************************************************************************************
// ****************GAME CONTROL WITH
// MOUSE**********************************************
// *************************************************************************************
private void moveTo(int xpos, int ypos) {
repeat = true;
int x1 = ypos / CELL_SIZE;
int y1 = xpos / CELL_SIZE;
int d;
boolean valid = true;
int st, bc = 0;
if (x1 == x && y1 != y) {
if (y1 > y) {
for (int i = y; i <= y1; i++) {
st = state[x][i];
if (st == WALL_ST || st == NULL_ST) {
valid = false;
break;
} else if (st == BOX_ST || st == FIT_ST) {
bc++;
if (bc > 1) {
valid = false;
break;
}
}
}
} else {
for (int i = y1; i <= y; i++) {
st = state[x][i];
if (st == WALL_ST || st == NULL_ST) {
valid = false;
break;
} else if (st == BOX_ST || st == FIT_ST) {
bc++;
if (bc > 1) {
valid = false;
break;
}
}
}
}
} else if (x1 != x && y1 == y) {
if (x1 > x) {
for (int i = x; i <= x1; i++) {
st = state[i][y];
if (st == WALL_ST || st == NULL_ST) {
valid = false;
break;
} else if (st == BOX_ST || st == FIT_ST) {
bc++;
if (bc > 1) {
valid = false;
break;
}
}
}
} else {
for (int i = x1; i <= x; i++) {
st = state[i][y];
if (st == WALL_ST || st == NULL_ST) {
valid = false;
break;
} else if (st == BOX_ST || st == FIT_ST) {
bc++;
if (bc > 1) {
valid = false;
break;
}
}
}
}
} else {
valid = false;
}
if (valid) {
if (x1 == x && y1 != y) {
if (y1 > y) {
d = y1 - y;
for (int i = 0; i < d && repeat; i++) {
changeState(RIGHT_MOVE);
try {
Thread.sleep(SLEEP);
} catch (InterruptedException e1) {
//empty
}
}
} else {
d = y - y1;
for (int i = 0; i < d && repeat; i++) {
changeState(LEFT_MOVE);
try {
Thread.sleep(SLEEP);
} catch (InterruptedException e1) {
//empty
}
}
}
} else if (x1 != x && y1 == y) {
if (x1 > x) {
d = x1 - x;
for (int i = 0; i < d && repeat; i++) {
changeState(DOWN_MOVE);
try {
Thread.sleep(SLEEP);
} catch (InterruptedException e1) {
//empty
}
}
} else {
d = x - x1;
for (int i = 0; i < d && repeat; i++) {
changeState(UP_MOVE);
try {
Thread.sleep(SLEEP);
} catch (InterruptedException e1) {
//empty
}
}
}
}
} else {
List<Point> path = findPath(new Point(y, x), new Point(y1, x1));
if (path.size() > 1) {
Point cpnt, opnt;
opnt = (Point) path.get(0);
int psize = path.size();
for (int i = 1; i < psize && repeat; i++) {
cpnt = (Point) path.get(i);
moveOne(cpnt.y, cpnt.x, opnt.y, opnt.x);
opnt = cpnt;
try {
Thread.sleep(SLEEP);
} catch (InterruptedException e1) {
//empty
}
}
}
}
}
private void moveOne(int x1, int y1, int x, int y) {
int dx = x - x1, dy = y - y1;
if (Math.abs(dx) + Math.abs(dy) != 1) {
return;
}
if (dx == -1) {
changeState(DOWN_MOVE);
} else if (dx == 1) {
changeState(UP_MOVE);
} else if (dy == -1) {
changeState(RIGHT_MOVE);
} else if (dy == 1) {
changeState(LEFT_MOVE);
}
}
private List<Point> findPath(Point p1, Point p2) {
List<Point> nlist = new ArrayList<Point>();
List<Point> path = new ArrayList<Point>();
Hashtable<Point, Point> vmap = new Hashtable<Point, Point>();
nlist.add(p1);
Point pp = p1, pp2 = null;
int xx, yy, vi = 0;
while (!(pp.equals(p2) || nlist.size() == vi)) {
pp = (Point) nlist.get(vi++);
xx = pp.x - 1;
yy = pp.y;
if (xx >= 0 &&
(state[yy][xx] == BACK_ST || state[yy][xx] == GOAL_ST || state[yy][xx] == GOAL_ST) &&
!vmap.containsKey(pp2 = new Point(xx, yy)) &&
!nlist.contains(pp2)) {
nlist.add(pp2);
vmap.put(pp2, pp);
}
xx = pp.x + 1;
if (xx < X_SIZE &&
(state[yy][xx] == BACK_ST || state[yy][xx] == GOAL_ST || state[yy][xx] == GOAL_ST) &&
!vmap.containsKey(pp2 = new Point(xx, yy)) &&
!nlist.contains(pp2)) {
nlist.add(pp2);
vmap.put(pp2, pp);
}
xx = pp.x;
yy = pp.y - 1;
if (yy >= 0 &&
(state[yy][xx] == BACK_ST || state[yy][xx] == GOAL_ST || state[yy][xx] == GOAL_ST) &&
!vmap.containsKey(pp2 = new Point(xx, yy)) &&
!nlist.contains(pp2)) {
nlist.add(pp2);
vmap.put(pp2, pp);
}
yy = pp.y + 1;
if (yy < Y_SIZE &&
(state[yy][xx] == BACK_ST || state[yy][xx] == GOAL_ST || state[yy][xx] == GOAL_ST) &&
!vmap.containsKey(pp2 = new Point(xx, yy)) &&
!nlist.contains(pp2)) {
nlist.add(pp2);
vmap.put(pp2, pp);
}
}
if (pp.equals(p2)) {
do {
path.add(0, pp);
pp2 = pp;
pp = (Point) vmap.get(pp);
} while (pp2 != pp && pp != null);
}
return path;
}
public void moveTo2(int xpos, int ypos) {
repeat = true;
int x1 = ypos / CELL_SIZE;
int y1 = xpos / CELL_SIZE;
int d;
if (state[x1][y1] == NULL_ST || state[x1][y1] == WALL_ST)
return;
if (x1 == x && y1 != y) {
if (y1 > y) {
d = y1 - y;
for (int i = 0; i < d && repeat; i++) {
changeState(RIGHT_MOVE);
}
} else {
d = y - y1;
for (int i = 0; i < d && repeat; i++) {
changeState(LEFT_MOVE);
}
}
} else if (x1 != x && y1 == y) {
if (x1 > x) {
d = x1 - x;
for (int i = 0; i < d && repeat; i++) {
changeState(DOWN_MOVE);
}
} else {
d = x - x1;
for (int i = 0; i < d && repeat; i++) {
changeState(UP_MOVE);
}
}
}
}
private void changeMode() {
switch (gameMode) {
case START_MODE: {
gameMode = PLAY_MODE;
break;
}
case PLAY_MODE: {
break;
}
case HELP_MODE: {
break;
}
case END_MODE: {
nextWorld();
gameMode = PLAY_MODE;
break;
}
}
update(getGraphics());
}
private void controlWorld(int key) {
switch (key) {
case KeyEvent.VK_N:
// next world
nextWorld();
break;
case KeyEvent.VK_P:
// previous world
previousWorld();
break;
case KeyEvent.VK_S:
// restart
startWorld();
break;
case KeyEvent.VK_U:
// undo
if (gameMode == PLAY_MODE)
undo();
break;
case KeyEvent.VK_R:
// redo
if (gameMode == PLAY_MODE)
redo();
break;
case KeyEvent.VK_B:
// toggle beep
toggleBeep();
break;
case KeyEvent.VK_H:
// show help
help();
break;
case KeyEvent.VK_C:
// continue the game
continueGame();
break;
}
}
private void nextWorld() {
worldId++;
if (worldId == 5) {
// int x = worldId * 100;
}
if (worldId == vecs.length)
worldId = 0;
vec = vecs[worldId];
controlWorld(KeyEvent.VK_S);
}
private void previousWorld() {
worldId--;
if (worldId < 0)
worldId = vecs.length - 1;
vec = vecs[worldId];
controlWorld(KeyEvent.VK_S);
}
private void startWorld() {
ereaseWorld();
loadWorld();
repaint();
undoStack.removeAllElements();
redoStack.removeAllElements();
gameMode = PLAY_MODE;
}
private void toggleBeep() {
beepOn = !beepOn;
// beep.setState(beepOn);
}
private void help() {
gameMode = HELP_MODE;
changeMode();
}
private void continueGame() {
gameMode = PLAY_MODE;
update(getGraphics());
}
private void ereaseWorld() {
for (int i = 0; i < X_SIZE; i++) {
for (int j = 0; j < Y_SIZE; j++) {
state[i][j] = 0;
}
}
}
// ******************* UNDO ********************
private Stack<Integer> undoStack = new Stack<Integer>();
private Stack<Integer> redoStack = new Stack<Integer>();
private boolean isUndo = false;
private boolean isRedo = false;
private void undo() {
isUndo = true;
if (undoStack.empty()) {
beep();
} else {
changeState(((Integer) undoStack.pop()).intValue());
}
isUndo = false;
}
private void redo() {
isRedo = true;
if (redoStack.empty()) {
beep();
} else {
changeState(((Integer) redoStack.pop()).intValue());
}
isRedo = false;
}
private boolean checkEnd() {
int v, x, y;
boolean ret = true;
for (int i = 0; i < goals.length; i++) {
v = goals[i];
x = 0xFFFF & v;
y = 0xFFFF & (v >> 16);
if (state[x][y] != FIT_ST) {
ret = false;
break;
}
}
return ret;
}
// ****************** GRAPHICS *********************************
// private Image[] imgVec = new Image[8];
// private int ISIZE = CELL_SIZE;
// STATE PAINTING
/**
* Paints the NULL state.
*/
private void paintNull(Graphics g, int j, int i) {
// Image img=imgVec[NULL_ST];
// if(img==null){
// img=createImage(ISIZE,ISIZE);
// imgVec[NULL_ST]=img;
// Graphics ig=img.getGraphics();
g.setColor(Color.black);
g.fillRect(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
// }
// g.drawImage(img,j * DIM, i * DIM,this);
}
private void paintWall(Graphics g, int j, int i) {
// Image img=imgVec[WALL_ST];
// if(img==null){
// img=createImage(ISIZE,ISIZE);
// imgVec[WALL_ST]=img;
// Graphics ig=img.getGraphics();
g.setColor(Color.gray);
g.fillRect(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
g.setColor(Color.lightGray);
g.drawRect(j * CELL_SIZE + 1, i * CELL_SIZE + 1, CELL_SIZE - 2,
CELL_SIZE - 2);
// }
// g.drawImage(img,j * CELL_SIZE, i * CELL_SIZE,this);
}
private void paintBack(Graphics g, int j, int i) {
// Image img=imgVec[BACK_ST];
// if(img==null){
// img=createImage(ISIZE,ISIZE);
// imgVec[BACK_ST]=img;
// Graphics ig=img.getGraphics();
g.setColor(Color.blue);
g.fillRect(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
// }
// g.drawImage(img,j * CELL_SIZE, i * CELL_SIZE,this);
}
private void paintGoal(Graphics g, int j, int i) {
// Image img=imgVec[GOAL_ST];
// if(img==null){
// img=createImage(ISIZE,ISIZE);
// imgVec[GOAL_ST]=img;
// Graphics ig=img.getGraphics();
g.setColor(Color.green);
g.fillOval(j * CELL_SIZE + CELL_SIZE / 4,
i * CELL_SIZE + CELL_SIZE / 4, CELL_SIZE / 2, CELL_SIZE / 2);
// }
// g.drawImage(img,j * CELL_SIZE, i * CELL_SIZE,this);
}
private void paintBox(Graphics g, int j, int i, Color c) {
g.setColor(c);
g.fillRect(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
g.setColor(Color.lightGray);
g.drawRect(j * CELL_SIZE + 1, i * CELL_SIZE + 1, CELL_SIZE - 2,
CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + 1, i * CELL_SIZE + 1, (j + 1) * CELL_SIZE - 1,
(i + 1) * CELL_SIZE - 1);
g.drawLine(j * CELL_SIZE + 1, (i + 1) * CELL_SIZE - 1, (j + 1) * CELL_SIZE - 1,
i * CELL_SIZE + 1);
}
private void paintBox(Graphics g, int j, int i) {
// Image img=imgVec[BOX_ST];
// if(img==null){
// img=createImage(ISIZE,ISIZE);
// imgVec[BOX_ST]=img;
// Graphics ig=img.getGraphics();
paintBox(g, j, i, Color.yellow);
// }
// g.drawImage(img,j * CELL_SIZE, i * CELL_SIZE,this);
}
private void paintFit(Graphics g, int j, int i) {
paintBox(g, j, i, Color.red);
}
private void paintMan(Graphics g, int j, int i) {
g.setColor(Color.cyan);
// head
g.fillOval(j * CELL_SIZE + CELL_SIZE / 2 - CELL_SIZE / 8, i * CELL_SIZE +
CELL_SIZE / 16, CELL_SIZE / 4, CELL_SIZE / 4);
// g.drawLine(j * CELL_SIZE + CELL_SIZE / 2, i * CELL_SIZE + 2, j *
// CELL_SIZE + CELL_SIZE / 2, i * CELL_SIZE + 13);
// body
g.fillRect(j * CELL_SIZE + CELL_SIZE / 2 - CELL_SIZE / 16, i *
CELL_SIZE + CELL_SIZE / 4, CELL_SIZE / 8, CELL_SIZE / 3 +
CELL_SIZE / 12);
// g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 + 1, i * CELL_SIZE + 8, j *
// CELL_SIZE + CELL_SIZE / 2 + 1, i * CELL_SIZE + 13);
// arms
g.fillRect(j * CELL_SIZE + CELL_SIZE / 8, i * CELL_SIZE + CELL_SIZE * 5 / 16,
CELL_SIZE * 3 / 4, CELL_SIZE / 16);
// legs
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2, i * CELL_SIZE + CELL_SIZE * 7 / 12,
j * CELL_SIZE + 4, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2, i * CELL_SIZE + CELL_SIZE * 7 / 12,
(j + 1) * CELL_SIZE - 4, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 + 1, i * CELL_SIZE + CELL_SIZE * 7 / 12,
j * CELL_SIZE + 4 + 1, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 - 1, i * CELL_SIZE + CELL_SIZE * 7 / 12,
(j + 1) * CELL_SIZE - 4 - 1, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 + 2, i * CELL_SIZE + CELL_SIZE * 7 / 12,
j * CELL_SIZE + 4 + 2, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 - 2, i * CELL_SIZE + CELL_SIZE * 7 / 12,
(j + 1) * CELL_SIZE - 4 - 2, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 + 3, i * CELL_SIZE + CELL_SIZE * 7 / 12,
j * CELL_SIZE + 4 + 3, (i + 1) * CELL_SIZE - 2);
g.drawLine(j * CELL_SIZE + CELL_SIZE / 2 - 3, i * CELL_SIZE + CELL_SIZE * 7 / 12,
(j + 1) * CELL_SIZE - 4 - 3, (i + 1) * CELL_SIZE - 2);
}
private void paintManGoal(Graphics g, int j, int i) {
paintGoal(g, j, i);
paintMan(g, j, i);
}
private void paintStart(Graphics g) {
g.setColor(Color.black);
int dx = 200;
int dy = 100;
int x = (BW_WIDTH - dx) / 2;
int y = (BW_HEIGHT - dy) / 2;
g.fillRect(x, y, dx, dy);
g.setColor(Color.white);
g.drawRect(x + 2, y + 2, dx - 4, dy - 4);
g.drawRect(x + 3, y + 3, dx - 6, dy - 6);
g.drawRect(x + 4, y + 4, dx - 8, dy - 8);
g.drawString("CLICK HERE!", x + 70, y + 50);
}
private void paintEnd(Graphics g) {
g.setColor(Color.black);
int dx = 200;
int dy = 100;
int x = (BW_WIDTH - dx) / 2;
int y = (BW_HEIGHT - dy) / 2;
g.fillRect(x, y, dx, dy);
g.setColor(Color.white);
g.drawRect(x + 2, y + 2, dx - 4, dy - 4);
g.drawRect(x + 3, y + 3, dx - 6, dy - 6);
g.drawRect(x + 4, y + 4, dx - 8, dy - 8);
g.drawString("GOOD JOB!", x + 70, y + 50);
}
private static String[] help = {"s - start game", "n - next world",
"p - previous world", "u - undo", "r - redo", "b - toggle beep",
"h - help", " ", "Press C to continue", " ", "Created by",
"Levente S\u00e1ntha, 2002",
};
private void paintHelp(Graphics g) {
g.setColor(Color.black);
int dx = 200;
int dy = 320;
int x = (BW_WIDTH - dx) / 2;
int y = (BW_HEIGHT - dy) / 2;
g.fillRect(x, y, dx, dy);
g.setColor(Color.white);
g.drawRect(x + 2, y + 2, dx - 4, dy - 4);
g.drawRect(x + 3, y + 3, dx - 6, dy - 6);
g.drawRect(x + 4, y + 4, dx - 8, dy - 8);
g.drawString("H E L P", x + 80, y + 40);
for (int i = 0; i < help.length; i++) {
g.drawString(help[i], x + 40, y + 70 + 20 * i);
}
}
private void paintShape(Graphics g, int j, int i) {
int c = state[i][j];
if (c > NULL_ST)
switch (c) {
case NULL_ST:
paintNull(g, j, i);
break;
case WALL_ST:
paintWall(g, j, i);
break;
case BACK_ST:
paintBack(g, j, i);
break;
case GOAL_ST:
paintBack(g, j, i);
paintGoal(g, j, i);
break;
case BOX_ST:
paintBox(g, j, i);
break;
case FIT_ST:
paintFit(g, j, i);
break;
case MAN_ST:
paintBack(g, j, i);
paintMan(g, j, i);
break;
case MAN_GOAL_ST:
paintBack(g, j, i);
paintManGoal(g, j, i);
break;
}
}
private Image iBuff = null;
public void paint(Graphics gr) {
if (iBuff == null) {
iBuff = createImage(BW_WIDTH, BW_HEIGHT);
}
Graphics g = iBuff.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, BW_WIDTH, BW_HEIGHT);
switch (gameMode) {
case START_MODE: {
paintStart(g);
break;
}
case PLAY_MODE: {
for (int j = 0; j < X_SIZE; j++) {
for (int i = 0; i < Y_SIZE; i++) {
paintShape(g, j, i);
}
}
break;
}
case HELP_MODE: {
paintHelp(g);
break;
}
case END_MODE: {
paintEnd(g);
break;
}
}
g.dispose();
gr.drawImage(iBuff, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
private int invert(int key) {
int inv = -1;
switch (key) {
case LEFT_MOVE:
inv = RIGHT_MOVE;
break;
case RIGHT_MOVE:
inv = LEFT_MOVE;
break;
case UP_MOVE:
inv = DOWN_MOVE;
break;
case DOWN_MOVE:
inv = UP_MOVE;
break;
case LEFT_PUSH:
inv = RIGHT_DRAW;
break;
case RIGHT_PUSH:
inv = LEFT_DRAW;
break;
case UP_PUSH:
inv = DOWN_DRAW;
break;
case DOWN_PUSH:
inv = UP_DRAW;
break;
case LEFT_DRAW:
inv = RIGHT_MOVE;
break;
case RIGHT_DRAW:
inv = LEFT_MOVE;
break;
case UP_DRAW:
inv = DOWN_MOVE;
break;
case DOWN_DRAW:
inv = UP_MOVE;
break;
}
return inv;
}
private void undoController(int key) {
if (isUndo) {
redoStack.push(new Integer(invert(key)));
} else {
if (redoStack.size() > 0 && !isRedo)
redoStack.removeAllElements();
undoStack.push(new Integer(invert(key)));
}
}
private void changeState(int key) {
Graphics g = getGraphics();
int xt = x, yt = y, ct;
xo = x;
yo = y;
boolean isDraw = false;
switch (key) {
case LEFT_MOVE:
y--;
yt = y - 1;
break;
case RIGHT_MOVE:
y++;
yt = y + 1;
break;
case UP_MOVE:
x--;
xt = x - 1;
break;
case DOWN_MOVE:
x++;
xt = x + 1;
break;
case LEFT_DRAW:
yt = y + 1;
y--;
isDraw = true;
break;
case RIGHT_DRAW:
yt = y - 1;
y++;
isDraw = true;
break;
case UP_DRAW:
xt = x + 1;
x--;
isDraw = true;
break;
case DOWN_DRAW:
xt = x - 1;
x++;
isDraw = true;
break;
}
int c = state[x][y];
if (isDraw) {
undoController(key);
cellExited(xo, yo);
cellExited(xt, yt);
cellEntered(x, y, MAN_ST);
cellEntered(xo, yo, BOX_ST);
paintShape(g, yt, xt);
paintShape(g, y, x);
paintShape(g, yo, xo);
} else if (c == BACK_ST || c == GOAL_ST) {
undoController(key);
cellExited(xo, yo);
cellEntered(x, y, MAN_ST);
paintShape(g, y, x);
paintShape(g, yo, xo);
} else if (c == BOX_ST || c == FIT_ST) {
ct = state[xt][yt];
if (ct == BACK_ST || ct == GOAL_ST) {
undoController(PUSH_BASE + key);
cellExited(xo, yo);
cellExited(x, y);
cellEntered(x, y, MAN_ST);
cellEntered(xt, yt, BOX_ST);
paintShape(g, yt, xt);
paintShape(g, y, x);
paintShape(g, yo, xo);
} else {
block();
}
} else {
block();
}
if (checkEnd()) {
gameMode = END_MODE;
paintEnd(g);
}
}
private void cellEntered(int x, int y, int mst) {
int st = state[x][y];
if (st == BACK_ST) {
state[x][y] = mst;
} else if (st == GOAL_ST) {
state[x][y] = mst == MAN_ST ? MAN_GOAL_ST : FIT_ST;
}
}
private void cellExited(int x, int y) {
int st = state[x][y];
if (st == MAN_ST || st == BOX_ST) {
state[x][y] = BACK_ST;
} else if (st == FIT_ST || st == MAN_GOAL_ST) {
state[x][y] = GOAL_ST;
}
}
private void block() {
x = xo;
y = yo;
repeat = false;
beep();
}
private boolean beepOn = true;
private void beep() {
// if (beepOn) getToolkit().beep();
}
public Dimension getPreferredSize() {
return new Dimension(BW_WIDTH, BW_HEIGHT);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
// *********** MAIN ************************
public static void main(String[] argv) {
BoxWorld bw = new BoxWorld();
bw.init();
Frame frame = new JFrame("BoxWorld");
frame.setResizable(false);
frame.add(bw);
frame.addWindowListener(bw);
frame.pack();
frame.setSize(400, 400);
frame.setLocation(40, 40);
frame.setVisible(true);
bw.requestFocus();
// frame.setVisible(true);
}
// ************ EMPTY METHODS *********************
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
}