电脑迷宫鼠---补充(Controller里的具体实现)

发布时间 2023-07-03 16:56:17作者: strind

电脑迷宫鼠

补充(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;
    }


}