电脑迷宫鼠
补充(Controller里的具体实现)
public class Controller {
@FXML
private TextField startX; //都是界面上的组件
@FXML
private TextField startY;
@FXML
private TextField endX;
@FXML
private TextField endY;
@FXML
private GridPane grid;
@FXML
private ChoiceBox<String> create;
@FXML
private TextField row;
@FXML
private TextField col;
@FXML
private Label wrongMsg;
@FXML
private Label createWrongMsg;
@FXML
private TextArea info;
// 生成的迷宫
private int[][] maze;
// 默认迷宫的行数和列数
private int ROW = 59;
private int COL = 59;
// 遍历迷宫时的方向
private int[][] go = new int[][]{
{-1, 0},
{0, 1},
{1, 0},
{0, -1}
};
// 遍历迷宫时,放用于回溯的点
private HashMap<Integer, int[]> map = new HashMap<>();
// 记录路径
private List<List<int[]>> paths = new LinkedList<>();
// 初始化
@FXML
private void initialize() {
closeMsg();//关闭提示的错误信息
ObservableList<String> observableList = FXCollections.observableArrayList("自动创建", "手动创建");
create.setItems(observableList);
}
/**
* 点击背景,将一些错误提示信息删掉
*
* @param event
*/
@FXML
void MouseClickedBackground(MouseEvent event) {
// 将错误信息隐藏
closeMsg();
}
/**
* 点击创建迷宫
*
* @param event
*/
@FXML
void MouseClickedCreateStart(MouseEvent event) {
// 将错误信息隐藏
closeMsg();
// 点击迷宫创建按钮
// 判断是否有其他线程在运行
if (isAThreadRunning("supDfs", "findOne")) {
// 有其他线程在运行,创建失败
return;
}
// 进行判断,是手动还是自动
String value = create.getValue();
if ("自动创建".equals(value)) {
System.out.println("自动创建");
// 进行判断,看用户是否输入了行数和列数
try {
int Row = Integer.parseInt(row.getText().length() == 0 ? "0" : row.getText());
int Col = Integer.parseInt(col.getText().length() == 0 ? "0" : col.getText());
// 进行判断提高代码的健壮性
if (Row > 3 && Row <= 59 && Col > 3 && Col <= 59) {
if (Row % 2 == 0) Row++;
if (Col % 2 == 0) Col++;
ROW = Row;
COL = Col;
// 按照用户的输入进行迷宫的创建
maze = God.getInstance().maze(Row, Col);
} else if (((row.getText().length() == 0) && (col.getText().length() > 0))
|| ((col.getText().length() == 0) && (row.getText().length() > 0))) {
createWrongMsg.setText("行数或列数有误,迷宫创建失败");//将错误信息展示给用户
createWrongMsg.setVisible(true);
return;
} else if (Row < 3 || Row > 59 || Col < 3 || Col > 59) {
createWrongMsg.setText("行数或列数有误,迷宫创建失败");//将错误信息展示给用户
createWrongMsg.setVisible(true);
return;
} else {
// 采取默认迷宫的创建
ROW = 59;
COL = 59;
maze = God.getInstance().maze();
}
// 得到迷宫图
System.out.println("迷宫" + maze);
// 这里grid.getChildren()可以简单理解为获取所有的路和墙
grid.getChildren().clear();
paint();
// 打印迷宫到控制台
for (int[] ma : maze) {
System.out.println(Arrays.toString(ma));
}
} catch (NumberFormatException e) {
// 输入非数值的值,提示用户
wrongMsg.setText("输入仅支持合法的数字");
wrongMsg.setVisible(true);
}
} else {
System.out.println("手动创建");
// 从文件里读入以保存的迷宫图
String url = "";
// 随机抽取一个路径创建迷宫
int k = (int) (Math.random() * 8) + 1;
// 创建迷宫所用的文件
File file = new File("src/handMaking/maze" + k + ".txt");
// 生成迷宫
ROW = 59;
COL = 59;
maze = createMazeByTxt(file);
System.out.println("迷宫" + k);
// 得到迷宫图
grid.getChildren().clear();
paint();
// 打印迷宫到控制台
for (int[] ma : maze) {
System.out.println(Arrays.toString(ma));
}
}
}
/**
* 、
* 寻找最优解
*
* @param event
*/
@FXML
void MouseClickedFindBest(MouseEvent event) {
// 将错误信息隐藏
closeMsg();
// 查询是否由其他线程在运行,将其关闭
if (isAThreadRunning("supDfs", "findOne")) {
// 有其他线程在运行,结束
return;
}
// 检查迷宫是否创建
if (maze == null) {
wrongMsg.setText("迷宫还未创建");
wrongMsg.setVisible(true);
return;
}
// 从新绘制迷宫,全部变成黑白色
paint();
//System.out.println("点击了我");
findWays();
// 获取得到的路径总数
int size = paths.size();
if (size == 0) {
// 无路可走
wrongMsg.setText("起点或终点有误");
wrongMsg.setVisible(true);
} else if (size == 1) {
// 只有一条路可走
List<int[]> ints = paths.get(0);
// 反映在页面上
printWays(ints);
} else { // 多条路可走,选择结点最少的
// 寻找最少结点所在的路径
int index = 0;
for (int i = 0; i < paths.size(); i++) {
if (paths.get(i).size() < paths.get(index).size()) index = i;
}
// 反映在页面上
printWays(paths.get(index));
}
}
/**
* 点击找寻路径
*
* @param event
*/
@FXML
void MouseClickedFindStart(MouseEvent event) throws InterruptedException {
// 将错误信息隐藏
closeMsg();
// 查询是否由其他线程在运行
if (isAThreadRunning("supDfs", "findOne")) {
// 如果有其他线程在运行,结束现在
return;
}
// 检查迷宫是否创建
if (maze == null) {
wrongMsg.setText("迷宫还未创建");
wrongMsg.setVisible(true);
return;
}
// 从新绘制迷宫,全部变成黑白色
paint();
//寻路
int valid = findWays();
// 能找到合适的路
if (valid == 0) {
// 获取得到的路径总数
int size = paths.size();
if (size == 0) {
// 没有得到路径,说明起点无法走到终点
// 提示错误信息
wrongMsg.setText("起点或终点有误");
wrongMsg.setVisible(true);
} else {
// 直接拿第一条路径返回
List<int[]> ints = paths.get(0);
// 在页面进行展示
printWays(ints);
}
}
}
/**
* 遍历迷宫
*
* @param event
*/
@FXML
void MouseClickedRunAll(MouseEvent event) {
// 将错误信息隐藏
closeMsg();
// 查询是否有其他线程在运行
if (isAThreadRunning("supDfs", "findOne")) {
// 有其他线程在运行,结束现在的运作
System.out.println("有其他线程在运行");
return;
}
// 检查迷宫是否创建
if (maze == null) {
wrongMsg.setText("迷宫还未创建");
wrongMsg.setVisible(true);
return;
}
try {
findSuperDfs();
} catch (Exception e) {
System.out.println("遍历迷宫可视化异常");
}
}
/**
* 根据坐标将结果反映在页面上,寻路
*
* @param way
*/
private void printWays(List<int[]> way) {
Task task = new Task() {
@Override
protected Object call() throws Exception {
int[] ints = way.get(0);
reFresh(ints[0] * COL + ints[1], Color.GREEN);
ints = way.get(way.size() - 1);
reFresh(ints[0] * COL + ints[1], Color.RED);
for (int j = 1; j < way.size() - 1; j++) {
Thread.sleep(35);
ints = way.get(j);
reFresh(ints[0] * COL + ints[1], Color.ORANGE);
}
return null;
}
;
};
Thread t = new Thread(task, "findOne");
t.start();
}
/**
* 根据起点和终点,寻找所有合适的解
*/
private int findWays() {
int sX, sY, eX, eY;
try {
// 寻优起点
sX = Integer.parseInt(startX.getText().length() == 0 ? "1" : startX.getText());
sY = Integer.parseInt(startY.getText().length() == 0 ? "1" : startY.getText());
// 寻路终点
eX = Integer.parseInt(endX.getText().length() == 0 ? (ROW - 2) + "" : endX.getText());
eY = Integer.parseInt(endY.getText().length() == 0 ? (COL - 2) + "" : endY.getText());
} catch (NumberFormatException e) {
wrongMsg.setText("无法识别坐标");
wrongMsg.setVisible(true);
return -1;
}
// 判断坐标的合法性
if (!isRight(sX, sY, eX, eY)) {
wrongMsg.setText("坐标输入有误");
wrongMsg.setVisible(true);
return -1;
}
System.out.println(maze[sX][sY] + " " + maze[eX][eY]);
// 清空paths,防止上一次的查询残留
paths.clear();
// 起点和终点都是合法位置,就开始寻找
if (maze[sX][sY] != 1 && maze[eX][eY] != 1) {
System.out.println("开始寻找" + sX + " " + sY + " " + eX + " " + eY);
dfs(new LinkedList<>(), sX, sY, eX, eY);
}
System.out.println("一共寻找到 " + paths.size() + " 这么多条路");
return 0;
}
// 当前坐标 终点
// 寻找到多条合适的路,从头到尾
private void dfs(List<int[]> list, int x, int y, int ex, int ey) {
// 请自行实现
}
/**
* 遍历迷宫时用到,将过程可视化
*/
private void findSuperDfs() {
// 请自行实现
}
/**
* 遍历迷宫使用,只要到达终点就不在遍历
*/
private boolean superDfs(List<int[]> list, int x, int y, int ex, int ey) {
// 请自行实现
}
/**
* 改变方块的颜色
*
* @param index
* @param color
*/
private void reFresh(int index, Color color) {
Rectangle rectangle = (Rectangle) grid.getChildren().get(index);
rectangle.setFill(color);
}
/**
* 画迷宫
*/
private void paint() {
// 如果迷宫还不存在
if (grid.getChildren().size() == 0) {
System.out.println(ROW + " " + COL);
// 设置迷宫每个方块的大小
int k = 590 / ROW;
k = Math.min(590 / COL, k);
System.out.println("k的大小为:" + k);
if (k > 20) k = 20;
// 设置迷宫的大小
//grid.setMaxHeight(ROW * k);
grid.setPrefHeight(ROW * k);
System.out.println("高度" + ROW * k);
//grid.setMaxWidth(COL * k);
grid.setPrefWidth(COL * k);
System.out.println("宽度" + COL * k);
System.out.println("创建迷宫");
// 开始创建迷宫
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
Rectangle rec = new Rectangle();
rec.setWidth(k);
rec.setHeight(k);
if (maze[i][j] == 0) rec.setFill(Color.WHITE);
else rec.setFill(Color.BLACK);
//列 行
grid.add(rec, j * k, i * k);
}
}
} else {
// 迷宫已经存在,将迷宫恢复的最开始的样子
System.out.println("恢复迷宫的颜色");
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
Rectangle rec = (Rectangle) grid.getChildren().get(i * COL + j);
if (maze[i][j] == 0) rec.setFill(Color.WHITE);
else rec.setFill(Color.BLACK);
}
}
}
}
/**
* 寻找在index前集合里是否已经出现
*
* @param list
* @param index
* @return
*/
private int isValid(List<int[]> list, int index) {
int[] origin = list.get(index);
if (map.isEmpty()) return -1;
//int k = 0;
for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
int[] key = entry.getValue();
if (key[0] == origin[0] && key[1] == origin[1])
return entry.getKey();
//if (k++ > map.size() - 2) break;
}
return -1;
}
/**
* 判断用户输入的坐标是否合法
*
* @param x
* @param y
* @param ex
* @param ey
* @return
*/
private boolean isRight(int x, int y, int ex, int ey) {
if (x != 1 && (x < 1 || x > ROW - 2)) return false;
if (y != 1 && (y < 1 || y > COL - 2)) return false;
if (ex != ROW - 2 && (ex < 1 || ex > ROW - 2)) return false;
if (ey != COL - 2 && (ey < 1 || ey > COL - 2)) return false;
return true;
}
/**
* 将提示的错误信息关闭
*/
private void closeMsg() {
wrongMsg.setVisible(false);
createWrongMsg.setVisible(false);
}
/**
* 查看是否还有其他的线程在运行
*
* @param list
* @return
*/
private boolean isAThreadRunning(String... list) {
try {
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
Thread[] threads = new Thread[threadGroup.activeCount()];
threadGroup.enumerate(threads);
for (Thread thread : threads) {
System.out.println(thread.getName());
for (String name : list) {
if (name.equals("supDfs") && name.equals(thread.getName())) {
wrongMsg.setText("迷宫正在遍历中……");
wrongMsg.setVisible(true);
return true;
} else if (name.equals("findOne") && name.equals(thread.getName())) {
wrongMsg.setText("迷宫正在寻路中……");
wrongMsg.setVisible(true);
return true;
}
}
}
} catch (NullPointerException e) {
System.out.println("e -> 空指针");
}
return false;
}
/**
* 根据文件创建迷宫
*
* @param file
* @return
*/
private int[][] createMazeByTxt(File file) {
int[][] lab = new int[59][59];
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String line = bufferedReader.readLine();
if (line != null) {
for (int i = 0; i < 59; i++) {
String[] numbers = line.split(",");
for (int j = 0; j < 59; j++) {
lab[i][j] = Integer.parseInt(numbers[j]);
}
// 继续读下一行
line = bufferedReader.readLine();
}
}
// 关闭资源
bufferedReader.close();
} catch (IOException e) {
// 文件未找到异常
System.out.println("文件未找到……");
}
return lab;
}
}