附录:源码

项目一

package Test;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Objects;
import java.util.Stack;

import javax.swing.*;

//Calculator类,继承JFrame框架,实现事件监听器接口
class Calculator extends JFrame implements ActionListener {
    private final String[] KEYS = {"7", "8", "9", "AC",
            "4", "5", "6", "-",
            "1", "2", "3", "+",
            "0",  "/",  "^2", "*",
            "(", ")", ".", "="};
    private JButton keys[] = new JButton[KEYS.length];
    private JTextArea resultText = new JTextArea();    // 文本域组件TextArea可容纳多行文本;文本框内容初始值设为0
    private JTextArea HistoryText = new JTextArea();    // 历史记录文本框初始值设为空
    private JPanel jp2 = new JPanel();
    private JScrollPane gdt1 = new JScrollPane(resultText);
    private JScrollPane gdt2 = new JScrollPane(HistoryText);
    private JLabel label = new JLabel("历史记录");
    private String input = "";   //计算文本框输入的中缀表达式

    // 构造方法
    public Calculator() {

        resultText.setBounds(20, 18, 255, 120);     // 设置文本框大小
        resultText.setAlignmentX(LEFT_ALIGNMENT);  // 文本框内容左对齐
        resultText.setEditable(false);  // 文本框不允许修改结果
        resultText.setFont(new Font("font", Font.PLAIN, 18));    //设置结果文本框输入文字的字体、类型、大小
        HistoryText.setFont(new Font("font", Font.PLAIN, 18));    //设置历史记录文本框输入文字的字体、类型、大小
        HistoryText.setBounds(290, 40, 250, 330);   // 设置文本框大小
        HistoryText.setAlignmentX(LEFT_ALIGNMENT);  // 文本框内容左对齐
        HistoryText.setEditable(false);     // 文本框不允许修改结果
        label.setBounds(300, 15, 100, 20);  //设置标签位置及大小
        jp2.setBounds(290, 40, 250, 330);   //设置面板窗口位置及大小
        jp2.setLayout(new GridLayout());
        JPanel jp1 = new JPanel();
        jp1.setBounds(20, 18, 255, 120);    //设置面板窗口位置及大小
        jp1.setLayout(new GridLayout());
        resultText.setLineWrap(true);   // 激活自动换行功能
        resultText.setWrapStyleWord(true);  // 激活断行不断字功能
        HistoryText.setLineWrap(true);  //自动换行
        HistoryText.setWrapStyleWord(true);
        jp1.add(gdt1);  //将滚动条添加入面板窗口中
        jp2.add(gdt2);
        this.add(jp1);  //将面板添加到总窗体中
        this.add(jp2);  //将面板添加到总窗体中
        this.setLayout(null);
        this.add(label);    // 新建“历史记录”标签

        // 放置按钮 x,y为按钮的横纵坐标
        int x = 20, y = 200;
        for (int i = 0; i < KEYS.length; i++) {
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);
            keys[i].setBounds(x, y, 50, 40);
            if (x < 215) {
                x += 65;
            } else {
                x = 20;
                y += 45;
            }
            this.add(keys[i]);
        }
        for (int i = 0; i < KEYS.length; i++)   // 每个按钮都注册事件监听器
        {
            keys[i].addActionListener(this);
        }
        this.setResizable(false);//不允许调整计算器界面大小
        this.setBounds(700, 300, 560, 450);//计算器界面位置和大小
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭计算器程序终止
        this.setVisible(true);
    }

    // 事件处理
    public void actionPerformed(ActionEvent e) {
        String label = e.getActionCommand();    //获得事件源的标签
        if (Objects.equals(label, "AC"))    //清空按钮,消除显示屏文本框前面所有的输入和结果
        {
            input = "";
            resultText.setText("");      //更新文本域的显示
        }  else if (Objects.equals(label, "^2")) {
            String m;
            if(input.isEmpty()) m="error!";
            else m = String.valueOf(pfys(input));
            resultText.setText(input + "^2" + "=" + m);
            HistoryText.setText(HistoryText.getText() + resultText.getText() + "\n");
            input = m;
        } else if (Objects.equals(label, "=")) {
            if (input.isEmpty()) return;
            String[] s = houzhui(input);    //将中缀表达式转换为后缀表达式
            double result = Result(s);     //计算后缀表达式得出最终算式结果
            resultText.setText(input + "=" + result);
            HistoryText.setText(HistoryText.getText() + resultText.getText() + "\n");
        } else {

            input = input + label;
            resultText.setText(input);
        }
    }

    //将中缀表达式转换为后缀表达式
    private String[] houzhui(String infix) {  //infix 中缀
        String s = "";// 用于承接多位数的字符串
        Stack<String> opStack = new Stack<String>();
        Stack<String> postQueue = new Stack<String>();   // 后缀表达式,为了将多位数存储为独立的字符串
        System.out.println("中缀:" + infix);
        for (int i = 0; i < infix.length(); i++)    // 遍历中缀表达式
        // indexof函数,返回字串首次出现的位置;charAt函数返回index位置处的字符;
        {
            if ("1234567890.".indexOf(infix.charAt(i)) >= 0) {    // 遇到数字字符直接入队

                s = "";// 作为承接字符,每次开始时都要清空
                for (; i < infix.length() && "0123456789.".indexOf(infix.charAt(i)) >= 0; i++) {
                    s = s + infix.charAt(i);
                }
                i--;   //避免跳过对非数字字符的处理
                postQueue.push(s);  // 数字字符直接加入后缀表达式
            } else if ("(".indexOf(infix.charAt(i)) >= 0) {   // 遇到左括号
                opStack.push(String.valueOf(infix.charAt(i)));   // 左括号入栈
            } else if (")".indexOf(infix.charAt(i)) >= 0) {   // 遇到右括号
                while (!opStack.peek().equals("(")) {    // 栈顶元素循环出栈,直到遇到左括号为止
                    postQueue.push(opStack.pop());
                }
                opStack.pop();     //删除左括号
            } else if ("*%/+-".indexOf(infix.charAt(i)) >= 0)   // 遇到运算符
            {
                if (opStack.empty() || "(".contains(opStack.peek())) {// 若栈为空或栈顶元素为左括号则直接入栈
                    opStack.push(String.valueOf(infix.charAt(i)));
                } else {
                    // 当栈顶元素为高优先级或同级运算符时,让栈顶元素出栈进入后缀表达式后,直到符合规则后,当前运算符再入栈
                    boolean rule = ("*%/+-".contains(opStack.peek()) && "+-".indexOf(infix.charAt(i)) >= 0) || ("*%/".contains(opStack.peek()) && "*%/".indexOf(infix.charAt(i)) >= 0);
                    while (!opStack.empty() && rule) {
                        postQueue.push(opStack.peek());  //peek()方法:返回栈顶的元素但不移除它
                        opStack.pop();
                    }
                    opStack.push(String.valueOf(infix.charAt(i)));   // 当前元素入栈
                }
            }
        }
        while (!opStack.empty()) {// 遍历结束后将栈中剩余元素依次出栈进入后缀表达式
            postQueue.push(opStack.pop());
        }
        //将后缀表达式栈转换为字符串数组格式
        String[] suffix = new String[postQueue.size()];
        for (int i = postQueue.size() - 1; i >= 0; i--) {
            suffix[i] = postQueue.pop();
        }
        System.out.println("后缀:" + Arrays.toString(suffix.clone()));
        return suffix;
    }
    //平方运算方法
    public double pfys(String str) {
        double a = Double.parseDouble(str);
        return Math.pow(a, 2);
    }

    // 计算后缀表达式,并返回最终结果
    public double Result(String[] suffix) {  //suffix 后缀
        Stack<String> Result = new Stack<>();// 顺序存储的栈,数据类型为字符串
        int i;
        for (i = 0; i < suffix.length; i++) {
            if ("1234567890.".indexOf(suffix[i].charAt(0)) >= 0) {  //遇到数字,直接入栈
                Result.push(suffix[i]);
            } else {    // 遇到运算符字符,将栈顶两个元素出栈计算并将结果返回栈顶
                double x, y, n = 0;
                x = Double.parseDouble(Result.pop());   // 顺序出栈两个数字字符串,并转换为double类型
                y = Double.parseDouble(Result.pop());
                switch (suffix[i]) {
                    case "*":
                        n = y * x;
                        break;
                    case "/":
                        if (x == 0) return 0;
                        else n = y / x;
                        break;
                    case "-":
                        n = y - x;
                        break;
                    case "+":
                        n = y + x;
                        break;
                }
                Result.push(String.valueOf(n)); // 将运算结果重新入栈
            }
        }

        System.out.println("return:" + Result.peek());
        return Double.parseDouble(Result.peek());   // 返回最终结果
    }

    // 主函数
    public static void main(String[] args) {
        Calculator a = new Calculator();
    }
}

项目二

package com.itheima;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;

public class MainFrame extends JFrame {
    private Snake snake; //蛇
    private JPanel jPanel; //游戏棋盘
    private Timer timer; //定时器,在规定的时间内调用蛇移动的方法
    private Node food; //食物

    public MainFrame() throws HeadlessException {
        //初始化窗体参数
        initFrame();
        //初始化游戏棋盘
        initGamePanel();
        //初始化蛇
        initSnake();
        //初始化食物
        initFood();
        //初始化定时器
        initTimer();
        //设置键盘监听,让蛇随着上下左右方向移动
        setKeyListener();
    }

    //初始化食物
    private void initFood() {
        food=new Node();
        food.random();
    }

    //设置键盘监听
    private void setKeyListener() {
        addKeyListener(new KeyAdapter() {
            //当键盘按下时,会自动掉此方法
            public void keyPressed(KeyEvent e) {
                //键盘中的一个键都有一个编号
                switch (e.getKeyCode()){

                    case KeyEvent.VK_W: //上键
                        if(snake.getDirection()!=Direction.DOWN){
                            snake.setDirection(Direction.UP);
                        }
                        break;
                    case KeyEvent.VK_S: //下键
                        if(snake.getDirection()!=Direction.UP){
                            snake.setDirection(Direction.DOWN);
                        }
                        break;
                    case KeyEvent.VK_A: //左键
                        if(snake.getDirection()!=Direction.RIGHT){
                            snake.setDirection(Direction.LEFT);
                        }
                        break;
                    case KeyEvent.VK_D: //右键
                        if(snake.getDirection()!=Direction.LEFT){
                            snake.setDirection(Direction.RIGHT);
                        }
                        break;
                }
            }
        });
    }

    //初始化定时器
    private void initTimer() {
        //创建定时器对象
        timer=new Timer();

        //初始化定时任务
        TimerTask timerTask=new TimerTask() {
            @Override
            public void run() {
                snake.move();
                //判断蛇头是否和食物重合
                Node head = snake.getBody().getFirst();
                if(head.getX()==food.getX()&&head.getY()==food.getY()){
                    snake.eat(food);
                    food.random();
                }
                //重绘游戏棋盘
                jPanel.repaint();
            }
        };

        //每100毫秒,执行一次定时任务
        timer.scheduleAtFixedRate(timerTask,0,100);
    }

    private void initSnake() {
        snake=new Snake();
    }

    //初始化游戏棋盘
    private void initGamePanel() {
        jPanel=new JPanel(){
            //绘制游戏棋盘中的内容
            @Override
            public void paint(Graphics g) {
                //清空棋盘
                g.clearRect(0,0,600,600);

                //Graphics g 可以看做是一个画笔,它提供了很多方法可以来绘制一些基本的图形(直线、矩形)
                //绘制40条横线
                for (int i = 0; i <=40; i++) {
                    g.drawLine(0,i*15,600,i*15);
                }
                //绘制40条竖线  第n条: (n*15,0)      (n*15,600)
                for (int i = 0; i <=40; i++) {
                    g.drawLine(i*15,0,i*15,600);
                }

                //绘制蛇
                LinkedList<Node> body = snake.getBody();
                for (Node node : body) {
                    g.fillRect(node.getX()*15,node.getY()*15,15,15);
                }

                //绘制食物
                g.fillRect(food.getX()*15,food.getY()*15,15,15);
            }
        };

        //把棋盘添加到窗体中
        add(jPanel);
    }

    //初始化窗体参数
    private void initFrame() {
        //窗体宽高
        setSize(610,640);
        //窗体的位置
        setLocation(400,400);
        //关闭按钮
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //窗体大小不可变
        setResizable(false);
    }

    public static void main(String[] args) {
        //创建窗体对象,并显示
        new MainFrame().setVisible(true);
    }
}

项目三

import tkinter as tk
from mazegenerator import mazeutils
import numpy as np
import math
import threading
import time
import random
import copy


class UnionSet(object):
    """
    并查集实现,构造函数中的matrix是一个numpy类型
    """

    def __init__(self, arr):
        self.parent = {pos: pos for pos in arr}
        self.count = len(arr)

    def find(self, root):
        if root == self.parent[root]:
            return root
        return self.find(self.parent[root])

    def union(self, root1, root2):
        self.parent[self.find(root1)] = self.find(root2)


class Maze(object):
    """
    迷宫生成类
    """

    def __init__(self, width=11, height=11):
        assert width >= 5 and height >= 5, "Length of width or height must be larger than 5."

        self.width = (width // 2) * 2 + 1
        self.height = (height // 2) * 2 + 1
        self.start = [1, 0]
        self.destination = [self.height - 2, self.width - 1]
        self.matrix = None
        self.path = []



    def generate_matrix_dfs(self):
        # 地图初始化,并将出口和入口处的值设置为0
        self.matrix = -np.ones((self.height, self.width))
        self.matrix[self.start[0], self.start[1]] = 0
        self.matrix[self.destination[0], self.destination[1]] = 0

        visit_flag = [[0 for i in range(self.width)] for j in range(self.height)]

        def check(row, col, row_, col_):
            temp_sum = 0
            for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                temp_sum += self.matrix[row_ + d[0]][col_ + d[1]]
            return temp_sum <= -3

        def dfs(row, col):
            visit_flag[row][col] = 1
            self.matrix[row][col] = 0
            if row == self.start[0] and col == self.start[1] + 1:
                return

            directions = [[0, 2], [0, -2], [2, 0], [-2, 0]]
            random.shuffle(directions)
            for d in directions:
                row_, col_ = row + d[0], col + d[1]
                if row_ > 0 and row_ < self.height - 1 and col_ > 0 and col_ < self.width - 1 and visit_flag[row_][
                    col_] == 0 and check(row, col, row_, col_):
                    if row == row_:
                        visit_flag[row][min(col, col_) + 1] = 1
                        self.matrix[row][min(col, col_) + 1] = 0
                    else:
                        visit_flag[min(row, row_) + 1][col] = 1
                        self.matrix[min(row, row_) + 1][col] = 0
                    dfs(row_, col_)

        dfs(self.destination[0], self.destination[1] - 1)
        self.matrix[self.start[0], self.start[1] + 1] = 0

    # prim算法
    def generate_matrix_prim(self):
        # 地图初始化,并将出口和入口处的值设置为0
        self.matrix = -np.ones((self.height, self.width))

        def check(row, col):
            temp_sum = 0
            for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                temp_sum += self.matrix[row + d[0]][col + d[1]]
            return temp_sum < -3

        queue = []
        row, col = (np.random.randint(1, self.height - 1) // 2) * 2 + 1, (
                    np.random.randint(1, self.width - 1) // 2) * 2 + 1
        queue.append((row, col, -1, -1))
        while len(queue) != 0:
            row, col, r_, c_ = queue.pop(np.random.randint(0, len(queue)))
            if check(row, col):
                self.matrix[row, col] = 0
                if r_ != -1 and row == r_:
                    self.matrix[row][min(col, c_) + 1] = 0
                elif r_ != -1 and col == c_:
                    self.matrix[min(row, r_) + 1][col] = 0
                for d in [[0, 2], [0, -2], [2, 0], [-2, 0]]:
                    row_, col_ = row + d[0], col + d[1]
                    if row_ > 0 and row_ < self.height - 1 and col_ > 0 and col_ < self.width - 1 and self.matrix[row_][
                        col_] == -1:
                        queue.append((row_, col_, row, col))

        self.matrix[self.start[0], self.start[1]] = 0
        self.matrix[self.destination[0], self.destination[1]] = 0

    # 递归切分算法,还有问题,现在不可用
    def generate_matrix_split(self):
        # 地图初始化,并将出口和入口处的值设置为0
        self.matrix = -np.zeros((self.height, self.width))
        self.matrix[0, :] = -1
        self.matrix[self.height - 1, :] = -1
        self.matrix[:, 0] = -1
        self.matrix[:, self.width - 1] = -1

        # 随机生成位于(start, end)之间的偶数
        def get_random(start, end):
            rand = np.random.randint(start, end)
            if rand & 0x1 == 0:
                return rand
            return get_random(start, end)

        # split函数的四个参数分别是左上角的行数、列数,右下角的行数、列数,墙壁只能在偶数行,偶数列
        def split(lr, lc, rr, rc):
            if rr - lr < 2 or rc - lc < 2:
                return

            # 生成墙壁,墙壁只能是偶数点
            cur_row, cur_col = get_random(lr, rr), get_random(lc, rc)
            for i in range(lc, rc + 1):
                self.matrix[cur_row][i] = -1
            for i in range(lr, rr + 1):
                self.matrix[i][cur_col] = -1

            # 挖穿三面墙得到连通图,挖孔的点只能是偶数点
            wall_list = [
                ("left", cur_row, [lc + 1, cur_col - 1]),
                ("right", cur_row, [cur_col + 1, rc - 1]),
                ("top", cur_col, [lr + 1, cur_row - 1]),
                ("down", cur_col, [cur_row + 1, rr - 1])
            ]
            random.shuffle(wall_list)
            for wall in wall_list[:-1]:
                if wall[2][1] - wall[2][0] < 1:
                    continue
                if wall[0] in ["left", "right"]:
                    self.matrix[wall[1], get_random(wall[2][0], wall[2][1] + 1) + 1] = 0
                else:
                    self.matrix[get_random(wall[2][0], wall[2][1] + 1), wall[1] + 1] = 0

            # self.print_matrix()
            # time.sleep(1)
            # 递归
            split(lr + 2, lc + 2, cur_row - 2, cur_col - 2)
            split(lr + 2, cur_col + 2, cur_row - 2, rc - 2)
            split(cur_row + 2, lc + 2, rr - 2, cur_col - 2)
            split(cur_row + 2, cur_col + 2, rr - 2, rc - 2)

            self.matrix[self.start[0], self.start[1]] = 0
            self.matrix[self.destination[0], self.destination[1]] = 0

        split(0, 0, self.height - 1, self.width - 1)

    # 最小生成树算法-kruskal(选边法)思想生成迷宫地图,这种实现方法最复杂。
    def generate_matrix_kruskal(self):
        # 地图初始化,并将出口和入口处的值设置为0
        self.matrix = -np.ones((self.height, self.width))

        def check(row, col):
            ans, counter = [], 0
            for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                row_, col_ = row + d[0], col + d[1]
                if row_ > 0 and row_ < self.height - 1 and col_ > 0 and col_ < self.width - 1 and self.matrix[
                    row_, col_] == -1:
                    ans.append([d[0] * 2, d[1] * 2])
                    counter += 1
            if counter <= 1:
                return []
            return ans

        nodes = set()
        row = 1
        while row < self.height:
            col = 1
            while col < self.width:
                self.matrix[row, col] = 0
                nodes.add((row, col))
                col += 2
            row += 2

        unionset = UnionSet(nodes)
        while unionset.count > 1:
            row, col = nodes.pop()
            directions = check(row, col)
            if len(directions):
                random.shuffle(directions)
                for d in directions:
                    row_, col_ = row + d[0], col + d[1]
                    if unionset.find((row, col)) == unionset.find((row_, col_)):
                        continue
                    nodes.add((row, col))
                    unionset.count -= 1
                    unionset.union((row, col), (row_, col_))

                    if row == row_:
                        self.matrix[row][min(col, col_) + 1] = 0
                    else:
                        self.matrix[min(row, row_) + 1][col] = 0
                    break

        self.matrix[self.start[0], self.start[1]] = 0
        self.matrix[self.destination[0], self.destination[1]] = 0

    # 迷宫寻路算法DFS
    def find_path_dfs(self, destination):
        visited = [[0 for i in range(self.width)] for j in range(self.height)]

        def dfs(path):
            visited[path[-1][0]][path[-1][1]] = 1
            if path[-1][0] == destination[0] and path[-1][1] == destination[1]:
                self.path = path[:]
                return
            for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                row_, col_ = path[-1][0] + d[0], path[-1][1] + d[1]
                if row_ > 0 and row_ < self.height - 1 and col_ > 0 and col_ < self.width and visited[row_][
                    col_] == 0 and self.matrix[row_][col_] == 0:
                    dfs(path + [[row_, col_]])

        dfs([[self.start[0], self.start[1]]])


if __name__ == '__main__':
    maze = Maze(51, 51)
    maze.generate_matrix_kruskal()
    maze.find_path_dfs(maze.destination)



def draw_cell(canvas, row, col, color="#FFFFFF"):
    x0, y0 = col * cell_width, row * cell_width
    x1, y1 = x0 + cell_width, y0 + cell_width
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline=color, width=0)


def draw_path(canvas, matrix, row, col, color, line_color):
    # 列
    if row + 1 < rows and matrix[row - 1][col] >= 1 and matrix[row + 1][col] >= 1:
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width
        x1, y1 = x0 + cell_width / 5, y0 + cell_width
    # 行
    elif col + 1 < cols and matrix[row][col - 1] >= 1 and matrix[row][col + 1] >= 1:
        x0, y0 = col * cell_width, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + cell_width, y0 + cell_width / 5
    # 左上角
    elif col + 1 < cols and row + 1 < rows and matrix[row][col + 1] >= 1 and matrix[row + 1][col] >= 1:
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + 3 * cell_width / 5, y0 + cell_width / 5
        canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline=line_color, width=0)
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + cell_width / 5, y0 + 3 * cell_width / 5
    # 右上角
    elif row + 1 < rows and matrix[row][col - 1] >= 1 and matrix[row + 1][col] >= 1:
        x0, y0 = col * cell_width, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + 3 * cell_width / 5, y0 + cell_width / 5
        canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline=line_color, width=0)
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + cell_width / 5, y0 + 3 * cell_width / 5
    # 左下角
    elif col + 1 < cols and matrix[row - 1][col] >= 1 and matrix[row][col + 1] >= 1:
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width
        x1, y1 = x0 + cell_width / 5, y0 + 3 * cell_width / 5
        canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline=line_color, width=0)
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + 3 * cell_width / 5, y0 + cell_width / 5
    # 右下角
    elif matrix[row - 1][col] >= 1 and matrix[row][col - 1] >= 1:
        x0, y0 = col * cell_width, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + 3 * cell_width / 5, y0 + cell_width / 5
        canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline=line_color, width=0)
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width
        x1, y1 = x0 + cell_width / 5, y0 + 3 * cell_width / 5
    else:
        x0, y0 = col * cell_width + 2 * cell_width / 5, row * cell_width + 2 * cell_width / 5
        x1, y1 = x0 + cell_width / 5, y0 + cell_width / 5
    canvas.create_rectangle(x0, y0, x1, y1, fill=color, outline=line_color, width=0)


def draw_maze(canvas, matrix, path, moves):
    """
    根据matrix中每个位置的值绘图:
    -1: 墙壁
    0: 空白
    1: 参考路径
    2: 移动过的位置
    """
    for r in range(rows):
        for c in range(cols):
            if matrix[r][c] == 0:
                draw_cell(canvas, r, c)
            elif matrix[r][c] == -1:
                draw_cell(canvas, r, c, '#330000')
            elif matrix[r][c] == 1:
                draw_cell(canvas, r, c)
                draw_path(canvas, matrix, r, c, '#E5FFCC', '#E5FFCC')
            elif matrix[r][c] == 2:
                draw_cell(canvas, r, c)
                draw_path(canvas, matrix, r, c, '#CCCCFF', '#CCCCFF')
    for p in path:
        matrix[p[0]][p[1]] = 1
    for move in moves:
        matrix[move[0]][move[1]] = 2


def update_maze(canvas, matrix, path, moves):
    canvas.delete("all")
    matrix = copy.copy(matrix)
    for p in path:
        matrix[p[0]][p[1]] = 1
    for move in moves:
        matrix[move[0]][move[1]] = 2

    row, col = movement_list[-1]
    colors = ['#330000', '#F2F2F2', '#330000', '#F2F2F2', '#330000', '#F2F2F2', '#330000', '#F2F2F2']
    if level > 2:
        colors = ['#232323', '#252525', '#2a2a32', '#424242', '#434368', '#b4b4b4', '#525288', '#F2F2F2']

    for r in range(rows):
        for c in range(cols):
            distance = (row - r) * (row - r) + (col - c) * (col - c)
            if distance >= 100:
                color = colors[0:2]
            elif distance >= 60:
                color = colors[2:4]
            elif distance >= 30:
                color = colors[4:6]
            else:
                color = colors[6:8]

            if matrix[r][c] == 0:
                draw_cell(canvas, r, c, color[1])
            elif matrix[r][c] == -1:
                draw_cell(canvas, r, c, color[0])
            elif matrix[r][c] == 1:
                draw_cell(canvas, r, c, color[1])
                draw_path(canvas, matrix, r, c, '#00FF22', '#00FF22')
            elif matrix[r][c] == 2:
                draw_cell(canvas, r, c, color[1])
                draw_path(canvas, matrix, r, c, '#ee3f4d', '#ee3f4d')





def _eventHandler(event):
    global movement_list
    global click_counter
    global next_maze_flag
    global level

    if not next_maze_flag and event.keysym in ['A', 'D', 'W', 'S']:
        click_counter += 1
        windows.title("Maze Level-{} Steps-{}".format(level, click_counter))
        cur_pos = movement_list[-1]
        ops = {'A': [0, -1], 'D': [0, 1], 'W': [-1, 0], 'S': [1, 0]}
        r_, c_ = cur_pos[0] + ops[event.keysym][0], cur_pos[1] + ops[event.keysym][1]
        if len(movement_list) > 1 and [r_, c_] == movement_list[-2]:
            movement_list.pop()
            while True:
                cur_pos = movement_list[-1]
                counter = 0
                for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                    r_, c_ = cur_pos[0] + d[0], cur_pos[1] + d[1]
                    if c_ >= 0 and maze.matrix[r_][c_] == 0:
                        counter += 1
                if counter != 2:
                    break
                movement_list.pop()
        elif r_ < maze.height and c_ < maze.width and maze.matrix[r_][c_] == 0:
            while True:
                movement_list.append([r_, c_])
                temp_list = []
                for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                    r__, c__ = r_ + d[0], c_ + d[1]
                    if c__ < maze.width and maze.matrix[r__][c__] == 0 and [r__, c__] != cur_pos:
                        temp_list.append([r__, c__])
                if len(temp_list) != 1:
                    break
                cur_pos = [r_, c_]
                r_, c_ = temp_list[0]
        update_maze(canvas, maze.matrix, maze.path, movement_list)

    elif next_maze_flag:
        next_maze_flag = False
        movement_list = [maze.start]
        click_counter = 0
        maze.generate_matrix_kruskal()
        maze.path = []
        draw_maze(canvas, maze.matrix, maze.path, movement_list)
        level += 1


def _paint(event):
    x, y = math.floor((event.y - 1) / cell_width), math.floor((event.x - 1) / cell_width)
    if maze.matrix[x][y] == 0:
        maze.find_path_dfs([x, y])
        update_maze(canvas, maze.matrix, maze.path, movement_list)


def _reset(event):
    maze.path = []
    update_maze(canvas, maze.matrix, maze.path, movement_list)


if __name__ == '__main__':
    # 基础参数
    cell_width = 10
    rows = 30
    cols = 40
    height = cell_width * rows
    width = cell_width * cols
    level = 1
    click_counter = 0
    next_maze_flag = False

    windows = tk.Tk()
    windows.title("迷宫")
    canvas = tk.Canvas(windows, background="#F2F2F2", width=width, height=height)
    canvas.pack()

    maze = Maze(cols, rows)
    movement_list = [maze.start]
    maze.generate_matrix_kruskal()
    draw_maze(canvas, maze.matrix, maze.path, movement_list)

    canvas.bind("<Button-1>", _paint)
    canvas.bind("<Button-3>", _reset)
    canvas.bind_all("<KeyPress>", _eventHandler)
    windows.mainloop()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值