@@ 30,100 30,59 @@ import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pools;
import net.dermetfan.jigsawPuzzle.Constants;
import net.dermetfan.jigsawPuzzle.utils.PolygonRegionDrawable;
-import net.dermetfan.utils.libgdx.math.GeometryUtils;
import net.dermetfan.utils.libgdx.scene2d.Scene2DUtils;
/** represents a puzzle and manages {@link Piece Pieces}
* @author dermetfan */
public class JigsawPuzzle {
- private final Array<Piece> placedPieces, remainingPieces;
+ private final Array<Piece> pieces;
public JigsawPuzzle() {
- remainingPieces = new Array<>(Piece.class);
- placedPieces = new Array<>(Piece.class);
+ pieces = new Array<>(Piece.class);
}
/** @param pieces the amount of pieces that will probably be in this puzzle */
public JigsawPuzzle(int pieces) {
- remainingPieces = new Array<>(pieces);
- placedPieces = new Array<>(pieces);
- }
-
- /** @param pieces the {@link #remainingPieces remaining pieces} */
- public JigsawPuzzle(Piece... pieces) {
- remainingPieces = new Array<>(pieces);
- placedPieces = new Array<>(pieces.length);
+ this.pieces = new Array<>(pieces);
}
- /** Solves the puzzle by {@link #place(Piece) placing} all {@link #remainingPieces remaining pieces}.
- * @param relativeTo the piece relative to which the puzzle should be solved */
- public void solve(Piece relativeTo) {
- if(placedPieces.contains(relativeTo, true) || remainingPieces.contains(relativeTo, true))
- for(Piece piece : remainingPieces) {
- if(piece == relativeTo)
- continue;
- place(piece);
- }
- else
- throw new IllegalArgumentException("the reference piece is not part of the puzzle");
- }
-
- /** moves all {@link #placedPieces} to {@link #remainingPieces} */
- public void unsolve() {
- remainingPieces.addAll(placedPieces);
- placedPieces.clear();
- placedPieces.ensureCapacity(remainingPieces.size); // just for performance
+ /** @param pieces the {@link #pieces} */
+ public JigsawPuzzle(Piece... pieces) {
+ this.pieces = new Array<>(pieces);
}
- /** Places the given piece in its spot on the puzzle. If no piece was {@link #placedPieces placed} yet, it's position is assumed to be correct (hence it will simply be moved to {@link #placedPieces})
- * @param piece the piece to automatically place in its spot on the puzzle */
- public void place(Piece piece) {
- if(!remainingPieces.removeValue(piece, true))
- throw new IllegalArgumentException("the given piece is not remaining and hence cannot be automatically placed");
- Piece ref = placedPieces.size > 0 ? placedPieces.first() : piece;
- piece.snap(ref);
- placedPieces.add(piece);
- }
-
- /** @param piece the piece to add to {@link #remainingPieces} */
- public void addRemaining(Piece piece) {
- placedPieces.removeValue(piece, true);
- remainingPieces.add(piece);
+ /** solves the puzzle by letting all {@link #pieces} {@link Piece#place(Piece) snap} into their spot
+ * @param relativeTo the piece relative to which the puzzle should be solved */
+ public void solve(Piece relativeTo) {
+ if(!pieces.contains(relativeTo, true))
+ throw new IllegalArgumentException("the reference piece is not part of the puzzle");
+ for(Piece piece : pieces) {
+ if(piece == relativeTo)
+ continue;
+ piece.place(relativeTo);
+ }
}
- /** @return if the puzzle is solved */
- public boolean isSolved() {
- return remainingPieces.size == 0;
+ /** @param piece the piece to add to {@link #pieces} */
+ public void add(Piece piece) {
+ if(!pieces.contains(piece, true))
+ pieces.add(piece);
}
- /** Checks if the given piece is correctly positioned. Always returns true if no piece was placed yet.
- * @param piece the piece which position to check
- * @param tolerance the distance by which the piece is allowed to be off
- * @return if the given piece is correctly placed in relation to {@link #placedPieces} */
- public boolean isCorrectlyPlaced(Piece piece, float tolerance) {
- return placedPieces.size <= 0 || piece.inRelationTo(placedPieces.first(), tolerance);
- }
-
- /** usually not necessary, {@link #isSolved()} should return the right result
- * @param tolerance the distance by which each piece is allowed to be off
- * @return if the {@link #placedPieces} are really correctly placed */
- public boolean checkPlaced(float tolerance) {
- Piece reference = placedPieces.first();
- for(Piece piece : placedPieces)
- if(!piece.inRelationTo(reference, tolerance))
+ /** @param tolerance the distance by which each piece is allowed to be off
+ * @return if the puzzle is solved */
+ public boolean isSolved(float tolerance) {
+ Piece reference = pieces.first();
+ for(Piece piece : pieces)
+ if(!piece.isPlacedCorrectly(reference, tolerance))
return false;
return true;
}
- /** @return the {@link #placedPieces} */
- public Array<Piece> getPlacedPieces() {
- return placedPieces;
- }
-
- /** @return the {@link #remainingPieces} */
- public Array<Piece> getRemainingPieces() {
- return remainingPieces;
+ /** @return the {@link #pieces} */
+ public Array<Piece> getPieces() {
+ return pieces;
}
public Source createSource(final Group board, final DragAndDrop dnd) {
@@ 181,11 140,10 @@ public class JigsawPuzzle {
Actor dragged = payload.getDragActor();
Scene2DUtils.addAtStageCoordinates(dragged, board);
if(dragged instanceof Piece) {
- Piece piece = (Piece) dragged;
- if(isCorrectlyPlaced(piece, Constants.tolerance)) {
- if(remainingPieces.contains(piece, true)) // TODO remove this condition (not the body!) when Puzzle doesn't know the difference between remaining and placed Pieces anymore
- place(piece); // snap it into its perfect position in relation to some already placed piece
- if(isSolved() && solvedCallback != null)
+ Piece piece = (Piece) dragged, ref = pieces.first();
+ if(piece.isPlacedCorrectly(ref, Constants.tolerance)) {
+ piece.place(ref); // snap it into its perfect position in relation to some already placed piece
+ if(isSolved(Constants.tolerance) && solvedCallback != null)
solvedCallback.run();
}
}
@@ 197,7 155,7 @@ public class JigsawPuzzle {
* @author dermetfan */
public static class Piece extends Image {
- /** the position of the piece on the puzzle (the minX and minY of its vertices) */
+ /** the position of the piece on the puzzle (the {@link PolygonRegionDrawable#getPolygonX() minX} and {@link PolygonRegionDrawable#getPolygonY() minY} of its vertices) */
private float slotX, slotY;
public Piece(PolygonRegionDrawable drawable) {
@@ 224,27 182,27 @@ public class JigsawPuzzle {
if(hit == this && drawable != null) {
tmpPolygon.setVertices(drawable.getRegion().getVertices());
tmpPolygon.setPosition(-slotX, -slotY);
- if(!tmpPolygon.contains(x / getWidth() * GeometryUtils.width(tmpPolygon.getVertices()), y / getHeight() * GeometryUtils.height(tmpPolygon.getVertices())))
+ if(!tmpPolygon.contains(x / getWidth() * drawable.getPolygonWidth(), y / getHeight() * drawable.getPolygonHeight()))
return null;
}
return hit;
}
- /** @param ref the piece in relation to which to snap into this piece's spot */
- public void snap(Piece ref) {
- Vector2 refPuzzlePoint = Pools.obtain(Vector2.class).set(ref.getX(), ref.getY()).sub(ref.slotX, ref.slotY);
+ /** @param reference the piece in relation to which to this piece should snap in its spot */
+ public void place(Piece reference) {
+ Vector2 refPuzzlePoint = Pools.obtain(Vector2.class).set(reference.getX(), reference.getY()).sub(reference.slotX, reference.slotY);
setPosition(refPuzzlePoint.x + slotX, refPuzzlePoint.y + slotY);
Pools.free(refPuzzlePoint);
}
- /** @param ref the piece in which relation this piece should be
- * @param tolerance the tolerance in the x and y axis
- * @return if this piece is in relation to the given piece with the given tolerance */
- public boolean inRelationTo(Piece ref, float tolerance) {
+ /** @param reference the piece in relation to which this piece's position should be checked
+ * @param tolerance the distance by which each piece is allowed to be off
+ * @return if this piece is placed correctly in relation to the given reference piece with the given tolerance */
+ public boolean isPlacedCorrectly(Piece reference, float tolerance) {
// get puzzle points (bottom left corner of the puzzle)
- Vector2 puzzlePoint = Pools.obtain(Vector2.class).set(-slotX, -slotY), refPuzzlePoint = Pools.obtain(Vector2.class).set(-ref.slotX, -ref.slotY);
+ Vector2 puzzlePoint = Pools.obtain(Vector2.class).set(-slotX, -slotY), refPuzzlePoint = Pools.obtain(Vector2.class).set(-reference.slotX, -reference.slotY);
localToStageCoordinates(puzzlePoint);
- ref.localToStageCoordinates(refPuzzlePoint);
+ reference.localToStageCoordinates(refPuzzlePoint);
// see if they're the same
boolean rel = puzzlePoint.epsilonEquals(refPuzzlePoint, tolerance);
@@ 83,7 83,7 @@ public class PlayScreen extends ScreenAd
float nextX = 0, tallest = 0;
for(FileHandle psh : Assets.puzzlePSHs(level)) { // set up the pieces on the bank
Piece piece = new Piece(new PolygonRegionDrawable(Assets.manager.get(psh.path(), PolygonRegion.class)));
- puzzle.addRemaining(piece);
+ puzzle.add(piece);
board.addActor(piece);
piece.setX(nextX);
nextX += piece.getWidth();
@@ 99,4 99,14 @@ public class PolygonRegionDrawable exten
return polygonY;
}
+ /** @return the {@link #polygonWidth} */
+ public float getPolygonWidth() {
+ return polygonWidth;
+ }
+
+ /** @return the {@link #polygonHeight} */
+ public float getPolygonHeight() {
+ return polygonHeight;
+ }
+
}