Astart
import java.util.ArrayList;
import java.util.List;
public class AStart {
public static int[][] NODES;
public int STEP = 10;
private ArrayList<Node> openList = new ArrayList<Node>();
private ArrayList<Node> closeList = new ArrayList<Node>();
public AStart() {
NODES=Maze.LabId;
Node startNode = new Node(1, 1);//起点
Node endNode = new Node(19, 19);//终点
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;
}
System.out.println("\n"+"打印有路径的地图:");
for (int i = 0; i < NODES.length; i++) {
for (int j = 0; j < NODES.length; j++) {
if (exists(arrayList, i, j)) {
NODES[i][j]=2;
}
System.out.print(NODES[i][j] + " ");
}
System.out.println();
}
}
//寻找开放列表里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<Node>();
// 只考虑上下左右,不考虑斜对角
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) {
if (x >=0 && x < NODES.length && y >=0 && y < NODES.length && NODES[x][y]==1) {
return true;
}
return false;
}
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(tempStart, 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(tempStart, node);
node.H = calcH(end, node);
node.calcF();
openList.add(node);
}
//计算G值的方法
private int calcG(Node start, Node node) {
int G = STEP;
int parentG = node.parent != null ? node.parent.G : 0;
return G + parentG;
}
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 java.util.Random;
public class Maze {
public static int row = 10;// 初始地图有路的迷宫单元行数
public static int column = 10;// 初始地图有路的迷宫单元列数
public static int r = 2 * row + 1;// 迷宫单元行数,保证是奇数
public static int c = 2 * column + 1;// 迷宫单元列数,保证是奇数
public static int[][] LabId;// 存放迷宫的数组,迷宫单元数组
Random rand = new Random();
public Maze() {
LabId = new int[r][c];
System.out.println("初始化地图:");
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
LabId[i][j] = 0;// 将所有格子都设为墙, 0 为墙 1为路
if (i % 2 == 1 && j % 2 == 1)// 将奇数行奇数列设为路,1为路,0为墙
LabId[i][j] = 1;
System.out.print(LabId[i][j] + " ");// 打印初始化地图,在控制台输出查看
}
System.out.println();
}
// 调用深度优先搜索算法
accLabDFS();
System.out.println("\n" + "生成迷宫:");
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
System.out.print(LabId[i][j] + " ");// 打印生成的深度优先算法生成的迷宫,在控制台输出查看
}
System.out.println();
}
}
// 实现深度优先算法
public void accLabDFS() {
int[] lab;// 访问队列
int count = row * column;// 所有的迷宫单元数,不包括墙
lab = new int[count];
for (int i = 0; i < count; i++)
lab[i] = 0;// 设置所有单元都为未访问过的,0表示未访问过,1表示已访问过
for (int v = 0; v < count; v++) {// 从第0个点开始遍历
if (lab[v] != 1) {// 如果该单元还未被访问,则递归调用深度优先算法遍历
DFS(lab, v);
}
}
}
public void DFS(int[] LabG, int v) {
LabG[v] = 1;// 访问顶点
int[] neighbor = { v + row, v - row, v - 1, v + 1 };// 该点的四个邻居 上下左右
int[] offR = { 0, 0, -1, 1 }, offC = { 1, -1, 0, 0 };// Row上个方向的偏移 Column上各方向的偏移,上下左右
int[] tag = { -1, -1, -1, -1 };// 记录打通位置
int n = 0;// 打通的次数
while (n < 4) {// 上下左右四个方向都遍历,
int i = rand.nextInt(4);// 随机打通一个方向
if (tag[i] == 1)
continue;// 进入下一轮循环
tag[i] = 1;// 打通墙,设为1
n++;
int w = neighbor[i];// 定义一个该方向上的邻居
if (w > LabG.length - 1 || w < 0)
continue; // w不存在,即该方向上没有邻居
// 取出现在的v点的位置
int x = v % row;
int y = v / row;
// 遍历到四个边界时再往边界方向就没有邻居了,进入下一轮循环
if (i == 0 && y == column - 1)
continue;// 上方向
if (i == 1 && y == 0)
continue;// 下方向
if (i == 2 && x == 0)
continue;// 左方向
if (i == 3 && x == row - 1)
continue;// 右方向
// 如果该点有未访问的邻居,则把该点与其邻居间的墙打通,即相邻的格子中间的位置放1
if (LabG[w] == 0) {
LabId[2 * x + 1 + offR[i]][2 * y + 1 + offC[i]] = 1;
DFS(LabG, w);// 递归
}
}
}
}
Panel
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Panel extends JPanel implements MouseListener, KeyListener{
Maze M = new Maze();
AStart A = new AStart();
private JPanel jp = new JPanel();
private JButton answer = new JButton("路径");
private JButton hide = new JButton("隐藏");
private JButton reset = new JButton("重置");
private JButton exit = new JButton("退出");
private JButton start = new JButton("开始");
BufferedImage wall = null;
BufferedImage bj = null;
BufferedImage victory = null;
BufferedImage my = null;
int myx = 1;
int myy = 1;
int endx;
int endy;
boolean isVictory = false;
boolean isWin = false;
boolean isBegin = true;
boolean ans = false;
public Panel() {
this.setName("迷宫");// 设置标题
this.setLayout(null);
answer.setBounds(470, 130, 90, 30);
hide.setBounds(470, 210, 90, 30);
reset.setBounds(470, 290, 90, 30);
exit.setBounds(470, 370, 90, 30);
start.setBounds(470, 450, 90, 30);
answer.addMouseListener(this);
hide.addMouseListener(this);
reset.addMouseListener(this);
exit.addMouseListener(this);
start.addMouseListener(this);
start.addKeyListener(this);
this.add(jp);
this.add(start);
this.add(answer);
this.add(hide);
this.add(reset);
this.add(exit);
try {
bj = ImageIO.read(new File("images/bj.jpg"));// 放窗口背景图片
victory=ImageIO.read(new File("images/victory.png"));
wall = ImageIO.read(new File("images/wall.jpg"));// 放墙的图片
my = ImageIO.read(new File("images/my.png"));// 放墙的图片
} catch (IOException e) {
e.printStackTrace();
}
}
// 画组件
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(20, 80, 420, 420);
g.drawImage(bj, 0, 0, this);
g.setColor(Color.ORANGE);
g.setFont(new Font("隶书", Font.BOLD, 40));
g.drawString("迷宫小游戏", 160, 50);
// 画迷宫
for (int i = 0; i < M.LabId.length; i++) {
for (int j = 0; j < M.LabId[0].length; j++) {
if (M.LabId[i][j] == 0) {
g.drawImage(wall, 20 + i * 20, 80 + j * 20, this);
}
}
}
// 画A*路径
if (ans) {
for (int i = 0; i < A.NODES.length; i++) {
for (int j = 0; j < A.NODES[0].length; j++) {
if (A.NODES[i][j] == 2) {
g.fillOval(20 + 20 * i, 80 + 20 * j, 18, 18);
}
}
}
}
g.setColor(Color.orange);
g.fillRect(40, 100, 20, 20);// 画起点
g.fillRect(400, 460, 20, 20);// 画终点
g.drawImage(my, 20 + 20 * myx, 80 + 20 * myy, this);// 画角色
// 判断是否到达终点
if (this.myx ==19 && this.myy ==19) {
isVictory = true;
}
if (isBegin){
g.drawString("按下开始开始游戏", 150, 300);
}
if (isVictory) {
g.drawImage(victory, 60,180, this);// 画角色
g.drawString("按下空格重置或点击重置", 20, 445);
g.setColor(Color.ORANGE);
}
}
// 鼠标监听
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource().equals(answer)) {
ans = true;
isVictory=false;
}
if (e.getSource().equals(hide)) {
ans = false;
isVictory=false;
}
if (e.getSource().equals(reset)) {
ans = false;
isVictory=false;
myx = 1;
myy = 1;
new Panel();
}
if (e.getSource().equals(exit)) {
System.exit(0);
}
if (e.getSource().equals(start)) {
ans = false;
isVictory=false;
isBegin = false;
new Panel();
myx = 1;// 开始游戏,角色从起点开始出发
myy = 1;
}
repaint();
}
// 键盘监听
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
int k = e.getKeyCode();
if (k == KeyEvent.VK_SPACE) {
isBegin = false;
ans = false;
isVictory=false;
new Panel();
myx = 1;// 开始游戏,角色从起点开始出发
myy = 1;
}
if (k == KeyEvent.VK_A && A.NODES[myx - 1][myy] != 0 && myx - 1 >= 1) {
myx--;
}
if (k == KeyEvent.VK_D && A.NODES[myx + 1][myy] != 0 && myx + 1 <= 21) {
myx++;
}
if (k == KeyEvent.VK_W && A.NODES[myx][myy - 1] != 0 && myy - 1 >= 1) {
myy--;
}
if (k == KeyEvent.VK_S && A.NODES[myx][myy + 1] != 0 && myy + 1 <= 21) {
myy++;
}
repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
Test
import java.awt.Toolkit;
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("迷宫小游戏");
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
frame.setSize(600, 600);
frame.setLocation((width - 600) / 2, (height - 600) / 2);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Panel());
frame.setFocusable(true);
frame.setVisible(true);
frame.requestFocus();
}
}