任务要求:用java面向对象程序设计语言,设计和实现一电脑鼠走迷宫的软件程序,即一个假想的小车能在图示的迷宫中根据设定的起始点和终点自主寻找路径。
具体内容:1. 迷宫地图自动随机生成;
2. 最短路径自动寻找(具有判断通路与障碍的功能;走不通具备返回的能力);
3. 界面展示;
本人代码基本结构:用javafx设计面板,以一个按钮一个方法来实现六个按钮的功能(放在各自的事件处理器内);设计Gezi类来存储迷宫格子的数据,设计Point类来存储坐标数据。
import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Maze extends Application {
static FlowPane flowpane = new FlowPane();
static Gezi[][] gezi = new Gezi[33][33];
static Stack<Point> stack1 = new Stack<>();
static Point Startpoint1 = new Point(1, 1);
static Button button1 = new Button("生成迷宫");
static Button button2 = new Button("自动寻路");
static Button button3 = new Button("遍历迷宫");
static Button button4 = new Button("单步寻路");
static Button button5 = new Button("清空效果");
static Button button6 = new Button(" 退出 ");
public static void main(String[] args) throws Exception {
Application.launch(args);
}
public void start(Stage primaryStage) throws Exception
{
HBox hbox = new HBox();
button2.setDisable(true); //按钮“变灰”,即是否可点击,true可;false不可
button3.setDisable(true);
button4.setDisable(true);
button5.setDisable(true);
button6.setDisable(true);
VBox vbox = new VBox();
vbox.getChildren().add(button1);
vbox.getChildren().add(button2);
vbox.getChildren().add(button3);
vbox.getChildren().add(button4);
vbox.getChildren().add(button5);
vbox.getChildren().add(button6);
//鼠标点击事件
button1.setOnAction(new button1HandlerClass());
button2.setOnAction(new button2HandlerClass());
button3.setOnAction(new button3HandlerClass());
stack1.add(Startpoint1);
button4.setOnAction(new button4HandlerClass());
button5.setOnAction(new button5HandlerClass());
button6.setOnAction(new button6HandlerClass());
hbox.getChildren().add(vbox);
hbox.getChildren().add(flowpane);
Scene scene = new Scene(hbox,800,660);
primaryStage.setScene(scene);
primaryStage.show();
}
/*让迷宫全是墙.
选一个单元格作为迷宫的通路,然后把它的邻墙放入列表
当列表里还有墙时
从列表里随机选一个墙,如果这面墙分隔的两个单元格只有一个单元格被访问过,那就从列表里移除这面墙,并把墙打通,让未访问的单元格成为迷宫的通路,再把这个格子周围的墙加入列表
如果墙两面的单元格都已经被访问过,那就直接从列表里移除这面墙
走过的路和所有的路数目相等,结束*/
class button1HandlerClass implements EventHandler<ActionEvent> //随机生成迷宫(prim算法)
{
@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
Random random = new Random();
button2.setDisable(false);
button3.setDisable(false);
button4.setDisable(false);
button5.setDisable(false);
button6.setDisable(false);
ArrayList<Gezi> way = new ArrayList<>();
ArrayList<Gezi> wall = new ArrayList<>();
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
gezi[i][j] = new Gezi(i, j, true,false); //true为墙false为路
}
}
for(int i=1;i<=31;i+=2)
{
for(int j=1;j<=31;j+=2)
{
gezi[i][j].setFilled(false);
way.add(gezi[i][j]);
}
}
gezi[1][1].setStart(true);
gezi[31][31].setEnd(true);
ArrayList<Gezi> search = new ArrayList<>();
int startX = 1;
int startY = 1;
gezi[startX][startY].setSearched(true);
search.add(gezi[startX][startY]);
while(true)
{
if(gezi[startX+1][startY].isFilled())
{
if(startX+1<32)
wall.add(gezi[startX+1][startY]);
}
if(gezi[startX-1][startY].isFilled())
{
if(startX-1>0)
wall.add(gezi[startX-1][startY]);
}
if(gezi[startX][startY+1].isFilled())
{
if(startY+1<32)
wall.add(gezi[startX][startY+1]);
}
if(gezi[startX][startY-1].isFilled())
{
if(startY-1>0)
wall.add(gezi[startX][startY-1]);
}
int n1 = random.nextInt(wall.size());
int n2 = 0;
if(gezi[wall.get(n1).getX()-1][wall.get(n1).getY()].isSearched())
{
n2++;
}
if(gezi[wall.get(n1).getX()+1][wall.get(n1).getY()].isSearched())
{
n2++;
}
if(gezi[wall.get(n1).getX()][wall.get(n1).getY()-1].isSearched())
{
n2++;
}
if(gezi[wall.get(n1).getX()][wall.get(n1).getY()+1].isSearched())
{
n2++;
}
if(n2==2)
{
wall.remove(n1);
}
else
{
if(!gezi[wall.get(n1).getX()-1][wall.get(n1).getY()].isFilled())
{
if(!gezi[wall.get(n1).getX()-1][wall.get(n1).getY()].isSearched())
{
gezi[wall.get(n1).getX()-1][wall.get(n1).getY()].setSearched(true);
search.add(gezi[wall.get(n1).getX()-1][wall.get(n1).getY()]);
startX = wall.get(n1).getX()-1;
startY = wall.get(n1).getY();
}
}
if(!gezi[wall.get(n1).getX()+1][wall.get(n1).getY()].isFilled())
{
if(!gezi[wall.get(n1).getX()+1][wall.get(n1).getY()].isSearched())
{
gezi[wall.get(n1).getX()+1][wall.get(n1).getY()].setSearched(true);
search.add(gezi[wall.get(n1).getX()+1][wall.get(n1).getY()]);
startX = wall.get(n1).getX()+1;
startY = wall.get(n1).getY();
}
}
if(!gezi[wall.get(n1).getX()][wall.get(n1).getY()-1].isFilled())
{
if(!gezi[wall.get(n1).getX()][wall.get(n1).getY()-1].isSearched())
{
gezi[wall.get(n1).getX()][wall.get(n1).getY()-1].setSearched(true);
search.add(gezi[wall.get(n1).getX()][wall.get(n1).getY()-1]);
startX = wall.get(n1).getX();
startY = wall.get(n1).getY()-1;
}
}
if(!gezi[wall.get(n1).getX()][wall.get(n1).getY()+1].isFilled())
{
if(!gezi[wall.get(n1).getX()][wall.get(n1).getY()+1].isSearched())
{
gezi[wall.get(n1).getX()][wall.get(n1).getY()+1].setSearched(true);
search.add(gezi[wall.get(n1).getX()][wall.get(n1).getY()+1]);
startX = wall.get(n1).getX();
startY = wall.get(n1).getY()+1;
}
}
gezi[wall.get(n1).getX()][wall.get(n1).getY()].setFilled(false);
wall.remove(n1);
}
if(search.size()==way.size())
break;
}
flowpane.setPrefSize(660, 660);
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
if(!gezi[i][j].isFilled()) //路
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
if(gezi[i][j].isStart())
{
rectangle.setFill(Color.PINK);
}
else if(gezi[i][j].isEnd())
{
rectangle.setFill(Color.YELLOW);
}
else
rectangle.setFill(Color.WHITE);
flowpane.getChildren().add(rectangle);
}
else //墙
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
rectangle.setFill(Color.BLACK);
flowpane.getChildren().add(rectangle);
}
}
}
}
}
class button2HandlerClass implements EventHandler<ActionEvent> //自动寻路//BFS算法//找出一条路径
{
@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
Point Startpoint = new Point(1, 1);
Point Endpoint = new Point(31, 31);
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
gezi[i][j].setGo(false);
gezi[i][j].setColored(false);;
}
}
int x = 0;
int y = 0;
Stack<Point> stack = new Stack<>();
stack.add(Startpoint);
gezi[Startpoint.x][Startpoint.y].setGo(true);
while(!stack.empty())
{
Point point1 = stack.pop(); //重点,(回溯)
int flag = 0;
for(int i=0;i<4;i++)
{
switch(i)
{
case 0: x = point1.x+1; //向下
y = point1.y;
break;
case 1: x = point1.x; //向右
y = point1.y+1;
break;
case 2: x = point1.x; //向左
y = point1.y-1;
break;
case 3: x = point1.x-1; //向上
y = point1.y;
break;
}
if(!gezi[x][y].isFilled()&&!gezi[x][y].isGo())
{
gezi[x][y].setGo(true);
stack.push(point1);
stack.push(new Point(x,y));
if(x == Endpoint.x&&y == Endpoint.y) //到达终点
{
flag = 1;
}
break;
}
}
if(flag == 1) //到达终点退出
break;
}
for(int i=0;i<stack.size();i++)
{
gezi[stack.get(i).x][stack.get(i).y].setColored(true);
}
flowpane.getChildren().clear();
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
if(!gezi[i][j].isFilled()) //路
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
if(gezi[i][j].isColored())
{
rectangle.setFill(Color.GREEN);
}
else
{
rectangle.setFill(Color.WHITE);
}
flowpane.getChildren().add(rectangle);
}
else //墙
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
rectangle.setFill(Color.BLACK);
flowpane.getChildren().add(rectangle);
}
}
}
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
gezi[i][j].setGo(false);
gezi[i][j].setColored(false);;
}
}
}
}
class button3HandlerClass implements EventHandler<ActionEvent> //遍历迷宫//找出所有路径
{
@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
Point Startpoint = new Point(1, 1);
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
gezi[i][j].setGo(false);
gezi[i][j].setColored(false);
}
}
int x = 0;
int y = 0;
Stack<Point> stack = new Stack<>();
stack.add(Startpoint);
gezi[Startpoint.x][Startpoint.y].setGo(true);
while(!stack.empty())
{
Point point1 = stack.pop(); //重点,(回溯)
for(int i=0;i<4;i++)
{
switch(i)
{
case 0: x = point1.x+1; //向下
y = point1.y;
break;
case 1: x = point1.x; //向右
y = point1.y+1;
break;
case 2: x = point1.x; //向左
y = point1.y-1;
break;
case 3: x = point1.x-1; //向上
y = point1.y;
break;
}
if(!gezi[x][y].isFilled()&&!gezi[x][y].isGo())
{
gezi[x][y].setGo(true);
stack.push(point1);
stack.push(new Point(x,y));
break;
}
}
}
flowpane.getChildren().clear();
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
if(!gezi[i][j].isFilled()) //路
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
if(gezi[i][j].isGo())
{
rectangle.setFill(Color.GREEN);
}
else
{
rectangle.setFill(Color.WHITE);
}
flowpane.getChildren().add(rectangle);
}
else //墙
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
rectangle.setFill(Color.BLACK);
flowpane.getChildren().add(rectangle);
}
}
}
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
gezi[i][j].setGo(false);
gezi[i][j].setColored(false);;
}
}
}
}
class button4HandlerClass implements EventHandler<ActionEvent> //单步寻路
{
@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
int x = 0;
int y = 0;
gezi[Startpoint1.x][Startpoint1.y].setGo(true);
Point point1 = stack1.pop(); //重点,(回溯)
gezi[point1.x][point1.y].setColored(false);
for(int i=0;i<4;i++)
{
switch(i)
{
case 0: x = point1.x+1; //向下
y = point1.y;
break;
case 1: x = point1.x; //向右
y = point1.y+1;
break;
case 2: x = point1.x; //向左
y = point1.y-1;
break;
case 3: x = point1.x-1; //向上
y = point1.y;
break;
}
if(!gezi[x][y].isFilled()&&!gezi[x][y].isGo())
{
gezi[x][y].setGo(true);
stack1.push(point1);
stack1.push(new Point(x,y));
break;
}
}
for(int i=0;i<stack1.size();i++)
{
gezi[stack1.get(i).x][stack1.get(i).y].setColored(true);
}
flowpane.getChildren().clear();
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
if(!gezi[i][j].isFilled()) //路
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
if(gezi[i][j].isColored())
{
rectangle.setFill(Color.GREEN);
}
else
{
rectangle.setFill(Color.WHITE);
}
flowpane.getChildren().add(rectangle);
}
else //墙
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
rectangle.setFill(Color.BLACK);
flowpane.getChildren().add(rectangle);
}
}
}
}
}
class button5HandlerClass implements EventHandler<ActionEvent> //清空效果
{
@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
gezi[i][j].setGo(false);
gezi[i][j].setColored(false);
}
}
stack1.clear();
stack1.add(Startpoint1);
flowpane.getChildren().clear();
for(int i=0;i<33;i++)
{
for(int j=0;j<33;j++)
{
if(!gezi[i][j].isFilled()) //路
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
if(gezi[i][j].isStart())
{
rectangle.setFill(Color.PINK);
}
else if(gezi[i][j].isEnd())
{
rectangle.setFill(Color.YELLOW);
}
else
rectangle.setFill(Color.WHITE);
flowpane.getChildren().add(rectangle);
}
else //墙
{
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setHeight(20);
rectangle.setFill(Color.BLACK);
flowpane.getChildren().add(rectangle);
}
}
}
}
}
class button6HandlerClass implements EventHandler<ActionEvent> //退出
{
@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
flowpane.getChildren().clear();
button2.setDisable(true);
button3.setDisable(true);
button4.setDisable(true);
button5.setDisable(true);
button6.setDisable(true);
}
}
}
class Gezi
{
private int x;
private int y;
private boolean filled;
private boolean searched;
private boolean colored;
private boolean go;
private boolean start;
private boolean end;
public boolean isStart() {
return start;
}
public void setStart(boolean start) {
this.start = start;
}
public boolean isEnd() {
return end;
}
public void setEnd(boolean end) {
this.end = end;
}
public boolean isGo() {
return go;
}
public void setGo(boolean go) {
this.go = go;
}
public boolean isColored() {
return colored;
}
public void setColored(boolean colored) {
this.colored = colored;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isFilled() {
return filled;
}
public void setFilled(boolean filled) {
this.filled = filled;
}
public boolean isSearched() {
return searched;
}
public void setSearched(boolean searched) {
this.searched = searched;
}
public Gezi()
{
}
public Gezi(int x,int y,boolean filled,boolean searched)
{
this.filled = filled;
this.x = x;
this.y = y;
this.searched = searched;
}
}
class Point
{
int x;
int y;
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public Point()
{
}
public Point(int x,int y)
{
this.x = x;
this.y = y;
}
}
功能展示:
算法说明:
1.自动随机生成迷宫prim算法
2.寻路BFS算法(广度优先)
3.回溯算法(深度优先)
建议算法及思路参考资料:
基于Java FX,BFS和Prim实现的迷宫小游戏
迷宫自动生成程序
使用prim算法生成随机迷宫
三大迷宫生成算法
三种迷宫生成算法概述
基于递归分割的迷宫生成算法与自动寻路
注意:代码注释较少,相应方法和思路get到了就行。感兴趣的小伙伴还可以设计一个自定义起点终点的功能来做到相应的进阶