jaki1910 | Bonjour,
est ce que svp je peux savoir d’après ce code comment il detecte si les pieces sont bien mises et que le puzzle est résolu.
je pense que apres le clique sur la piece il recupere son identifiant, mais je ne comprends pas comment sa voisine est detecté avant de les coller?
Merci beaucoup pour votre aide.
Code :
- /**
- *Each piece knows the portion of the image it contains, how its edges are to *be drawn, and what its
- * neighboring pieces are.
- *
- * <p> When two or more Pieces are put together, the result is another
- * Piece object, a MultiPiece.
- *
- * @see MultiPiece
- */
- public class Piece implements Serializable
- {
- // Class constants ------------------------------------------------------
- /** Unique id for the next piece */
- private static int nextId = 0;
- /** A Piece must be within this many pixels of "perfect" to be considered
- * close. */
- public static final int posClose = 7;
- /** A Piece must be within this many degrees of rotation from another to
- * be considered aligned to it. */
- public static final int rotClose = 5;
- // Constructor and fields -----------------------------------------------
- /** Creates a new Piece. No initial rotation is done. (This is needed
- * by MultiPiece, which needs to set its subpieces before rotating.)
- * @param data image data
- * @param imageX X position of image relative to entire puzzle
- * @param imageY Y position of image relative to entire puzzle
- * @param imageWidth width of original image
- * @param imageHeight height of original image
- * @param totalWidth the width of the entire picture
- * @param totalHeight the height of the entire picture
- */
- protected Piece(int[] data, int imageX, int imageY, int imageWidth, int imageHeight, int totalWidth, int totalHeight)
- {
- id = nextId++;
- neighbors = new HashSet();
- this.curWidth = this.origWidth = imageWidth;
- this.curHeight = this.origHeight = imageHeight;
- origData = data;
- this.imageX = imageX;
- this.imageY = imageY;
- this.totalWidth = totalWidth;
- this.totalHeight = totalHeight;
-
- // computing hash code:
- if (data != null) {
- int temp = 0;
- for(int i = 0; i < data.length; i++) {
- temp += data[i];
- }
- this.hash = temp;
- } else {
- this.hash = 0;
- }
- }
- /** Creates a new Piece.
- * @param data image data
- * @param imageX X position of image relative to entire puzzle
- * @param imageY Y position of image relative to entire puzzle
- * @param imageWidth width of original image
- * @param imageHeight height of original image
- * @param totalWidth the width of the entire picture
- * @param totalHeight the height of the entire picture
- * @param rotation initial rotation
- */
- public Piece(int[] data, int imageX, int imageY, int imageWidth, int imageHeight, int totalWidth, int totalHeight, int rotation)
- {
- this (data, imageX, imageY, imageWidth, imageHeight, totalWidth, totalHeight);
- forceSetRotation (rotation);
- }
- /**
- * A Copy Constructor.
- * @param p
- */
- public Piece(Piece p) {
- this(p.getOrigData(), p.getImageX(), p.getImageY(),
- p.getImageWidth(), p.getImageHeight(), p.getTotalWidth(), p.getTotalHeight(), p.getRotation());
- }
- /** Piece's unique id. */
- protected int id;
- /** Location in the image. */
- int imageX, imageY;
- /** Size of the entire image. */
- int totalWidth, totalHeight;
- /** Location in the image adjusted by current rotation. */
- int rotatedX, rotatedY;
-
- /** Pieces considered to be neighbors to this one. They are the only
- * ones that can be fitted to it.
- */
- protected Set neighbors;
-
- /** Original image size and data. */
- protected int origWidth, origHeight;
- int[] origData;
-
- /** Current size and data, taking rotation into account. */
- protected int curWidth, curHeight;
- int[] curData;
- /** Location in the puzzle panel. */
- int puzzleX, puzzleY;
- /** Translation from a piece's upper-left corner to the point last clicked on. */
- int transX, transY;
- /** constant hash code of the piece. */
- protected int hash;
- /** Image for this Piece. We're going to now try making this null for
- * non-atomic pieces. */
- Image image;
- /** This is measured in integer degrees, 0-359. 0 is unrotated.
- * 90 is 90 degrees clockwise, etc. */
- int rotation;
-
- // Accessors ------------------------------------------------------------
-
- /** Returns this piece's unique id. */
- public int getId() {return id;}
-
- /** Returns this Piece's current rotation. The rotation is given in
- * integer degrees clockwise, and will always be between 0 and 359
- * inclusive.
- */
- public int getRotation() { return rotation; }
-
- /** Sets this Piece's current rotation. The rotation is given in integer
- * degrees clockwise, and should always be between 0 and 359 inclusive.
- * If the new rotation is different, this Piece's image data will be
- * recomputed.
- * @throws IllegalArgumentException if rotation is not in [0,359]
- */
- public void setRotation (int rot)
- {
- if (rot == rotation) return;
- forceSetRotation (rot);
- }
-
- /** Sets this Piece's current rotation. Unlike setRotation(), this
- * method forces a recompute of the image.
- * @throws IllegalArgumentException if rotation is not in [0,359]
- */
- protected void forceSetRotation (int rot)
- {
- if ((rot < 0) || (rot > 359)) throw new IllegalArgumentException("invalid rotation: "+rot);
- // For now, allow only 0, 90, 180, 270.
- if (rot % 90 != 0) {
- int newRot = rot / 90;
- System.out.println ("unsupported rotation "+rot+"; using "+newRot+" instead" );
- rot = newRot;
- }
- rotation = rot;
- recomputeImageData();
- if (image != null) image.flush();
- image = Toolkit.getDefaultToolkit().createImage (
- new MemoryImageSource (curWidth,curHeight, curData, 0, curWidth));
- }
-
- /** Fulshes the image, unless it is null. */
- public void flushImage() {
- if (image!= null) {
- image.flush();
- }
- image = Toolkit.getDefaultToolkit().createImage (
- new MemoryImageSource (curWidth,curHeight, curData, 0, curWidth));
- }
-
- /** Sets this Piece's upper-left position relative to the upper-left
- *position of the JigsawPuzzle.
- */
- public void setPuzzlePosition (int x, int y)
- {
- this.puzzleX = x;
- this.puzzleY = y;
- }
-
- /** Returns this Piece's current height in pixels. This is the height of
- * the smallest rectangle containing all of this Piece's image data at
- * its current rotation.
- */
- public int getCurrentHeight() { return curHeight; }
-
- /** Returns this Piece's current width in pixels. This is the width of
- * the smallest rectangle containing all of this Piece's image data at
- * its current rotation.
- */
- public int getCurrentWidth() { return curWidth; }
-
- /** Returns the width of the entire picture. */
- public int getTotalWidth() { return totalWidth; }
-
- /** Returns the height of the entire picture. */
- public int getTotalHeight() { return totalHeight; }
-
- /** Returns this Piece's image height in pixels. This is the height of
- * the smallest rectangle containing all of this Piece's image data in
- * its original orientation.
- */
- public int getImageHeight() { return origHeight; }
-
- /** Returns this Piece's image width in pixels. This is the width of the
- * smallest rectangle containing all of this Piece's image data in its
- * original orientation.
- */
- public int getImageWidth() { return origWidth; }
-
- /** Returns this Piece's X position in the original image. */
- public int getImageX() { return imageX; }
-
- /** Returns this Piece's Y position in the original image. */
- public int getImageY() { return imageY; }
-
- /** Returns this Piece's X position in the original image, modified by
- * its current rotation. The origin is the center of rotation. */
- public int getRotatedX() { return rotatedX; }
-
- /** Returns this Piece's Y position in the original image, modified by
- * its current rotation. The origin is the center of rotation. */
- public int getRotatedY() { return rotatedY; }
-
- /** Returns this Piece's X position in the original image, modified by
- * the given rotation. */
- public int getRotatedX(int rotation) { return rotatedX; }
-
- /** Returns this Piece's Y position in the original image, modified by
- * the given rotation. */
- public int getRotatedY(int rotation) { return rotatedY; }
-
- /** Returns this Piece's X position in the puzzle. */
- public int getPuzzleX() { return puzzleX; }
-
- /** Returns this Piece's Y position in the puzzle. */
- public int getPuzzleY() { return puzzleY; }
-
- /** Returns thie Piece's transX - last pressed X position. */
- public int getTransX() {return transX; }
- public void setTransX(int x) {transX = x;}
-
- /** Returns thie Piece's transY - last pressed Y position. */
- public int getTransY() {return transY; }
- public void setTransY(int y) {transY = y;}
-
- public HashSet getNeighbors() {
- return (HashSet)neighbors;
- }
-
- public void setNeighbors(HashSet neighbors) {
- this.neighbors = neighbors;
- }
- /** Returns this Piece's current image. This will be the Piece's portion
- * of the original image, rotated by this Piece's current rotation.
- */
- public Image getImage () { return image; }
-
- /** Returns current piece's data */
- public int[] getCurrData() {return curData; }
- public void setCurrData(int[] data) { curData = data; }
- /** Returns original piece's data */
- public int[] getOrigData() {
- return this.origData;
- }
- public void setOrigData(int[] data) {
- this.origData = data;
- }
-
- /** Returns a hash value - by the current data */
- public int hashCode() {
- return hash+rotation;
- }
-
-
- /** Adds a Piece to this Piece's set of neighbors.
- * @throws NullPointerException if neighbor is null
- */
- public void addNeighbor (Piece neighbor)
- {
- if (neighbor == null) throw new NullPointerException ("null neighbor" );
- neighbors.add (neighbor);
- }
-
- /** Removes the given Piece from this Piece's set of neighbors. */
- public void removeNeighbor (Piece neighbor)
- {
- neighbors.remove (neighbor);
- }
-
- /** Moves this Piece to the given location, relative to the puzzle
- * panel's upper-left corner.
- */
- public void moveTo (int x, int y)
- {
- setPuzzlePosition (x, y);
- }
-
- /** Draws this Piece in the given Graphics object. The current image
- * will be drawn, at this Piece's current puzzle position. */
- protected void draw (Graphics g)
- {
- Image img = getImage();
- if (img != null) g.drawImage (img, getPuzzleX(), getPuzzleY(), null);
- }
-
- /** Returns whether this Piece currently contains the given point,
- * relative to the puzzle panel's upper-left corner.
- */
- public boolean contains (int x, int y)
- {
- int puzX = getPuzzleX();
- int puzY = getPuzzleY();
- int w = getCurrentWidth();
- int h = getCurrentHeight();
-
- return (puzX <= x) && (x <= (puzX+w-1)) && (puzY <= y) && (y <= (puzY+h-1)) &&
- (getAlpha(x-puzX, y-puzY) != 0);
- }
-
- /** Returns the alpha (transparency) value at the given coordinates in
- * the current image data.
- */
- protected int getAlpha (int x, int y)
- {
- int pixel = curData[y*curWidth + x];
- return (pixel >> 24) & 0xff;
- }
-
- /** Returns whether this piece is located and oriented close enough to
- * the given Piece to be fitted.
- */
- public boolean isCloseTo (Piece piece)
- {
- // Check if pieces are aligned
- int rot = getRotation();
- int rotD = Math.abs (piece.getRotation() - getRotation());
- rotD = Math.min (rotD, 360-rotD);
- if (rotD > rotClose) return false;
- // If we're here - pieces are aligned
- int puzXD = getPuzzleX() - piece.getPuzzleX();
- int puzYD = getPuzzleY() - piece.getPuzzleY();
- int rotXD = getRotatedX() - piece.getRotatedX(rot);
- int rotYD = getRotatedY() - piece.getRotatedY(rot);
- return (Math.abs(puzXD-rotXD) <= posClose) && (Math.abs(puzYD-rotYD) <= posClose) ;
-
- }
-
- // Joining pieces -------------------------------------------------------
-
- /** Checks whether any of this Piece's neighbors are located and oriented
- * close enough to be joined to this one.
- * @return an array of Pieces, or null if no neighbors were close enough;
- * if the array is non-null, the first Piece will be the new one;
- * subsequent Pieces will be the ones it was built from
- */
- public Piece[] join ()
- {
- ArrayList close = new ArrayList();
- Iterator iter = neighbors.iterator();
- while (iter.hasNext()) {
- Piece piece = (Piece) iter.next();
- if (piece.isCloseTo (this))
- {
- close.add (piece);
- }
- }
- if (close.size() == 0) return null;
- // We can't just return the new MultiPiece, because the JigsawPuzzle
- // needs to know what pieces the new one was formed from that are
- // currently in its list. These might include other MultiPieces, which
- // wouldn't be in the new Piece's subpiece list.
- Piece newPiece = MultiPiece.join (this, close);
- Piece[] ret = new Piece[close.size()+2];
- ret[0] = newPiece;
- ret[1] = this;
- this.image.flush();
- for (int i = 0; i < close.size(); i++) {
- Piece piece = (Piece) close.get(i);
- ret[i+2] = piece;
- piece.image.flush();
- }
- System.gc();
- return ret;
- }
-
-
- // 4-way rotation -------------------------------------------------------
- /** Sets this Piece's rotated position and size, based on its current
- * rotation. The entire puzzle is rotated about the origin, and then
- * translated so that its new upper left corner is at the origin. Each
- * piece's rotated position is then defined by its new upper left corner
- * in the rotated puzzle.
- */
- protected void setRotatedPosition()
- {
- int rot = getRotation();
- switch (rot) {
- case 0: rotatedX = imageX; rotatedY = imageY;
- curWidth = origWidth; curHeight = origHeight;
- break;
- case 90: rotatedX = totalHeight-imageY-origHeight;
- rotatedY = imageX;
- curWidth = origHeight; curHeight = origWidth;
- break;
- case 180: rotatedX = totalWidth -imageX-origWidth;
- rotatedY = totalHeight-imageY-origHeight;
- curWidth = origWidth; curHeight = origHeight;
- break;
- case 270: rotatedX = imageY;
- rotatedY = totalWidth -imageX-origWidth;
- curWidth = origHeight; curHeight = origWidth;
- break;
- default: System.out.println ("sRotPos() can't handle rotation: "+rot);
- }
- }
-
- /** Recomputes this Piece's current image data and size from its original
- * image data and rotation.
- */
- public void recomputeImageData()
- {
- setRotatedPosition();
- if (rotation == 0) {
- curData = (int[]) origData.clone();
- } else if (rotation == 90) {
- curData = new int[origData.length];
- for (int i = 0; i < curWidth; i++) {
- for (int j = 0; j < curHeight; j++) {
- try {
- curData[j*curWidth+i] = origData[(origHeight-i-1)*origWidth + j];
- } catch (ArrayIndexOutOfBoundsException ex) {
- //System.out.println ("ArrayIndexOutOfBoundsException" );
- //System.out.println (" olen="+origData.length+" clen="+curData.length);
- //System.out.println (" i="+i+" j="+j);
- //System.out.println (" orgW="+origWidth+" orgH="+origHeight);
- //System.out.println (" curW="+ curWidth+" curH="+ curHeight);
- //System.out.println (" cIdx="+ (j*curWidth+i)+" oIdx="+ ((origWidth-j-1)*origHeight + i));
- throw new NullPointerException();
- }
- }
- }
- } else if (rotation == 180) {
- curData = new int[origData.length];
- for (int i = 0; i < curWidth; i++) {
- for (int j = 0; j < curHeight; j++) {
- curData[j*curWidth+i] = origData[(origHeight-j-1)*origWidth + (origWidth-i-1)];
- }
- }
- } else if (rotation == 270) {
- curData = new int[origData.length];
- for (int i = 0; i < curWidth; i++) {
- for (int j = 0; j < curHeight; j++) {
- curData[j*curWidth+i] = origData[i*origWidth + (origWidth-j-1)];
- }
- }
- }
- image = Toolkit.getDefaultToolkit().createImage (
- new MemoryImageSource (curWidth,curHeight, curData, 0, curWidth));
- }
- }
|
Code :
- public class JigsawPuzzle extends JPanel implements Serializable
- {
- /**
- * Overriding origianl writeObject.
- * @param out
- * @throws IOException
- */
- /*private void writeObject(ObjectOutputStream out) throws IOException {
- Iterator iter = zOrder.iterator();
- while (iter.hasNext()) {
- Piece p = (Piece)iter.next();
- out.writeObject(p);
- }
- }*/
- /**
- * Overriding original readObject
- * @param in
- * @throws IOException
- * @throws ClassNotFoundException
- */
- /*private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
-
- OrderedHashtable zOrder = new OrderedHashtable();
-
- try {
- Piece p;
- while(true) {
- p = (Piece)in.readObject();
- zOrder.put(new Integer(p.getId()), p);
- }
- } catch(OptionalDataException e) {
- // Build the puzzle
- this.image = null;
- this.cutter = null;
- this.zOrder = zOrder;
- setOpaque (true);
- setFocusable(true);
- bgColor = 4;
- setBackground (bgColors[bgColor]);
- setCursor (NORMAL_CURSOR);
- setClearColor();
- addWiring();
- computePreferredSize();
- }
- }*/
- // Class constants ------------------------------------------------------
- // ### Allow background to be changed.
- // ### Allow these to be configured.
- // Keyboard commands
- public static final char ROTATE_LEFT = 'E';
- public static final char ROTATE_RIGHT = 'R';
- public static final char SHUFFLE = 'S';
- public static final char PREV_BG = 'V';
- public static final char NEXT_BG = 'B';
- public static final char CLEAR = 'C';
- // Available background colors
- public static final Color[] bgColors = {
- Color.BLACK,
- new Color ( 48, 0, 0),
- new Color ( 0, 48, 0),
- new Color ( 0, 0, 48),
- new Color ( 48, 48, 48),
- new Color ( 96, 0, 0),
- new Color ( 0, 96, 0),
- new Color ( 0, 0, 96),
- new Color ( 96, 96, 96),
- new Color (144, 0, 0),
- new Color ( 0,144, 0),
- new Color ( 0, 0,144),
- new Color (144,144,144),
- };
- public static final Color CLEAR_COLOR_W = new Color (255,255,255,48);
- public static final Color CLEAR_COLOR_B = new Color ( 0, 0, 0,48);
- public static final Cursor
- NORMAL_CURSOR = new Cursor (Cursor.DEFAULT_CURSOR),
- CLEAR_CURSOR = new Cursor (Cursor.CROSSHAIR_CURSOR);
- // Constructor, fields, and supporting methods --------------------------
- /** Creates a new JigsawPuzzle.
- * Implicitly - this is a single player game.
- * @param image the final picture
- * @param cutter the cut to use on the image
- *
- */
- public JigsawPuzzle (Image image, JigsawCutter cutter)
- {
- super (false);
- this.image = image;
- this.cutter = cutter;
- this.zOrder = new OrderedHashtable();
- computePreferredSize();
- setOpaque (true);
- setFocusable(true);
- bgColor = 4;
- setBackground (bgColors[bgColor]);
- setCursor (NORMAL_CURSOR);
- setClearColor();
- addWiring();
- }
- public JigsawPuzzle() {
- super (false);
- this.image = null;
- this.cutter = null;
- this.zOrder = new OrderedHashtable();
- computePreferredSize();
- setOpaque (true);
- setFocusable(true);
- bgColor = 4;
- setBackground (bgColors[bgColor]);
- setCursor (NORMAL_CURSOR);
- setClearColor();
- addWiring();
- }
- /**
- * Checks if puzzle is ready - in means of having the pieces.
- * @return true = the puzzle is ready (all pieces are cut). false = the puzzle is not ready (has no cut pieces yet).
- */
- public boolean isPuzzleReady() {
- return (!zOrder.isEmpty());
- }
- public boolean isImageExist() {
- return (image != null);
- }
- Image image, finishedImage;
- JigsawCutter cutter;
- Dimension prefSize;
- boolean mouseDown = false;
- boolean finished = false;
- boolean clearMode = false;
- // Last in list = topmost piece
- protected OrderedHashtable zOrder;
- int bgColor;
- int clearX0, clearY0, clearX1, clearY1;
- Color clearColor;
- int width;
- int height;
- // If a keyboard command can affect a piece, it'll be this one.
- // Typically, this piece should be last in zOrder, but you never know.
- Piece focusPiece;
- /**
- * To null to focus piece - used after a puzzle is replace
- *
- */
- public void nullFocusPiece() {
- focusPiece = null;
- }
- // Jigsaw Puzzle's properties:
- /**
- * Gets the image of the puzzle
- */
- public Image getImage() {
- return image;
- }
- /**
- * Gets the cutter of the puzzle.
- * @return JigsawCutter
- */
- public JigsawCutter getCutter() {
- return cutter;
- }
- /** @return OrderedHashtable of the puzzle's pieces */
- public OrderedHashtable getPieces() {
- return zOrder;
- }
- private void addWiring()
- {
- addMouseListener (new MouseAdapter() {
- public void mousePressed (MouseEvent e) {
- JigsawPuzzle.this.requestFocusInWindow();
- mousePressed0 (e);
- }
- public void mouseReleased(MouseEvent e) {
- mouseReleased0(e);
- }
- public void mouseClicked(MouseEvent e) {
- JigsawPuzzle.this.requestFocusInWindow();
- }
- });
- addMouseMotionListener (new MouseMotionAdapter() {
- public void mouseDragged (MouseEvent e) { mouseDragged0 (e); }
- });
- addKeyListener (new KeyAdapter() {
- public void keyTyped (KeyEvent e) { keyTyped0 (e); }
- });
- }
- // Accessors ------------------------------------------------------------
- /** Tells this puzzle to cut the image into pieces and randomize their
- * positions. This is a potentially time-consuming operation, and should
- * not be done in the AWT thread.
- */
- public void reset()
- {
- this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- // Add progress listener:
- JigsawProgressDialog progressDialog =
- new JigsawProgressDialog((JFrame)this.getTopLevelAncestor(), null);
- CuttingProgress listener = new CuttingProgress(progressDialog);
- cutter.addPieceCreatedListener(listener);
- Thread t = new Thread(new Runnable() {
- public void run() {
- zOrder = null;
- Piece[] pieces = cutter.cut (image);
- shuffle (pieces);
- }
- });
- t.start();
- progressDialog.setString("Création du puzzle..." );
- progressDialog.show();
- // Removing the progress listener:
- cutter.removePieceCreatedListener(listener);
- this.setCursor(null);
- this.repaint();
- }
- // Event handlers for the cutting process:
- private class CuttingProgress implements PieceCreatedListener {
- private JigsawProgressDialog progressDialog;
- public CuttingProgress(JigsawProgressDialog progressDialog) {
- this.progressDialog = progressDialog;
- }
- /**
- * Updates the maximum value of the progress bar
- */
- public void totalPiecesComputed(int totalPieces) {
- progressDialog.setMinimum(0);
- progressDialog.setMaximum(totalPieces);
- }
- /**
- * Advances the progress bar.
- * In case we reached the end of progress - closes the dialog.
- */
- public void pieceCreated(int currentCreated) {
- progressDialog.setValue(currentCreated);
- if (progressDialog.getValue() >= progressDialog.getMaximum()) {
- progressDialog.hide();
- }
- }
- }
- /** Move current pieces around randomly, randomize z-order, but don't
- * randomize rotation.
- */
- public void shuffle()
- {
- Piece[] pieces = new Piece[zOrder.size()];
- zOrder.toArray(pieces);
- shuffle (pieces);
- repaint();
- }
- // Component methods ----------------------------------------------------
- public Dimension getMaximumSize() { return getPreferredSize(); }
- public Dimension getMinimumSize() { return getPreferredSize(); }
- public Dimension getPreferredSize() { return prefSize; }
- /** Returns whether the pieces have been prepared for this puzzle. */
- public boolean isCut()
- {
- return zOrder != null;
- }
- protected void paintComponent (Graphics g)
- {
- super.paintComponent(g);
- if (zOrder == null) {
- return;
- }
- int x = 0, y = 0;
- Iterator iter = zOrder.iterator();
- while (iter.hasNext()) {
- Piece piece = (Piece) iter.next();
- piece.draw (g);
- }
- if (clearMode && mouseDown) {
- int cx = Math.min (clearX0, clearX1);
- int cy = Math.min (clearY0, clearY1);
- int cw = Math.abs (clearX0-clearX1);
- int ch = Math.abs (clearY0-clearY1);
- g.setColor (clearColor);
- g.fillRect (cx, cy, cw, ch);
- }
- if (finished && (finishedImage != null)) {
- Piece lastPiece = (Piece) zOrder.getFirst();
- x = lastPiece.getPuzzleX();
- y = lastPiece.getPuzzleY();
- g.drawImage (finishedImage, x, y, null);
- }
- }
- public void setClearMode (boolean flag)
- {
- clearMode = flag;
- setCursor (clearMode ? CLEAR_CURSOR : NORMAL_CURSOR);
- // Just in case this is done from outside
- if (!clearMode && mouseDown) clear();
- }
- // Private methods ------------------------------------------------------
- /** Ideally, the preferred area is roughly 1.5 times the area of the
- * image, and the preferred width is 5/3 of the preferred height.
- * However, if the result would be smaller than the image in either
- * dimension, it is enlarged to allow the image to fit.
- */
- private void computePreferredSize()
- {
- Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
- prefSize = screen;
- }
- // ### Should this be public?
- private void finish()
- {
- if (zOrder.size() != 1) return;
- finished = true;
- Piece lastPiece = (Piece) zOrder.getFirst();
- // Auto-rotate the puzzle to its correct position.
- lastPiece.setRotation (0);
- // Center the last piece in the middle of the panel.
- int prevX = lastPiece.getPuzzleX();
- int prevY = lastPiece.getPuzzleY();
- final int width = lastPiece.getImageWidth();
- final int height = lastPiece.getImageHeight();
- int curW = getWidth();
- int curH = getHeight();
- final int centerX = (curW - width ) / 2;
- final int centerY = (curH - height) / 2;
- lastPiece.moveTo (centerX, centerY);
- repaint(0, prevX, prevY, width, height);
- repaint(0, centerX, centerY, width, height);
- // If we have the original image - fade into it - otherwise - finish here:
- if (image == null) {
- return;
- }
- // Draw the original image on top of the last piece in increasing
- // opaqueness. This should make the pieces appear to fade into the
- // original image.
- final int[] data = new int [width*height];
- try {
- new PixelGrabber(image, 0,0, width, height, data, 0, width).grabPixels();
- } catch (InterruptedException ex) {
- System.out.println ("interrupted on finish grab" );
- }
- for (int i = 0; i < data.length; i++) {
- data[i] = data[i] & 0x00ffffff;
- }
- ActionListener fader = new ActionListener() {
- int trans = 0x00;
- public void actionPerformed (ActionEvent evt) {
- for (int i = 0; i < data.length; i++)
- {
- data[i] = (data[i] & 0x00ffffff) | (trans << 24);
- }
- if (finishedImage != null) finishedImage.flush();
- finishedImage = Toolkit.getDefaultToolkit().createImage (
- new MemoryImageSource (width, height, data, 0, width));
- repaint(0, centerX, centerY, width, height);
- if (trans < 0xff) {
- trans += 0x11;
- if (trans >= 0xff) trans = 0xff;
- Timer timer = new Timer (200, this);
- timer.setRepeats (false);
- timer.start();
- }
- }
- };
- Timer timer = new Timer (200, fader);
- timer.setRepeats (false);
- timer.start();
- }
- // Mouse event handling -------------------------------------------------
- private void mousePressed0 (MouseEvent e)
- {
- if (finished) return;
- mouseDown = true;
- if (clearMode) startClearRect(e);
- else grabPiece(e);
- }
- private void mouseDragged0 (MouseEvent e)
- {
- if (finished) return;
- if (clearMode) dragClearRect(e);
- else dragPiece(e);
- }
- private void mouseReleased0 (MouseEvent e)
- {
- if (finished) return;
- mouseDown = false;
- if (clearMode) finishClearRect(e);
- else releasePiece (focusPiece, e);
- }
- private void grabPiece (MouseEvent e)
- {
- int x = e.getX();
- int y = e.getY();
- focusPiece = null;
- ListIterator iter = zOrder.listIterator(zOrder.size());
- while ((focusPiece == null) && (iter.hasPrevious())) {
- Piece piece = (Piece) iter.previous();
- if (piece.contains (x, y)) {
- focusPiece = piece;
- iter.remove();
- }
- }
- if (focusPiece != null) {
- zOrder.put(new Integer(focusPiece.getId()), focusPiece);
- focusPiece.transX = x - focusPiece.getPuzzleX();
- focusPiece.transY = y - focusPiece.getPuzzleY();
- // The focusPiece might have moved up in Z-order. At worst, we have
- // to repaint its bounding rectangle.
- repaint(0, focusPiece.getPuzzleX(), focusPiece.getPuzzleY(),
- focusPiece.getCurrentWidth(), focusPiece.getCurrentHeight());
- }
- }
- private void dragPiece (MouseEvent e)
- {
- if (focusPiece == null) return;
- int prevX = focusPiece.getPuzzleX();
- int prevY = focusPiece.getPuzzleY();
- int prevW = focusPiece.getCurrentWidth();
- int prevH = focusPiece.getCurrentHeight();
- focusPiece.moveTo (e.getX()-focusPiece.transX, e.getY()-focusPiece.transY);
- // Repaint the focusPiece' previous and current bounding rects.
- repaint(0, prevX, prevY, prevW, prevH);
- repaint(0, focusPiece.getPuzzleX(), focusPiece.getPuzzleY(),
- focusPiece.getCurrentWidth(), focusPiece.getCurrentHeight());
- }
- public void releasePiece (Piece piece, MouseEvent e)
- {
- //System.out.println("In release piece of JigsawPuzzle" );
- if (piece == null) return;
- Piece[] result = piece.join();
- if (result != null) {
- Piece newPiece = result[0];
- for (int i = 1; i < result.length; i++)
- {
- Integer key = new Integer(result[i].getId());
- zOrder.remove(key);
- }
- zOrder.put(new Integer(newPiece.getId()), newPiece);
- focusPiece = newPiece;
- // Joined pieces may be of any size and number. Mouse release isn't
- // a terribly frequent event, so just repaint the whole thing. If
- // it's really necessary later, the thing to do would be to repaint
- // the bounding rect for every piece in the result array above.
- repaint();
- if (zOrder.size() == 1) finish();
- }
- }
- private void startClearRect (MouseEvent e)
- {
- clearX0 = e.getX();
- clearY0 = e.getY();
- }
- private void dragClearRect (MouseEvent e)
- {
- int prevX1 = clearX1;
- int prevY1 = clearY1;
- clearX1 = e.getX();
- clearY1 = e.getY();
- int x = Math.min (clearX0, prevX1);
- int y = Math.min (clearY0, prevY1);
- int w = Math.abs (clearX0-prevX1);
- int h = Math.abs (clearY0-prevY1);
- repaint (0, x,y,w,h);
- x = Math.min (clearX0, clearX1);
- y = Math.min (clearY0, clearY1);
- w = Math.abs (clearX0-clearX1);
- h = Math.abs (clearY0-clearY1);
- repaint (0, x,y,w,h);
- }
- private void finishClearRect (MouseEvent e)
- {
- clearX1 = e.getX();
- clearY1 = e.getY();
- int cx0 = Math.max (0, Math.min (clearX0, clearX1));
- int cy0 = Math.max (0, Math.min (clearY0, clearY1));
- int cx1 = Math.min (getWidth(), Math.max (clearX0, clearX1));
- int cy1 = Math.min (getHeight(),Math.max (clearY0, clearY1));
- Iterator iter = zOrder.iterator();
- while (iter.hasNext())
- {
- Piece piece = (Piece) iter.next();
- if (intersects (piece, cx0,cy0,cx1,cy1))
- shuffle (piece, cx0,cy0,cx1,cy1);
- }
- repaint();
- }
- /** Return whether the piece intersects with the rectangle defined by the
- * given points. ### Not perfect; returns true for some pieces that it
- * shouldn't. Ideally, it should grab the part of the Piece in the
- * rectangle, and search it for non-transparent pixels. Costly, so be
- * careful.
- */
- private boolean intersects (Piece piece, int x0, int y0, int x1, int y1)
- {
- int px = piece.getPuzzleX();
- int py = piece.getPuzzleY();
- int pw = piece.getCurrentWidth();
- int ph = piece.getCurrentHeight();
- int w = x1 - x0;
- int h = y1 - y0;
- Rectangle r = new Rectangle (x0,y0,w,h);
- Rectangle rp = new Rectangle (px,py,pw,ph);
- return r.intersects(rp);
- }
- static final Rectangle emptyRect = new Rectangle (0,0,0,0);
- /** Shuffle piece randomly, but keeping it out of the rectangle defined
- * by the given points. */
- private void shuffle (Piece piece, int x0, int y0, int x1, int y1)
- {
- // Make the rectangle denoting where the Piece could be placed in the
- // whole panel. Top point will be (0,0).
- int w = getWidth() - piece.getCurrentWidth();
- int h = getHeight() - piece.getCurrentHeight();
- // If w or h is negative, the piece is too big to be shuffled, so quit.
- if (w<0 || h<0) return;
- // Define the endpoints of the rectangle the Piece must avoid.
- int ax = Math.max (0, x0 - piece.getCurrentWidth());
- int ay = Math.max (0, y0 - piece.getCurrentHeight());
- int ah = y1 - ay;
- // Now define four rectangles forming the shape where the NW piece
- // corner could go. I'll use BorderLayout rectangles as a guide.
- Rectangle north = (ay==0) ? emptyRect : new Rectangle (0,0, w, ay);
- Rectangle south = (y1>=h) ? emptyRect : new Rectangle (0,y1+1, w, h-y1);
- Rectangle west = (ax==0 || ah==0) ? emptyRect : new Rectangle (0,ay, ax,ah);
- Rectangle east = (x1>=w || ah==0) ? emptyRect : new Rectangle (x1,ay, w-x1,ah);
- int nArea = north.width * north.height, sArea = south.width * south.height,
- wArea = west .width * west .height,
- eArea = east .width * east .height,
- totalArea = nArea + sArea + wArea + eArea;
- int rand = (int) (Math.random() * totalArea);
- rand -= nArea; if (rand<0) { shuffle (piece,north); return; }
- rand -= sArea; if (rand<0) { shuffle (piece,south); return; }
- rand -= wArea; if (rand<0) { shuffle (piece,west ); return; }
- shuffle (piece,east );
- }
- private void shuffle (Piece piece, Rectangle rect)
- {
- int dx = (int) (Math.random() * rect.width);
- int dy = (int) (Math.random() * rect.height);
- piece.moveTo (rect.x+dx, rect.y+dy);
- }
- // Keyboard event handling ----------------------------------------------
- public void keyTyped0 (KeyEvent e)
- {
- if (finished) return;
- char ch = Character.toUpperCase (e.getKeyChar());
- if (ch==ROTATE_LEFT) {
- rotatePiece (focusPiece, 270);
- }
- else if (ch==ROTATE_RIGHT) {
- rotatePiece (focusPiece, 90);
- }
- else if (ch==PREV_BG) prevBackground();
- else if (ch==NEXT_BG) nextBackground();
- // The following features are disabled when playing multi-players game
- else if (ch==CLEAR) toggleClearMode();
- else if (ch==SHUFFLE) shuffle();
- else return;
- }
- public Piece findPiece(int pieceId) {
- Piece remoteFocusPiece=null;
- Iterator iter = zOrder.iterator();
- while(iter.hasNext()) {
- remoteFocusPiece = (Piece)iter.next();
- if (remoteFocusPiece.getId()==pieceId) {
- // Piece Found
- return remoteFocusPiece;
- }
- }
- return null;
- }
- public void rotatePiece (Piece piece, int amount)
- {
- if (piece == null) return;
- int newRotation = piece.getRotation()+amount;
- newRotation %= 360;
- int prevW = piece.getCurrentWidth();
- int prevH = piece.getCurrentHeight();
- int prevX = piece.getPuzzleX();
- int prevY = piece.getPuzzleY();
- piece.setRotation (newRotation);
- // Make the piece appear to rotate about its center.
- // ### Feature: When the mouse is down, rotate about the cursor instead
- // of the center.
- int centerX = prevX + prevW/2;
- int centerY = prevY + prevH/2;
- int currW = piece.getCurrentWidth();
- int currH = piece.getCurrentHeight();
- int currX = centerX - currW/2;
- int currY = centerY - currH/2;
- piece.moveTo (currX, currY);
- repaint(0, prevX, prevY, prevW, prevH);
- repaint(0, currX, currY, currW, currH);
- }
- private void shuffle(Piece[] pieces)
- {
- zOrder = null;
- // Copy pieces in random order into zOrder, and randomize their
- // positions.
- OrderedHashtable zOrder0 = new OrderedHashtable();
- int lastIdx = pieces.length-1;
- while (lastIdx > 0) {
- int pIdx = (int) (Math.random() * (lastIdx+1));
- Piece piece = pieces[pIdx];
- piece.setPuzzlePosition ((int) (Math.random() * (width - piece.getCurrentWidth())) ,
- (int) (Math.random() * (height - piece.getCurrentHeight())) );
- zOrder0.put(new Integer(piece.getId()), piece);
- if (pIdx != lastIdx) {
- Piece temp = pieces[lastIdx];
- pieces[lastIdx] = pieces[pIdx];
- pieces[pIdx] = temp;
- }
- lastIdx--;
- }
- zOrder0.put(new Integer(pieces[0].getId()), pieces[0]);
- finished = false;
- if (finishedImage != null) {
- finishedImage.flush();
- finishedImage = null;
- }
- zOrder = zOrder0;
- }
- private void prevBackground()
- {
- bgColor--;
- if (bgColor < 0) bgColor = bgColors.length-1;
- setBackground (bgColors[bgColor]);
- setClearColor();
- repaint();
- }
- private void nextBackground()
- {
- bgColor++;
- if (bgColor >= bgColors.length) bgColor = 0;
- setBackground (bgColors[bgColor]);
- setClearColor();
- repaint();
- }
- private void toggleClearMode()
- {
- if (mouseDown) return; // can't toggle clear mode while dragging
- setClearMode (!clearMode);
- }
- private void clear()
- {
- // ### stub
- }
- private void setClearColor()
- { clearColor = getClearColor(); }
- private Color getClearColor()
- { return isBright (bgColors[bgColor]) ? CLEAR_COLOR_B : CLEAR_COLOR_W; }
- private boolean isBright (Color c)
- {
- float[] hsb = new float[3];
- Color.RGBtoHSB (c.getRed(),c.getGreen(),c.getBlue(), hsb);
- return hsb[2] > 0.5;
- }
- /**
- * Retrieves a piece of the puzzle
- * @param key The piece's key - of the piece to retrieve
- * @return Returns the appropraite piece reference - or null, if no piece with the specified key was found.
- */
- public Piece getPiece(int key) {
- Piece p = (Piece)zOrder.get(new Integer(key));
- return p;
- }
- public void setHeight(int height) {
- this.height= height;
- }
- public void setWidth(int width) {
- this.width = width;
- }
- }
|
|