Monday 26 December 2016

Chapter 15 Exercise 35, Introduction to Java Programming, Tenth Edition Y. Daniel LiangY.

15.35 (Animation: self-avoiding random walk) Revise the preceding exercise to display the walk step by step in an animation, as shown in Figure 15.37c and  d.

import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;

import java.util.ArrayList;

public class PaneCollection {


    public static void drawArrowLine(double x1, double y1, double x2,   double y2, Pane pane) {
        drawArrowLine(x1, y1, x2, y2, pane, 15);
    }

    public static void drawArrowLine(double x1, double y1, double x2,   double y2, Pane pane, int length) {
        drawArrowLine(new Line(x1, y1, x2, y2), pane, length);
    }

    public static void drawArrowLine(Line line, Pane pane) {
        drawArrowLine(line, pane, 15);
    }

    public static void drawArrowLine(Line line, Pane pane, int length) {
        ObservableList<Node> list = pane.getChildren();

        double arctan = Math.atan(slope(line));
        double set45 = (line.getStartX() > line.getEndX()) ? 1.57 / 2 : -1.57 * 1.5;

        list.add(line);
        list.add(new Line(line.getEndX(), line.getEndY(),
                (line.getEndX() + Math.cos(arctan - set45) * length),
                (line.getEndY() + Math.sin(arctan - set45) * length)));
        list.add(new Line(line.getEndX(), line.getEndY(),
                (line.getEndX() + Math.cos(arctan + set45) * length),
                (line.getEndY() + Math.sin(arctan + set45) * length)));
    }

    public static double slope(Line line) {
        return (line.getStartY() - line.getEndY()) / (line.getStartX() - line.getEndX());
    }

    public static double distance(double x1, double y1, double x2, double y2) {

        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    public static double distance(Line line) {
        return distance(line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY());
    }

    public static MyPoint getCenterPoint(Line line) {

        return new MyPoint(
                (line.getStartX() + line.getEndX()) / 2,
                (line.getStartY() + line.getEndY()) / 2);
    }

    public static void drawPointCounter(Pane pane, Point2D[] points) {
        int counter = 1;

        for (Point2D point : points) {
            Circle temp = new Circle(point.getX(), point.getY(), 5, Color.TRANSPARENT);
            Text text = new Text(point.getX(), point.getY(), "" + counter++);
            pane.getChildren().addAll(temp, text);
        }
    }

    public static boolean containsPoint(ArrayList<Point2D> points, double x, double y) {
        for (Point2D p : points) {
            if (p.getX() == x && p.getY() == y) return true;
        }
        return false;
    }

    public static boolean removePoint(ArrayList<Point2D> points, double x, double y) {

        int index = 0;
        for (Point2D p : points) {
            if (p.getX() == x && p.getY() == y) {
                points.remove(index);
                return true;
            }
            index++;
        }
        return false;
    }

    public static Line copyLine(Line l) {
        return new Line(l.getStartX(), l.getStartY(), l.getEndX(), l.getEndY());
    }


}

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.ArrayList;

public class Exercise_35 extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        RandomWalkPane pane = new RandomWalkPane();

        Button btStart = new Button("Start");
        btStart.setOnAction(e -> pane.play());

        HBox hButtons = new HBox(btStart);
        hButtons.setAlignment(Pos.CENTER);
        hButtons.setPadding(new Insets(10, 10, 10, 10));

        BorderPane borderPane = new BorderPane(pane, null, null, hButtons, null);
        borderPane.setMinWidth(400);
        borderPane.setMinHeight(400);
        primaryStage.setScene(new Scene(borderPane));
        primaryStage.setTitle("Random Walk");

        pane.setTranslateY(10);
        pane.setTranslateX(10);

        primaryStage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);

    }

    private class RandomWalkPane extends Pane {

        private double size = 20;
        private double squareCount = 11;
        private double w = size * squareCount;
        private double h = w;

        private Point2D centerP;
        private Point2D currentP;

        private boolean hasHitBorder;

        // All valid points
        ArrayList<Point2D> points = new ArrayList<>();
        // Line Path
        ArrayList<Line> lines = new ArrayList<>(); // keeps track of the entire path

        Timeline timeline;

        private RandomWalkPane() {
            setPrefWidth(w);
            setPrefHeight(h);

            if (squareCount % 2 == 0) {
                centerP = new Point2D(w / 2, h / 2);
            } else {
                centerP = new Point2D(w / 2 - (size/2), h / 2 - (size/2));
            }
//                centerP = new Point2D(w / 2, h / 2);

            currentP = centerP;
            // above is fine

            drawLayout();
            getChildren().add(new Circle(centerP.getX(), centerP.getY(), 2));
            // Generate path until it hits a border or a dead end
            while (nextPath());

            // Generate Polyline
            timeline = new Timeline(new KeyFrame(Duration.seconds(0.5), e-> nextLine()));

            timeline.setCycleCount(lines.size());
        }



        private void drawLayout() {

            // horizontal lines and adding possible points to array
            for (int i = 0; i <= squareCount; i++) {
                Line line = new Line(0, i * size, w, i * size);
                line.setOpacity(0.1);

                // add all possible points
                for (int j = 0; j <= squareCount; j++) {
                    double x = j * size;
                    double y = i * size;

                    points.add(new Point2D(x, y));

                }
                getChildren().add(line);
            }

            // since we start at the center
            // remove center point from points
            if (PaneCollection.containsPoint(points, centerP.getX(), centerP.getY())) {
                PaneCollection.removePoint(points, centerP.getX(), centerP.getY());
            }

            // vertical line
            for (int i = 0; i <= squareCount; i++) {
                Line line = new Line(i * size, 0, i * size, h);

                line.setOpacity(0.1);
                getChildren().add(line);
            }
        }

        private boolean nextPath() {
            // get possible paths
            Point2D[] possiblePs = new Point2D[4];
            possiblePs[0] = new Point2D(currentP.getX(), currentP.getY() - size); // up
            possiblePs[1] = new Point2D(currentP.getX(), currentP.getY() + size); // down
            possiblePs[2] = new Point2D(currentP.getX() - size, currentP.getY()); // left
            possiblePs[3] = new Point2D(currentP.getX() + size, currentP.getY()); // right

            boolean hasMoved = false;
            boolean[] isUsed = new boolean[possiblePs.length];

            for (int i = 0; i < 4;) {
                int ranIndex = (int) (Math.random() * 4);

                if (!isUsed[ranIndex]) {
                    isUsed[ranIndex] = true;
                    i++;
                    Point2D p = possiblePs[ranIndex];
                    if (PaneCollection.containsPoint(points, p.getX(), p.getY())) {

                        // draw path
                        Line line = new Line(
                                currentP.getX(), currentP.getY(),
                                p.getX(), p.getY());
                        currentP = p; // update current Point
                        lines.add(line);

                        // remove point from point tracker
                        PaneCollection.removePoint(points, p.getX(), p.getY());

                        // make the new point the current point
                        // update hasMoved
                        hasMoved = true;
                        checkBorder(currentP);

                        break; // break out of loop early
                    }

                }
            }

            return hasMoved; // return moved status
        }

        private void checkBorder(Point2D p) {
            double x = p.getX();
            double y = p.getY();

            if (x <= 0 || x >= w) hasHitBorder = true;
            if (y <= 0  || y >= h) hasHitBorder = true;
        }


        private int lineIndex = 0;
        private void nextLine() {
            getChildren().add(lines.get(lineIndex++));
        }

        private void play(){
            timeline.play();
        }
    }
}

No comments :

Post a Comment