软件技术实习项目三 迷宫

项目准备

需求分析

1.prime算法生成迷宫

2.A*算法实现自动寻路

编程语言及开发工具

JAVA,IDEA

项目软件概述

界面

 功能

1.能随机生成迷宫

2.自动寻路功能

代码

Main

import javax.swing.*;
public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setTitle("Remake(R)  Help(H)");
        frame.setSize(365,385);
        Maze maze = new Maze();
        frame.add(maze);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

CreateMaze

import java.util.Random;

class CreateMaze {
    public static int L;
    public static int[][] map;
    private static int size;
    CreateMaze(int l) {//保证行数和列数是奇数
        size=2*l+1;
        L=l;
        map = new int[size][size];
    }
    public static int[][] Init() {
        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++)
                map[i][j] = 0;// 0 为墙 1为路
        for (int i = 0; i < L; i++)
            for (int j = 0; j < L; j++)
                map[2 * i + 1][2 * j + 1] = 1;
        Prime();
        return map;
    }
    public static void Prime() {
        int[] Y, N;
        int sum = L * L;
        Y = new int[sum];
        N = new int[sum];
        int[] LR = {-1, 1, 0, 0};
        int[] UD = {0, 0, 1, -1};
        int[] S = {-1, 1, L, -L};
        for (int i = 0; i < sum; i++) {
            Y[i] =0;
            N[i] = 0;
        }
        // 起点
        Random rd = new Random();
        int random = rd.nextInt(sum);
        Y[0] = random;
        N[random] = 1;
        int count = 0;
        while (true) {
            int x = random % L;//坐标
            int y = random / L;
            int direction = -1;//保存方向,若没有方向可走,就默认为-1
            int i = 0;
            while (++i < 5) {
                int dir = rd.nextInt(4);
                int repos;
                int x1, y1;
                repos = random + S[dir];
                x1 = x + LR[dir];
                y1 = y + UD[dir];
                if (y1 >= 0 && x1 >= 0 && x1 < L && y1 < L && repos >= 0 && repos < sum
                        && N[repos] != 1) {
                    N[repos] = 1;
                    Y[++count] = repos;
                    random = repos;
                    direction = dir;
                    map[2 * x + 1 + LR[dir]][2 * y + 1 + UD[dir]] = 1;
                    break;
                } else {
                    if (count == sum - 1)
                        return;
                }
            }
            if (direction < 0) {
                random = Y[rd.nextInt(count + 1)];
            }
        }
    }
}

A*

import java.util.ArrayList;
import java.util.List;

class A {
    public static int[][] NODES;//定义一个迷宫单元数组
    public  int STEP = 10;//设每一步的权值为10
    private final ArrayList<Node> openList = new ArrayList<>();//维护一个开放列表
    private final ArrayList<Node> closeList = new ArrayList<>();//维护一个关闭列表
    A(int[][] map) {
        NODES=map;//初始化迷宫单元为新生成的对应地图,把Maze类里面生成的地图传给NODES,再在此地图基础上用A*算法寻路径
        Node startNode = new Node(Maze.cx, Maze.cy);//起点
        Node endNode = new Node(map.length-2, map.length-2);//终点
        Node parent = findPath(startNode, endNode); //父节点
        ArrayList<Node> arrayList = new ArrayList<Node>();
        while (parent != null) {
            arrayList.add(new Node(parent.x, parent.y));
            parent = parent.parent;
        }
        for (int i = 0; i < NODES.length; i++) {
            for (int j = 0; j < NODES.length; j++) {
                if (exists(arrayList, i, j)) {
                    NODES[i][j]=3;//标记关闭列表里的方格为2,为了方便后面在界面画系统寻路路径
                }
            }
        }
    }
    public static int[][] ans(){
        return NODES;
    }
    //寻找开放列表里F值最小的节点的方法
    public Node findMinFNodeInOpneList() {
        Node tempNode = openList.get(0);
        for (Node node : openList) {
            if (node.F < tempNode.F) {
                tempNode = node;
            }
        }
        return tempNode;
    }
    //遍历当前节点上下左右四个邻居的方法,
    public ArrayList<Node> findNeighborNodes(Node currentNode) {
        ArrayList<Node> arrayList = new ArrayList<>();
        // 只考虑上下左右,不考虑斜对角
        int topX = currentNode.x;
        int topY = currentNode.y - 1;
        if (canReach(topX, topY) && !exists(closeList, topX, topY)) {
            arrayList.add(new Node(topX, topY));
        }
        int bottomX = currentNode.x;
        int bottomY = currentNode.y + 1;
        if (canReach(bottomX, bottomY) && !exists(closeList, bottomX, bottomY)) {
            arrayList.add(new Node(bottomX, bottomY));
        }
        int leftX = currentNode.x - 1;
        int leftY = currentNode.y;
        if (canReach(leftX, leftY) && !exists(closeList, leftX, leftY)) {
            arrayList.add(new Node(leftX, leftY));
        }
        int rightX = currentNode.x + 1;
        int rightY = currentNode.y;
        if (canReach(rightX, rightY) && !exists(closeList, rightX, rightY)) {
            arrayList.add(new Node(rightX, rightY));
        }
        return arrayList;
    }

    //判断此处坐标是否可达,若超界或者是墙则不可达
    public boolean canReach(int x, int y) {
        return x >= 0 && x < NODES.length && y >= 0 && y < NODES.length && NODES[x][y] == 1;
    }

    //A*寻路过程
    public Node findPath(Node startNode, Node endNode) {
        openList.add(startNode);// 把起点加入 open list
        while (openList.size() > 0) {
            Node currentNode = findMinFNodeInOpneList();// 遍历 open list ,查找 F值最小的节点,把它作为当前要处理的节点
            openList.remove(currentNode);// 从open list中移除
            closeList.add(currentNode);// 把这个节点移到 close list
            ArrayList<Node> neighborNodes = findNeighborNodes(currentNode);
            for (Node node : neighborNodes) {//遍历四个邻居
                if (exists(openList, node)) {
                    foundPoint(currentNode, node);
                } else {
                    notFoundPoint(currentNode, endNode, node);
                }
            }
            if (find(openList, endNode) != null) {
                return find(openList, endNode);//找到终点了并返回
            }
        }
        return find(openList, endNode);
    }

    //在列表里可以找到节点后的情况
    private void foundPoint(Node tempStart, Node node) {
        int G = calcG(node);
        if (G < node.G) {
            node.parent = tempStart;
            node.G = G;
            node.calcF();
        }
    }

    //在节点里找不到节点的情况
    private void notFoundPoint(Node tempStart, Node end, Node node) {
        node.parent = tempStart;
        node.G = calcG(node);
        node.H = calcH(end, node);
        node.calcF();
        openList.add(node);
    }

    //计算G值的方法
    private int calcG(Node node) {
        int G = STEP;
        int parentG = node.parent != null ? node.parent.G : 0;
        return G + parentG;
    }

    //计算H值的方法
    private int calcH(Node end, Node node) {
        int step = Math.abs(node.x - end.x) + Math.abs(node.y - end.y);
        return step * STEP;
    }

    //找到终点的方法
    public static Node find(List<Node> nodes, Node point) {
        for (Node n : nodes)
            if ((n.x == point.x) && (n.y == point.y)) {
                return n;
            }
        return null;
    }

    //下面两个是exist方法的重载,判断不同参数情况时节点是否在列表里
    public static boolean exists(List<Node> nodes, Node node) {
        for (Node n : nodes) {
            if ((n.x == node.x) && (n.y == node.y)) {
                return true;
            }
        }
        return false;
    }

    public static boolean exists(List<Node> nodes, int x, int y) {
        for (Node n : nodes) {
            if ((n.x == x) && (n.y == y)) {
                return true;
            }
        }
        return false;
    }

    //节点类,定义了每一个节点的属性
    public static class Node {
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public int x;
        public int y;
        public int F;
        public int G;
        public int H;
        public void calcF() {
            this.F = this.G + this.H;
        }
        public Node parent;
    }
}

Maze

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Maze extends JPanel implements KeyListener,ActionListener {
    public final static int wall = 0;
    public final static int current = 2;
    static int cx = 1; //当前位置
    static int cy = 1;
    static int[][] map;
    static int i=0;
    public static void Map() {
        CreateMaze createMaze = new CreateMaze(16);
        map = CreateMaze.Init();
        map[1][1] = 2;
        cx = 1;
        cy = 1;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        this.addKeyListener(this);
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map.length; j++) {
                if (map[i][j] == 0) {
                    g.setColor(Color.BLACK);
                    g.fillRect(10 * i + 10, 10 * j + 10, 10, 10);
                }
                else if(map[i][j]==3){
                    g.setColor(Color.blue);
                    g.fillOval(10 * i + 12, 10 * j + 12, 5, 5);
                }
                else if (map[i][j] == 2) {
                    g.setColor(Color.red);
                    g.fillRect(10 * i + 10, 10 * j + 10, 10, 10);
                }
            }
        }
        g.setColor(Color.white);
        g.fillRect(10  , 10 + 10, 10, 10);//画入口
        g.fillRect(map.length*10  , map.length*10-10, 10, 10);
        g.setColor(Color.red);
        if (gameOver()) {
            g.setFont(new Font("黑体", Font.BOLD, 30));
            g.drawString("游戏胜利,按R重新开始", 20, 180);
        }
    }
    //将A*算法得出的路径返回给map
    public void ans() {
        A aStart = new A(map);
        map = A.ans();
    }

    public Maze() {
        Map();
        this.setFocusable(true);
        this.addKeyListener(this);
    }

    //判断游戏结束
    public static boolean gameOver() {
        return map.length - 2 == cx && map.length - 2 == cy;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        int x = cx, y = cy;
        if(!gameOver()) {
            if (key == KeyEvent.VK_LEFT && map[x - 1][y] != Maze.wall &&i==0) {//左移
                map[x - 1][y] = Maze.current;   //更改当前位置到移动到的位置
                map[x][y] = 1;//恢复地图原有的图标
                cx--;i++;
            } else if (key == KeyEvent.VK_RIGHT&&map[x + 1][y] != Maze.wall &&i==0) {
                map[x + 1][y] = Maze.current;  //右移
                map[x][y] = 1;
                cx++;i++;
            } else if (key == KeyEvent.VK_UP&&map[x][y - 1] != Maze.wall &&i==0) {
                map[x][y - 1] = Maze.current;  //上移
                map[x][y] = 1;
                cy--;i++;
            } else if (key == KeyEvent.VK_DOWN&&map[x][y + 1] != Maze.wall &&i==0) {
                map[x][y + 1] = 2;   //下移
                map[x][y] = 1;
                cy++;i++;
            }else if(key == KeyEvent.VK_H&&i==0){   //显示路径
                ans();
            }else if(key == KeyEvent.VK_R&&i==0){   //重置迷宫
                Map();
            }
        }else if(key == KeyEvent.VK_R&&i==0){   //游戏胜利按下R重新开始
            Map();
        }
        repaint();   //刷新游戏界面
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {

        i=0;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值