CS计算机代考程序代写 Java gui cache javaFx package comp1110.ass1.gui;

package comp1110.ass1.gui;

import comp1110.ass1.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

/**
* This class implements a GUI for the Walk the Dog game.
*
* You should not need to modify any code in this file,
* but you are welcome to read the code and use any part
* of it in your second assignment.
*
* Some elements of this class exist just to provide
* examples of how you might want to solve problems in
* your assignment.
*/
public class Game extends Application {

private static final int SQUARE_SIZE = 100;
private static final int MARGIN_X = 60;
private static final int MARGIN_Y = 30;
private static final int BOARD_WIDTH = 450;
private static final int BOARD_HEIGHT = 450;
private static final int BOARD_MARGIN = 25;
private static final int BOARD_Y = MARGIN_Y;
private static final int BOARD_X = MARGIN_X;
private static final int PLAY_AREA_Y = BOARD_Y + BOARD_MARGIN;
private static final int PLAY_AREA_X = BOARD_X + BOARD_MARGIN;
private static final int GAME_WIDTH = BOARD_X + BOARD_WIDTH + MARGIN_X + 280;
private static final int GAME_HEIGHT = BOARD_Y + BOARD_HEIGHT + MARGIN_Y + 100;

/* node groups */
private final Group root = new Group();
private final Group gpieces = new Group();
private final Group permanentPieces = new Group();
private final Group solution = new Group();
private final Group board = new Group();
private final Group controls = new Group();

/* where to find media assets */
private static final String URI_BASE = “assets/”;
private static final String BASEBOARD_URI = Game.class.getResource(URI_BASE + “baseboard.png”).toString();

/* Pieces */
DogOwnerPiece[] pieces = new DogOwnerPiece[4];

/* Tree */
GUIPiece tree;

int current_piece = -1; // leash length of current piece, -1 indicates no piece is selected

/* the difficulty slider */
private final Slider difficulty = new Slider();

/* message on completion */
private final Text completionText = new Text(“Well \ndone!”);

private final Text instructionText = new Text(“? to display solution\n” +
“Click and drag to move, scroll or PgUp/PgDn to rotate.\n” +
“A piece may only be moved if all other pieces are \nplaced validly or off the board.”);

/* The underlying game */
WalkTheDog walkTheDogGame;

/* Define a drop shadow effect that we will apply to unplaced pieces */
private static DropShadow dropShadow;

/* Static initializer to initialize dropShadow */ {
dropShadow = new DropShadow();
dropShadow.setOffsetX(4.0);
dropShadow.setOffsetY(4.0);
dropShadow.setColor(Color.color(0, 0, 0, .4));
}

class Offset {
public int x;
public int y;
Offset(int x, int y) {
this.x = x;
this.y = y;
}
}

public void createSolutionPiece(String placement) {
GUIPiece dog;
GUIPiece owner;
Leash leash;
int leashLength = 0;
Location dogLoc = new Location(placement.charAt(0) – ‘0’, placement.charAt(1) – ‘0’);
Location ownerLoc = new Location();
if (placement.length() == 4) {
ownerLoc = new Location(placement.charAt(2) – ‘0’, placement.charAt(3) – ‘0’);
leashLength = dogLoc.manhattanDistance(ownerLoc);
}
dog = new GUIPiece(“dog_” + getColour(leashLength), dogLoc);
solution.getChildren().add(dog);
if (placement.length() == 4) {
owner = new GUIPiece(“owner_” + getColour(leashLength), ownerLoc);
leash = new Leash(dog.getLayoutX(), dog.getLayoutY(), owner.getLayoutX(), owner.getLayoutY());
if (dogLoc.getX() != ownerLoc.getX() && dogLoc.getY() != ownerLoc.getY()) {
boolean is_treex_dogx = walkTheDogGame.getTree().getX() == dogLoc.getX();
leash.setAroundTree(dog.getLayoutX(), dog.getLayoutY(), owner.getLayoutX(), owner.getLayoutY(), is_treex_dogx);
} else
leash.snapToHome();
solution.getChildren().add(owner);
leash.addToSolution();
}
}

/**
* Assuming valid owner and dog locations, return whether or not the tree is
* underneath the leash of the piece
* @param dogLoc
* @param ownerLoc
* @return True if the tree fall under the leash, False otherwise.
*/
public boolean isTreeUnderLeash(Location dogLoc, Location ownerLoc) {
if (walkTheDogGame.getTree().offBoard() || (ownerLoc.offBoard() && dogLoc.offBoard()))
return false;
// Remove negatives to allow for correct encoding of placement string
Location dLoc = removeNegatives(dogLoc);
Location oLoc = removeNegatives(ownerLoc);
Location tLoc = removeNegatives(walkTheDogGame.getTree());
Location[] leash = WalkTheDog.findLeash(dLoc +””+ oLoc, tLoc);
for (int i = 1; i < leash.length - 1; i++) { Location l = leash[i]; if (l.equals(tLoc)) return true; } return false; } /** Translate x and y coordinates of loc up by 2 to remove negatives. */ public Location removeNegatives(Location loc) { return new Location(loc.getX() +3, loc.getY() +3); } /* Graphical representations of pieces */ class GUIPiece extends ImageView { final double homeX, homeY; /** * Construct a particular permanent piece * given a name and board location */ GUIPiece(String name, Location loc) { Image image = new Image(Game.class.getResource(URI_BASE + name + ".png").toString()); setImage(image); setFitHeight(SQUARE_SIZE-4); setFitWidth(SQUARE_SIZE-4); this.homeX = (loc.getX()) * SQUARE_SIZE + PLAY_AREA_X; this.homeY = (loc.getY()) * SQUARE_SIZE + PLAY_AREA_Y; setLayoutX(this.homeX); setLayoutY(this.homeY); } /** * Construct a particular permanent piece * given a name and coordinates */ GUIPiece(String name, double homeX, double homeY) { Image image = new Image(Game.class.getResource(URI_BASE + name + ".png").toString()); setImage(image); setFitHeight(SQUARE_SIZE-4); setFitWidth(SQUARE_SIZE-4); this.homeX = homeX; this.homeY = homeY; setLayoutX(homeX); setLayoutY(homeY); } } public String getColour(Piece piece) { return getColour(piece.getLeashLength()); } public String getColour(int leashLength) { if (leashLength == 3) return "red"; if (leashLength == 2) return "yellow"; if (leashLength == 1) return "blue"; return "green"; } class DogOwnerPiece { DraggablePiece dog; DraggablePiece owner; Leash leash; boolean hasOwner = false; Piece piece; DogOwnerPiece (Piece piece, int homeX, int homeY) { this.piece = piece; if (piece .getLeashLength() != 0) { this.hasOwner = true; this.dog = new DraggablePiece(homeX, homeY, "dog_" + getColour(piece), true, piece.getLeashLength()); this.owner = new DraggablePiece(homeX, homeY - SQUARE_SIZE * piece.getLeashLength(), "owner_" + getColour(piece), false, (piece).getLeashLength()); this.leash = new Leash(this.dog.getLayoutX(), this.dog.getLayoutY(), this.owner.getLayoutX(), this.owner.getLayoutY()); this.dog.addNeighbour(owner, leash); this.owner.addNeighbour(dog, leash); } else { this.dog = new DraggablePiece(homeX, homeY, "dog_green", true, 0); } } public void makePiece() { gpieces.getChildren().add(this.dog); if (this.hasOwner) { gpieces.getChildren().add(this.owner); leash.makePiece(); } } public void snapToHome() { this.dog.snapToHome(); this.dog.setEffect(dropShadow); if (this.hasOwner) { this.owner.snapToHome(); this.owner.setEffect(dropShadow); this.leash.snapToHome(); } current_piece = -1; } /** Returns whether or not the piece currently wrapped around a tree */ public boolean isWrapped() { Location dogLoc = this.dog.getBoardPosition(this.dog.getLayoutX(), this.dog.getLayoutY()); Location ownerLoc = this.owner.getBoardPosition(this.owner.getLayoutX(), this.owner.getLayoutY()); return wrapped(dogLoc, ownerLoc); } public boolean wrapped(Location loc1, Location loc2) { if (walkTheDogGame.getTree().offBoard()) return false; return loc1.getX() != loc2.getX() && loc1.getY() != loc2.getY(); } /** Assuming the piece is currently around a tree, return which direction is it wrapped around. True if wrapped clockwise (according to loc1), False if anticlockwise */ public boolean wrappedClockwise(Location loc1, Location loc2) { Location t = walkTheDogGame.getTree(); if (loc1.getX() == t.getX()) { if (loc1.getY() > loc2.getY())
return loc2.getX() > t.getX();
else
return loc2.getX() < t.getX(); } else { if (loc1.getX() > loc2.getX()) {
return loc2.getY() < t.getY(); } else { return loc2.getY() > t.getY();
}
}
}

/**
* Rotate the piece in the indicated direction, bending around a tree if necessary.
* @param clockwise which direction should the piece be rotated
* @param dog True if the dog is the pivot, False if the owner is the pivot
*/
public void rotate(boolean clockwise, boolean dog) {
Location dogLoc = this.dog.getBoardPosition(this.dog.getLayoutX(), this.dog.getLayoutY());
Location ownerLoc = this.owner.getBoardPosition(this.owner.getLayoutX(), this.owner.getLayoutY());
Location pivotLoc = dog ? dogLoc : ownerLoc;
Location rotateLoc = dog ? ownerLoc : dogLoc;
DraggablePiece rotatePiece = dog ? this.owner : this.dog;

if (!this.wrapped(pivotLoc, rotateLoc)) {
if (isTreeUnderLeash(pivotLoc, rotateLoc) && (this.owner.onBoard() || this.dog.onBoard())) {
Offset offset = this.rotateSimple(clockwise, walkTheDogGame.getTree(), rotateLoc);
rotatePiece.setLayoutX(offset.x * SQUARE_SIZE + rotatePiece.getLayoutX());
rotatePiece.setLayoutY(offset.y * SQUARE_SIZE + rotatePiece.getLayoutY());
boolean is_treex_dogx = walkTheDogGame.getTree().getX() == pivotLoc.getX();
this.leash.setAroundTree(this.dog.getLayoutX(), this.dog.getLayoutY(), this.owner.getLayoutX(), this.owner.getLayoutY(), dog == is_treex_dogx);
} else {
Offset offset = this.rotateSimple(clockwise, pivotLoc, rotateLoc);
rotatePiece.setLayoutX(offset.x * SQUARE_SIZE + rotatePiece.getLayoutX());
rotatePiece.setLayoutY(offset.y * SQUARE_SIZE + rotatePiece.getLayoutY());
this.leash.setStraight(this.dog.getLayoutX(), this.dog.getLayoutY(), this.owner.getLayoutX(), this.owner.getLayoutY());
}
} else {
this.straighten(dog);
if (this.wrappedClockwise(pivotLoc, rotateLoc) == clockwise) {
rotateLoc = rotatePiece.getBoardPosition(rotatePiece.getLayoutX(), rotatePiece.getLayoutY());
Offset offset = this.rotateSimple(clockwise, pivotLoc, rotateLoc);
rotatePiece.setLayoutX(offset.x * SQUARE_SIZE + rotatePiece.getLayoutX());
rotatePiece.setLayoutY(offset.y * SQUARE_SIZE + rotatePiece.getLayoutY());
this.leash.setStraight(this.dog.getLayoutX(), this.dog.getLayoutY(), this.owner.getLayoutX(), this.owner.getLayoutY());
}
}
}

/**
* Return the offset of the ‘rotate’ location from the ‘pivot’ location after a
* rotation in the direction indicated by ‘clockwise’
* @param clockwise True for clockwise rotation, False for anticlockwise rotation
* @param pivot The location of the pivot
* @param rotate The location to be rotated
* @return The offset of the rotate location from pivot location after a rotation
*/
public Offset rotateSimple(boolean clockwise, Location pivot, Location rotate) {
int x;
int y;
int leashLength = pivot.manhattanDistance(rotate);
if (rotate.getY() == pivot.getY()) {
x = pivot.getX();
if (rotate.getX() < pivot.getX()) clockwise = !clockwise; y = pivot.getY() + toInt(clockwise) * leashLength; } else { y = pivot.getY(); if (rotate.getY() > pivot.getY())
clockwise = !clockwise;
x = pivot.getX() + toInt(clockwise) * leashLength;
}
return new Offset(x – rotate.getX(), y – rotate.getY());
}

public int toInt(boolean b){
return (b) ? 1 : -1;
}

/**
* Straightens the leash of the piece, assuming the piece has a leash.
*
* @param fromDog True if the leash should be straighted from the perspective of the Dog,
* False if the leash should be straighted from the perspective of the Owner.
*/
public void straighten(boolean fromDog) {
Offset orientation = this.leash.getOrientation(fromDog);
DraggablePiece movePiece = fromDog ? this.owner : this.dog;
DraggablePiece pivotPiece = fromDog ? this.dog : this.owner;
movePiece.setLayoutX(pivotPiece.getLayoutX() + orientation.x * this.piece.getLeashLength());
movePiece.setLayoutY(pivotPiece.getLayoutY() + orientation.y * this.piece.getLeashLength());
this.leash.setStraight(this.dog.getLayoutX(), this.dog.getLayoutY(), this.owner.getLayoutX(), this.owner.getLayoutY());
}

/**
* Determines whether or not the current position of the piece is valid
* @return whether the current placement is valid
*/
public boolean isValidPlacement() {
Location dogLoc = this.dog.getBoardPosition(this.dog.getLayoutX(), this.dog.getLayoutY());
String owner = “”;
if (this.hasOwner) {
Location ownerLoc = this.owner.getBoardPosition(this.owner.getLayoutX(), this.owner.getLayoutY());
owner = ownerLoc + “”;
}
return walkTheDogGame.isPlacementValid(this.piece, dogLoc + “” + owner);
}

/**
* Adds piece to the backend game, removes drop shadows and checks completion.
* Also sets current_piece to -1 allowing other pieces to be dragged.
*/
public void place() {
Location dogLoc = this.dog.getBoardPosition(this.dog.getLayoutX(), this.dog.getLayoutY());
String ownerLoc = “”;
if (this.hasOwner) {
ownerLoc = “”+this.owner.getBoardPosition(this.owner.getLayoutX(), this.owner.getLayoutY());
this.owner.setEffect(null);
}
this.piece.placePiece(walkTheDogGame, dogLoc +””+ ownerLoc);
this.dog.setEffect(null);
current_piece = -1;
checkCompletion();
}

/**
* Removes the piece from the backend game and adds drop shadows
*/
public void remove() {
this.dog.setEffect(dropShadow);
// if piece is placed
if (this.piece.getDogLoc().getX() != -1)
this.piece.removePiece(walkTheDogGame);
if (this.hasOwner)
this.owner.setEffect(dropShadow);
}

}

/**
* Returns whether or not the piece with the given leash length can move.
* A piece can move if all other pieces are either off the board or in valid
* placements on the board.
*/
public boolean canMove(int leashLength) {
return current_piece == leashLength || current_piece == -1;
}

class Leash {
double dhomeX, dhomeY;
double ohomeX, ohomeY;
Line dogLeash;
Line ownerLeash;

Leash(double dogX, double dogY, double ownerX, double ownerY) {
this.dhomeX = dogX + SQUARE_SIZE/2;
this.dhomeY = dogY + SQUARE_SIZE/2;
this.ohomeX = ownerX + SQUARE_SIZE/2;
this.ohomeY = ownerY + SQUARE_SIZE/2;
dogLeash = new Line();
dogLeash.setStrokeWidth(5);
ownerLeash = new Line();
ownerLeash.setStrokeWidth(5);
dogLeash.setMouseTransparent(true);
ownerLeash.setMouseTransparent(true);
}

public void makePiece() {
gpieces.getChildren().add(this.dogLeash);
gpieces.getChildren().add(this.ownerLeash);
this.dogLeash.toFront();
this.ownerLeash.toFront();
}

public void addToSolution() {
solution.getChildren().add(this.dogLeash);
solution.getChildren().add(this.ownerLeash);
this.dogLeash.toFront();
this.ownerLeash.toFront();
}

public void translateLeash(double x, double y, double x2, double y2, boolean dog_first) {
Line l1 = dog_first ? dogLeash : ownerLeash;
Line l2 = dog_first ? ownerLeash : dogLeash;
l1.setLayoutX(x + SQUARE_SIZE/2);
l1.setLayoutY(y + SQUARE_SIZE/2);
l2.setLayoutX(x2 + SQUARE_SIZE/2);
l2.setLayoutY(y2 + SQUARE_SIZE/2);
this.dogLeash.toFront();
this.ownerLeash.toFront();
}

/**
* Set the leash around tree. The position of the tree is indicated by the
* @param dog_x
* @param dog_y
* @param owner_x
* @param owner_y
* @param is_treex_dogx
*/
public void setAroundTree(double dog_x, double dog_y, double owner_x, double owner_y, boolean is_treex_dogx) {
this.dogLeash.setLayoutX(dog_x + SQUARE_SIZE/2);
this.dogLeash.setLayoutY(dog_y + SQUARE_SIZE/2);
this.ownerLeash.setLayoutX(owner_x + SQUARE_SIZE/2);
this.ownerLeash.setLayoutY(owner_y + SQUARE_SIZE/2);
if (is_treex_dogx) {
this.dogLeash.setEndX(0);
this.dogLeash.setEndY(owner_y – dog_y);
this.ownerLeash.setEndX(dog_x – owner_x);
this.ownerLeash.setEndY(0);
}
else {
this.ownerLeash.setEndX(0);
this.ownerLeash.setEndY(dog_y – owner_y);
this.dogLeash.setEndX(owner_x – dog_x);
this.dogLeash.setEndY(0);
}
this.dogLeash.toFront();
this.ownerLeash.toFront();
}

/** Straighten the leash */
public void setStraight(double dog_x, double dog_y, double owner_x, double owner_y) {
this.dogLeash.setLayoutX(dog_x + SQUARE_SIZE/2);
this.dogLeash.setLayoutY(dog_y + SQUARE_SIZE/2);
this.ownerLeash.setLayoutX(owner_x + SQUARE_SIZE/2);
this.ownerLeash.setLayoutY(owner_y + SQUARE_SIZE/2);
this.dogLeash.setEndX(owner_x – dog_x);
this.dogLeash.setEndY(owner_y – dog_y);
this.ownerLeash.setEndX(0);
this.ownerLeash.setEndY(0);
this.dogLeash.toFront();
this.ownerLeash.toFront();
}

/**
* Return the direction the leash points from the dog or owner
* @param fromDog whether or not the direction should be returned from the dog or owner.
* @return An unit offset in the relevant direction
*/
public Offset getOrientation(boolean fromDog) {
Line l = fromDog ? dogLeash : ownerLeash;
Offset ans = new Offset(0, 0);
if (l.getEndX() > 0) // East
ans.x = SQUARE_SIZE;
if (l.getEndX() < 0) // West ans.x = -SQUARE_SIZE; if (l.getEndY() > 0) // North
ans.y = SQUARE_SIZE;
if (l.getEndY() < 0) // South ans.y= -SQUARE_SIZE; return ans; } public void snapToHome() { dogLeash.setLayoutX(dhomeX); dogLeash.setLayoutY(dhomeY); ownerLeash.setLayoutX(ohomeX); ownerLeash.setLayoutY(ohomeY); dogLeash.setEndX(ohomeX - dhomeX); dogLeash.setEndY(ohomeY - dhomeY); ownerLeash.setEndX(0); ownerLeash.setEndY(0); this.dogLeash.toFront(); this.ownerLeash.toFront(); } } /** * This class extends ImageView with the capacity for it to be dragged and dropped, * and snap-to-grid. */ class DraggablePiece extends GUIPiece { double mouseOffsetX, mouseOffsetY; double xdiff, ydiff; boolean hasNeighbour = false; boolean isDog; DraggablePiece neighbour; Leash leash; int leashLength; /** * Construct a draggable piece */ DraggablePiece(double homeX, double homeY, String name, boolean isDog, int leashLength) { super(name, homeX, homeY); this.leashLength = leashLength; this.isDog = isDog; setEffect(dropShadow); /* event handlers */ setOnMousePressed(event -> { // mouse press indicates begin of drag
requestFocus(); // Listen to key presses
if (canMove(this.leashLength)) {
hideCompletion();
DogOwnerPiece piece = pieces[this.leashLength];
piece.remove();
if (piece.hasOwner && piece.isWrapped()) {
piece.straighten(this.isDog);
}

current_piece = this.leashLength;
mouseOffsetX = this.getLayoutX() – event.getSceneX();
mouseOffsetY = this.getLayoutY() – event.getSceneY();

if (this.hasNeighbour) {
xdiff = this.getLayoutX() – neighbour.getLayoutX();
ydiff = this.getLayoutY() – neighbour.getLayoutY();
}
}
});
setOnMouseDragged(event -> {
if (canMove(this.leashLength)) {
DogOwnerPiece piece = pieces[this.leashLength];
// straighten owner if necessary
if (piece.hasOwner) {
Location loc1 = this.getBoardPosition(this.getLayoutX(), this.getLayoutY());
Location loc2 = this.neighbour.getBoardPosition(this.neighbour.getLayoutX(), this.neighbour.getLayoutY());
Location treeLoc = walkTheDogGame.getTree();
if (piece.isWrapped()) {
// no longer over tree
if (!((loc1.getX() == treeLoc.getX() && loc2.getY() == treeLoc.getY()) || (loc2.getX() == treeLoc.getX() && loc1.getY() == treeLoc.getY())))
piece.straighten(this.isDog);
}
}
this.toFront();
if (this.hasNeighbour) {
xdiff = this.getLayoutX() – neighbour.getLayoutX();
ydiff = this.getLayoutY() – neighbour.getLayoutY();
this.neighbour.toFront();
}
this.setLayoutX(event.getSceneX() + mouseOffsetX);
this.setLayoutY(event.getSceneY() + mouseOffsetY);
if (this.hasNeighbour) {
neighbour.setLayoutX(this.getLayoutX() – xdiff);
neighbour.setLayoutY(this.getLayoutY() – ydiff);
leash.translateLeash(getLayoutX(), getLayoutY(), getLayoutX() – xdiff, getLayoutY() – ydiff, isDog);
}
event.consume();
}
});
setOnMouseReleased(event -> { // drag is complete
if (canMove(this.leashLength)) {
if (this.hasNeighbour) {
xdiff = this.getLayoutX() – neighbour.getLayoutX();
ydiff = this.getLayoutY() – neighbour.getLayoutY();
}
this.snapToBoard();
if (pieces[this.leashLength].isValidPlacement()) {
pieces[this.leashLength].place();
}
}
});

setOnScroll(event -> {
if(event.getDeltaY() != 0.0)
scroll(event.getDeltaY() > 0.0);
});

setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.PAGE_UP)
scroll(true);
if (event.getCode() == KeyCode.PAGE_DOWN)
scroll(false);
});
}

/**
* Set pointers to neighbouring dog/owner and leash if necessary
* @param neighbour The neighbouring piece
* @param leash The associated leash
*/
public void addNeighbour(DraggablePiece neighbour, Leash leash){
this.neighbour = neighbour;
this.leash = leash;
this.hasNeighbour = true;
}

/**
* Updates the position, drop shadow and back end of the game after rotating the
* piece in the direction indicated.
* @param clockwise which direction to rotate around the pivot (this)
*/
public void scroll(boolean clockwise) {
if (canMove(this.leashLength) && this.hasNeighbour && this.leashLength != 0) {
hideCompletion();
current_piece = this.leashLength;
DogOwnerPiece piece = pieces[this.leashLength];
piece.remove();
this.toFront();
neighbour.toFront();
piece.rotate(clockwise, isDog);
// 0nly try to place piece if mouse has been released.
if ((getLayoutX() – PLAY_AREA_X) % SQUARE_SIZE == 0 && (getLayoutY() – PLAY_AREA_Y) % SQUARE_SIZE == 0) {
Location thisLoc = getBoardPosition(getLayoutX(), getLayoutY());
Location neighbourLoc = getBoardPosition(neighbour.getLayoutX(), neighbour.getLayoutY());
if (this.onBoard()) {
if (isDog && walkTheDogGame.isDogLocationValid(“” + thisLoc))
this.setEffect(null);
if (!isDog && walkTheDogGame.isOwnerLocationValid(“” + thisLoc))
this.setEffect(null);
} if (this.neighbour.onBoard()) {
String placement = isDog ? thisLoc + “” + neighbourLoc : neighbourLoc + “” + thisLoc;
if (walkTheDogGame.isLeashValid(placement, this.leashLength)) {
if (!isDog && walkTheDogGame.isDogLocationValid(“” + neighbourLoc)) {
this.neighbour.setEffect(null);
}
if (isDog && walkTheDogGame.isOwnerLocationValid(“” + neighbourLoc)) {
this.neighbour.setEffect(null);
}
}
}
if (piece.isValidPlacement()) {
piece.place();
}
}
}
}

/**
* Snap the piece to the nearest grid position if it is over the grid
* and in a valid placement.
* Update drop shadows accordingly.
*/
private void snapToBoard() {
DogOwnerPiece piece = pieces[this.leashLength];
if (onBoard()){
int gridX = snapXtoGrid(getLayoutX());
int gridY = snapYtoGrid(getLayoutY());
if (isDog) {
if (walkTheDogGame.isDogLocationValid(“”+getBoardPosition(gridX, gridY))) {
snapLayoutToGrid(gridX, gridY);
this.setEffect(null);
if (this.hasNeighbour) {
neighbour.setLayoutX(this.getLayoutX() – xdiff);
neighbour.setLayoutY(this.getLayoutY() – ydiff);
leash.translateLeash(getLayoutX(), getLayoutY(), neighbour.getLayoutX(), neighbour.getLayoutY(), isDog);
}
} else
piece.snapToHome();
} else {
if (walkTheDogGame.isOwnerLocationValid(“”+getBoardPosition(gridX, gridY))) {
snapLayoutToGrid(gridX, gridY);
this.setEffect(null);
neighbour.setLayoutX(this.getLayoutX() – xdiff);
neighbour.setLayoutY(this.getLayoutY() – ydiff);
leash.translateLeash(getLayoutX(), getLayoutY(), neighbour.getLayoutX(), neighbour.getLayoutY(), isDog);
} else
piece.snapToHome();
}
} else
piece.snapToHome();
}

/**
* Given an x location, snap it to the appropriate grid location
* @param layoutX the x location
* @return the x location snapped to the appropriate grid location
*/
private int snapXtoGrid(double layoutX) {
int n = (int) (layoutX – PLAY_AREA_X + SQUARE_SIZE/2 + 10*SQUARE_SIZE)/SQUARE_SIZE;
return PLAY_AREA_X + (n – 10) * SQUARE_SIZE;
}

/**
* Given a y location, snap it to the appropriate grid location
* @param layoutY the y location
* @return the y location snapped to the appropriate grid location plus the peg offset
*/
private int snapYtoGrid(double layoutY) {
int n = (int) (layoutY – PLAY_AREA_Y + SQUARE_SIZE/2 + 10*SQUARE_SIZE)/SQUARE_SIZE;
return PLAY_AREA_Y + (n-10) * SQUARE_SIZE;
}

/**
* Set the x and y locations of this graphical element to locations that
* are snapped to the grid.
* @param layoutX an x-location to be used to snap to
* @param layoutY a y0location to be used to snap to
*/
private void snapLayoutToGrid(double layoutX, double layoutY) {
setLayoutX(layoutX);
setLayoutY(layoutY);
}

/**
* @return true if the tile is on the board
*/
private boolean onBoard() {
return getLayoutX() > (PLAY_AREA_X – (SQUARE_SIZE / 2)) && (getLayoutX() < (PLAY_AREA_X + 3.5 * SQUARE_SIZE)) && getLayoutY() > (PLAY_AREA_Y – (SQUARE_SIZE / 2)) && (getLayoutY() < (PLAY_AREA_Y + 3.5 * SQUARE_SIZE)); } /** * Snap the tile to home. */ private void snapToHome() { this.setLayoutX(homeX); this.setLayoutY(homeY); } /** * Convert from x and y coordinates to a Location number on * the Walk the Dog board. * @param x the x position * @param y the y position * @return the corresponding Location */ public Location getBoardPosition(double x, double y) { int x2 = (snapXtoGrid(x) - PLAY_AREA_X) / SQUARE_SIZE; int y2 = (snapYtoGrid(y) - PLAY_AREA_Y) / SQUARE_SIZE; return new Location(x2, y2); } } /** * Set up event handlers for the main game * * @param scene The Scene used by the game. */ private void setUpHandlers(Scene scene) { /* create handlers for key press and release events */ scene.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.Q) {
Platform.exit();
event.consume();
} else if (event.getCode() == KeyCode.SLASH) {
solution.setOpacity(1.0);
solution.toFront();
gpieces.setOpacity(0);
event.consume();
}
});
scene.setOnKeyReleased(event -> {
if (event.getCode() == KeyCode.SLASH) {
solution.setOpacity(0);
solution.toBack();
gpieces.setOpacity(1.0);
event.consume();
}
});
}

/**
* Set up the group that represents the solution (and make it transparent)
*
* @param solution The solution as an array of chars.
*/
private void makeSolution(String solution) {
this.solution.getChildren().clear();

if (solution.length() == 0)
return;

if (solution.length() != 14) {
throw new IllegalArgumentException(“Solution incorrect length: ” + solution);
}
for (Piece piece : walkTheDogGame.getPieces())
piece.removePiece(walkTheDogGame);
for (int i = 0; i < solution.length(); i+=4) { if (solution.length() == i + 2) createSolutionPiece(solution.substring(i, i+2)); else createSolutionPiece(solution.substring(i, i+4)); } this.solution.setOpacity(0); } /** * Set up the group that represents the places that make the board */ private void makeBoard() { board.getChildren().clear(); ImageView baseboard = new ImageView(); baseboard.setImage(new Image(BASEBOARD_URI)); baseboard.setFitWidth(BOARD_WIDTH); baseboard.setFitHeight(BOARD_HEIGHT); baseboard.setLayoutX(BOARD_X-2); baseboard.setLayoutY(BOARD_Y-2); board.getChildren().add(baseboard); board.toBack(); } /** * Set up each of the dog owner pieces */ private void makePieces() { gpieces.getChildren().clear(); DogOwnerPiece piece; for (int i = 0; i < 4; i++) { if (i == 0) piece = new DogOwnerPiece(walkTheDogGame.getPiece(i), BOARD_X +BOARD_WIDTH+BOARD_MARGIN, BOARD_Y + BOARD_MARGIN-4); else piece = new DogOwnerPiece(walkTheDogGame.getPiece(i), BOARD_X +BOARD_WIDTH+ (i-1)*SQUARE_SIZE+BOARD_MARGIN, BOARD_HEIGHT - SQUARE_SIZE); pieces[i] = piece; piece.makePiece(); } gpieces.toFront(); } private void makePermanentPieces() { permanentPieces.getChildren().clear(); if (!walkTheDogGame.getTree().offBoard()) { tree = new GUIPiece("tree", walkTheDogGame.getTree()); permanentPieces.getChildren().add(tree); } if (!walkTheDogGame.getCat1().offBoard()) { permanentPieces.getChildren().add(new GUIPiece("cat1", walkTheDogGame.getCat1())); } if (!walkTheDogGame.getCat2().offBoard()) { permanentPieces.getChildren().add(new GUIPiece("cat2", walkTheDogGame.getCat2())); } for (Location ownerLoc : walkTheDogGame.getRequiredOwnerLocs()) { permanentPieces.getChildren().add(new GUIPiece("owner", ownerLoc)); } for (Location dogLoc : walkTheDogGame.getRequiredDogLocs()) { permanentPieces.getChildren().add(new GUIPiece("dog", dogLoc)); } permanentPieces.toFront(); } /** * Put all of the tiles back in their home position */ private void resetPieces() { gpieces.toFront(); for (DogOwnerPiece piece : pieces) { piece.snapToHome(); } } /** * Create the controls that allow the game to be restarted and the difficulty * level set. */ private void makeControls() { Button button = new Button("Restart"); button.setLayoutX(BOARD_X + BOARD_MARGIN + 320); button.setLayoutY(GAME_HEIGHT - 55); button.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent e) {
restart();
}
});
Button button2 = new Button(“New Game”);
button2.setLayoutX(BOARD_X + BOARD_MARGIN + 220);
button2.setLayoutY(GAME_HEIGHT – 55);
button2.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent e) {
newGame();
}
});
controls.getChildren().add(button);
controls.getChildren().add(button2);

difficulty.setMin(1);
difficulty.setMax(4);
difficulty.setValue(0);
difficulty.setShowTickLabels(true);
difficulty.setShowTickMarks(true);
difficulty.setMajorTickUnit(1);
difficulty.setMinorTickCount(0);
difficulty.setSnapToTicks(true);

difficulty.setLayoutX(BOARD_X + BOARD_MARGIN + 70);
difficulty.setLayoutY(GAME_HEIGHT – 50);
controls.getChildren().add(difficulty);

final Label difficultyCaption = new Label(“Difficulty:”);
difficultyCaption.setTextFill(Color.GREY);
difficultyCaption.setLayoutX(BOARD_X + BOARD_MARGIN);
difficultyCaption.setLayoutY(GAME_HEIGHT – 50);
controls.getChildren().add(difficultyCaption);
}

/**
* Create the message to be displayed when the player completes the puzzle.
*/
private void makeCompletion() {
completionText.setFill(Color.BLACK);
completionText.setEffect(dropShadow);
completionText.setCache(true);
completionText.setFont(Font.font(“Arial”, FontWeight.EXTRA_BOLD, 80));
completionText.setLayoutX(550);
completionText.setLayoutY(250);
completionText.setTextAlignment(TextAlignment.CENTER);
root.getChildren().add(completionText);
}

/**
* Create the message to be displayed when the player completes the puzzle.
*/
private void makeInstructions() {
instructionText.setFill(Color.BLACK);
instructionText.setCache(true);
instructionText.setFont(Font.font(“Arial”, 15));
instructionText.setLayoutX(480);
instructionText.setLayoutY(520);
instructionText.setTextAlignment(TextAlignment.CENTER);
root.getChildren().add(instructionText);
}

/**
* Show the completion message
*/
private void showCompletion() {
completionText.toFront();
completionText.setOpacity(1);
}

/**
* Hide the completion message
*/
private void hideCompletion() {
completionText.toBack();
completionText.setOpacity(0);
}

/**
* Check game completion and update status
*/
private void checkCompletion() {
WalkTheDog checkCompletionGame = new WalkTheDog(walkTheDogGame.getObjective());
if (checkCompletionGame.isSolution(walkTheDogGame.getPlacements())) {
showCompletion();
}
}
/**
* Start a new game, resetting everything as necessary
*/
private void newGame(Objective objective) {
try {
hideCompletion();
if (objective == null) {
walkTheDogGame = new WalkTheDog((int) difficulty.getValue() – 1);
} else {
walkTheDogGame = new WalkTheDog(objective);
}
makePermanentPieces();
String sol = walkTheDogGame.solve();
if (sol != null) {
makeSolution(sol);
}
makePieces();
} catch (IllegalArgumentException e) {
System.err.println(“Uh oh. ” + e);
e.printStackTrace();
Platform.exit();
}
resetPieces();
}
private void newGame() {
newGame(null);
}

/**
* Restart this game, creating a new game with the same objective.
*/
private void restart() {
newGame(walkTheDogGame.getObjective());
}

@Override
public void start(Stage primaryStage) {
primaryStage.setTitle(“Walk the Dog”);
Scene scene = new Scene(root, GAME_WIDTH, GAME_HEIGHT);

/* add each of the graphical elements */
root.getChildren().add(gpieces);
root.getChildren().add(permanentPieces);
root.getChildren().add(board);
root.getChildren().add(solution);
root.getChildren().add(controls);
setUpHandlers(scene);
makeBoard();
makeControls();
makeCompletion();
makeInstructions();

/* initialize a new game */
newGame();

/* finalize things for JavaFX, ready to show the window */
primaryStage.setScene(scene);
primaryStage.show();
}
}