package slidePuzzle; import baklava.*; import java.applet.Applet; import java.awt.*; public class SlidePuzzle extends Applet { // The playfield. public Playfield p; // Images to draw pieces in various directions and motions. public Image pieceImages[][] = new Image[3][4]; // The coordinates of the open space in the puzzle. int rowOpen = 3, colOpen = 3; // A "picture" of the grid. Piece[][] pieces = new Piece[4][4]; PuzzleButton shuffler; PuzzleButton stopper; // True if a piece is already moving. boolean moving = false; // True if the applet is shuffling itself. boolean shuffling = false; public void init() { // No background image, so set the // background color of the applet // (which is a Component...) setBackground(Color.white); p = new Playfield(this, 4 * 32, 4 * 32 + 32); // Set no layout manager for the applet setLayout(null); // IMPORTANT: add the playfield to the applet! add(p); int row, col; String base = getParameter("imageurl"); if ((base == null) || (base == "")) { System.out.println("imageurl parameter not set!"); return; } int pose; int direction; // Fetch all twelve images in a loop. for (pose = 0; (pose < 3); pose++) { Integer poseInteger = new Integer(pose); for (direction = 0; (direction < 4); direction++) { Integer directionInteger = new Integer(direction); String url = base + "piece" + poseInteger.toString() + directionInteger.toString() + ".gif"; pieceImages[pose][direction] = p.getImage(url); } } int count = 1; for (row = 0; (row < 4); row++) { for (col = 0; (col < 4); col++) { if ((row == rowOpen) && (col == colOpen)) { // Skip this position continue; } pieces[row][col] = new Piece(this, row, col, count); count++; } } // Buttons implemented as Baklava sprites shuffler = new PuzzleButton(this, 0, 128, 128, 32, "Shuffle"); shuffler.setLevel(0); stopper = new PuzzleButton(this, 0, 128, 128, 32, "Stop"); stopper.setLevel(-1); p.start(); } public void pieceClicked(Piece piece, int row, int col) { if (moving) { // Just one piece moves at a time. return; } // Can this piece move? if (rowOpen == row) { // Horizontal moves if (colOpen == (col + 1)) { // Moving right piece.setPoseAndDirection(1, 3); piece.setTimer(100, 0); moving = true; } else if (colOpen == (col - 1)) { // Moving left piece.setPoseAndDirection(1, 2); piece.setTimer(100, 0); moving = true; } } else if (colOpen == col) { // OK, try vertical moves if (rowOpen == (row + 1)) { // Moving down piece.setPoseAndDirection(1, 1); piece.setTimer(100, 0); moving = true; } else if (rowOpen == (row - 1)) { // Moving up piece.setPoseAndDirection(1, 0); piece.setTimer(100, 0); moving = true; } } // If we found that the piece can move, // set its speed and its destination. // Then record the old location as // the new open space. if (moving) { piece.setTarget(colOpen * 32, rowOpen * 32); if (shuffling) { // Super fast shuffle piece.setSpeed(90); } else { // Normal speed piece.setSpeed(60); } piece.setRowCol(rowOpen, colOpen); pieces[row][col] = null; pieces[rowOpen][colOpen] = piece; rowOpen = row; colOpen = col; } } public void moveDone() { moving = false; if (shuffling) { shuffleMove(); } } public void buttonPressed(PuzzleButton b) { if (b == shuffler) { if (moving) { // Important little touch: don't start // shuffling if a piece is still moving. return; } // Put the stop button on top shuffler.setLevel(-1); stopper.setLevel(0); startShuffling(); } else if (b == stopper) { // Put the shuffle button on top stopper.setLevel(-1); shuffler.setLevel(0); stopShuffling(); } } void startShuffling() { shuffling = true; shuffleMove(); } void stopShuffling() { shuffling = false; } void shuffleMove() { // Randomly "click" on a piece // that can legally move. int row; int col; if (Math.random() < .5) { // Vertical moves if ((rowOpen < 3) && (Math.random() < .5)) { // Up row = rowOpen + 1; col = colOpen; } else if (rowOpen > 0) { // Down row = rowOpen - 1; col = colOpen; } else { // Top row; so up wins after all row = rowOpen + 1; col = colOpen; } } else { // Horizontal moves if ((colOpen < 3) && (Math.random() < .5)) { // Left col = colOpen + 1; row = rowOpen; } else if (colOpen > 0) { // Right col = colOpen - 1; row = rowOpen; } else { // Leftmost column; so left wins after all col = colOpen + 1; row = rowOpen; } } // Tell the piece to move. pieceClicked(pieces[row][col], row, col); } public boolean isShuffling() { return shuffling; } }; // A button implemented as a sprite, instead of a separate AWT component. class PuzzleButton extends Sprite { SlidePuzzle p; String label; public PuzzleButton(SlidePuzzle pArg, int x, int y, int w, int h, String labelArg) { // Call the sprite constructor. super(pArg.p); p = pArg; label = labelArg; setX(x); setY(y); setWidth(w); setHeight(h); } public void paint(Graphics g) { // There's no image associated with this sprite; // it is drawn entirely by this replacement // paint method. g.setColor(Color.red); g.fillRect(getX(), getY(), getWidth(), getHeight()); g.setColor(Color.white); // Center the label (this is a bit involved) FontMetrics fm = p.p.getFontMetrics(g.getFont()); int x = getX() + getWidth() / 2; int y = getY() + getHeight() / 2; x -= fm.stringWidth(label) / 2; y += fm.getAscent() / 2; g.drawString(label, x, y); } public void mouseDown(Event evt, int x, int y) { // Report the button press to the puzzle. p.buttonPressed(this); } }; class Piece extends Sprite { SlidePuzzle p; int row; int col; int moveToX; int moveToY; int id; // 0, 1, 2 are resting, first foot, second foot int pose = 0; // 0, 1, 2, 3 are up, down, left, right int direction = 0; public Piece(SlidePuzzle pArg, int rowArg, int colArg, int idArg) { // Call the sprite constructor first! super(pArg.p); p = pArg; row = rowArg; col = colArg; id = idArg; setPoseAndDirection(0, (int) (Math.random() * 4)); Image image = p.pieceImages[pose][direction]; setX(col * 32); setY(row * 32); } public void paint(Graphics g) { super.paint(g); if (pose != 0) { // Don't draw the numbers when walking return; } g.setColor(Color.red); String text = (new Integer(id)).toString(); // Center the label (this is a bit involved) FontMetrics fm = p.p.getFontMetrics(g.getFont()); int x = getX() + getWidth() / 2; int y = getY() + getHeight() / 2; x -= fm.stringWidth(text) / 2; y += fm.getAscent() / 2; g.drawString(text, x, y); } public void mouseDown(Event evt, int x, int y) { // Don't report the mouse click if the applet // is shuffling itself if (!p.isShuffling()) { // Tell the puzzle that we've been clicked upon. p.pieceClicked(this, row, col); } } public void onArrival() { stopMoving(); } void stopMoving() { // We've arrived at our destination. setPoseAndDirection(0, direction); // Tell the puzzle we're done. p.moveDone(); } public void setRowCol(int rowArg, int colArg) { row = rowArg; col = colArg; } public void setPoseAndDirection(int poseArg, int directionArg) { pose = poseArg; direction = directionArg; setImage(p.pieceImages[pose][direction]); } public void timer(int id) { if (id == 0) { // A signal to change feet if we're not done walking. if (pose == 0) { return; } // We're still walking... int newPose; if (pose == 1) { newPose = 2; } else { newPose = 1; } setPoseAndDirection(newPose, direction); // Set a new timer to change feet again. setTimer(100, 0); } } };