***15.34 (模拟:自回避随机漫步)
在一个网格中的自回避漫步是指从一个点到另一点的过程中,不重复两次访问一个点。自回避漫步已经广泛应用在物理、化学和数学学科中。它们可以用来模拟像溶剂和聚合物这样的链状物。编写一个程序,显示一个从中心点出发到边界点结束的随机路径,如图15-37a所示,或者在一个尽头点结束(即该点被四个已经访问过的点包围),如图15- 37b所示。假设网格的大小是16×16
***15.35 (动画:自回避随机漫步)
修改上一个练习题,在一个动画中逐步地显示漫步,如图15-37c和图15-37d所示
- 习题思路
- 新建一个Pane,新建一个Rectangle表示网格的外围
- 每隔一段距离绘制一条虚线,绘制16条,横竖都画
- 设置一个Start按钮并添加到新建的HBox中,
- 新建一个BorderPane,按下时触发画线方法,把Pane设置在中心,把HBox设置在底部
- 新建一个画线方法,设置四个boolean参数代表上下左右是否都可以前进,如果都为false则退出
- (画线方法内部)随机产生一个数(0~3),按照相应的位置将线条的终点坐标进行调整,如果终点坐标到达边界则终止
- 添加动画的方式很简单,输入下面的语句并在按钮按下时调用animation.play()方法
EventHandler<ActionEvent> eventHandler = e -> DrawLine(); Timeline animation = new Timeline(new KeyFrame(Duration.millis(300),eventHandler));
代码示例:编程练习题15_35SelfAvoidanceRandomWalk.java
package chapter_15;
import java.util.ArrayList;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
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.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class 编程练习题15_35SelfAvoidanceRandomWalk extends Application{
EventHandler<ActionEvent> eventHandler = e -> DrawLine();
Timeline animation = new Timeline(new KeyFrame(Duration.millis(300),eventHandler));
int startX = 160,startY = 160;
int endX = 160,endY = 160;
Pane pane = new Pane();
ArrayList<String> point = new ArrayList<>();
boolean canStart = true;
@Override
public void start(Stage primaryStage) throws Exception {
Rectangle r = new Rectangle(1, 1, 320, 320);
r.setFill(Color.WHITE);
r.setStroke(Color.GRAY);
pane.getChildren().add(r);
for(int i = 1;i < 16;i++) {
Line lineH = new Line(0, i*20+1,320,i*20+1);
Line lineV = new Line(i*20+1,0 ,i*20+1, 320);
lineH.getStrokeDashArray().addAll(3.0, 4.0); // 设置虚线的样式,3表示实线段的长度,4表示空段的长度
lineV.getStrokeDashArray().addAll(3.0, 4.0); // 设置虚线的样式,3表示实线段的长度,4表示空段的长度
lineH.setStroke(Color.GRAY);
lineV.setStroke(Color.GRAY);
pane.getChildren().addAll(lineH,lineV);
}
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER);
Button btStart = new Button("Start");
btStart.setOnAction(e ->{
if(canStart)
animation.play();
});
hBox.getChildren().add(btStart);
point.add(startX+" "+startY);
animation.setCycleCount(Timeline.INDEFINITE);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(pane);
borderPane.setBottom(hBox);
Scene scene = new Scene(borderPane, 320, 360);
primaryStage.setTitle("编程练习题15_35SelfAvoidanceRandomWalk");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
boolean up = true;
boolean down = true;
boolean left = true;
boolean right = true;
public void DrawLine() {
if(point.contains(startX+" "+(startY-20))) {up = false;}
if(point.contains(startX+" "+(startY+20))) {down = false;}
if(point.contains((startX-20)+" "+startY)) {left = false;}
if(point.contains((startX+20)+" "+startY)) {right = false;}
if(!up&&!down&&!left&&!right) {animation.stop();canStart = false;}
int random;
do {
random = (int) (Math.random() * 4);
} while ((random == 0 && !up) || (random == 1 && !down) || (random == 2 && !left) || (random == 3 && !right));
if(random == 0) {//上
endY = startY-20;
}
else if(random == 1) {//下
endY = startY+20;
}
else if(random == 2) {//左
endX = startX-20;
}
else if(random == 3) {//右
endX = startX+20;
}
Line l = new Line(startX,startY,endX,endY);
l.setStroke(Color.RED);
pane.getChildren().add(l);
startX = endX;
startY = endY;
point.add(startX+" "+startY);
if (endX <= 0 || endY <= 0 || endX >= 320 || endY >= 320) {
animation.stop();
canStart = false;
return; // 可选:如果已经停止动画,则退出方法
}
}
}
15.34题可以通过35题注释部分代码得到
package chapter_15;
import java.util.ArrayList;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
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.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class 编程练习题15_34SelfAvoidanceRandomWalk extends Application{
//EventHandler<ActionEvent> eventHandler = e -> DrawLine();
//Timeline animation = new Timeline(new KeyFrame(Duration.millis(300),eventHandler));
int startX = 160,startY = 160;
int endX = 160,endY = 160;
Pane pane = new Pane();
ArrayList<String> point = new ArrayList<>();
boolean canStart = true;
@Override
public void start(Stage primaryStage) throws Exception {
Rectangle r = new Rectangle(1, 1, 320, 320);
r.setFill(Color.WHITE);
r.setStroke(Color.GRAY);
pane.getChildren().add(r);
for(int i = 1;i < 16;i++) {
Line lineH = new Line(0, i*20+1,320,i*20+1);
Line lineV = new Line(i*20+1,0 ,i*20+1, 320);
lineH.getStrokeDashArray().addAll(3.0, 4.0); // 设置虚线的样式,3表示实线段的长度,4表示空段的长度
lineV.getStrokeDashArray().addAll(3.0, 4.0); // 设置虚线的样式,3表示实线段的长度,4表示空段的长度
lineH.setStroke(Color.GRAY);
lineV.setStroke(Color.GRAY);
pane.getChildren().addAll(lineH,lineV);
}
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER);
Button btStart = new Button("Start");
btStart.setOnAction(e ->{
if(canStart)DrawLine();
//animation.play();
});
hBox.getChildren().add(btStart);
point.add(startX+" "+startY);
//animation.setCycleCount(Timeline.INDEFINITE);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(pane);
borderPane.setBottom(hBox);
Scene scene = new Scene(borderPane, 320, 360);
primaryStage.setTitle("编程练习题15_34SelfAvoidanceRandomWalk");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
boolean up = true;
boolean down = true;
boolean left = true;
boolean right = true;
public void DrawLine() {
if(point.contains(startX+" "+(startY-20))) {up = false;}
if(point.contains(startX+" "+(startY+20))) {down = false;}
if(point.contains((startX-20)+" "+startY)) {left = false;}
if(point.contains((startX+20)+" "+startY)) {right = false;}
if(!up&&!down&&!left&&!right) {canStart = false;}
int random;
do {
random = (int) (Math.random() * 4);
} while ((random == 0 && !up) || (random == 1 && !down) || (random == 2 && !left) || (random == 3 && !right));
if(random == 0) {//上
endY = startY-20;
}
else if(random == 1) {//下
endY = startY+20;
}
else if(random == 2) {//左
endX = startX-20;
}
else if(random == 3) {//右
endX = startX+20;
}
Line l = new Line(startX,startY,endX,endY);
l.setStroke(Color.RED);
pane.getChildren().add(l);
startX = endX;
startY = endY;
point.add(startX+" "+startY);
if (endX <= 0 || endY <= 0 || endX >= 320 || endY >= 320) {
//animation.stop();
canStart = false;
return; // 可选:如果已经停止动画,则退出方法
}
}
}
结果展示