实验项目三

import javax.swing.*;

import java.awt.*;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import java.util.Stack;

class Node {

public int x,y;

public Node parent;

public Node(int x, int y) {

this.x = x;

this.y = y;

}

public int F;//F为估价函数

public int G;

public int H;

public void calcF() {

this.F = this.G + this.H;

}

}

public class Maze extends JPanel implements KeyListener {

final static int wall = 0;

final static int road = 1;

static int[][] mMap;

boolean[][] visit;

static int num = 21;

int width = 21;

Node start = new Node(1, 1);

Node end = new Node(num - 2, num - 2);

Node dangqian;

Node next;

Stack<Node> path = new Stack<>();//记录生成地图时遍历的顺序

//走迷宫时用到的变量

private Node movePerson;

List<Integer> xpath = new ArrayList<>();//记录迷宫中行进的轨迹

List<Integer> ypath = new ArrayList<>();

private boolean drawpath = false;

//A*算法使用到的变量

public int sValue = 10;//设每一步的值为10

private ArrayList<Node> openList = new ArrayList<>();

private ArrayList<Node> closeList = new ArrayList<>();

Maze(){

mMap = new int [num][num];

visit = new boolean[num][num];

for (int i = 0; i < num; i = i+2) {//初始化地图的空格

for (int j = 0; j < num; j=j+2){

mMap[i][j] = wall;//其余均为墙

visit[i][j] = false;

}

}

for (int i = 1; i < num; i = i+2) {//初始化地图的空格

for (int j = 1; j < num; j=j+2){

mMap[i][j] = road;//奇数行奇数列的格子均为路

visit[i][j] = false;

}

}

visit[start.x][start.y] = true;

mMap[start.x][start.y] = road;

dangqian = start; //将当前格标记为开始格

movePerson=new Node(start.x-1,start.y);

drawpath=false;

createMaze();

this.addKeyListener(this);

this.setFocusable(true);

}

public void init(){//第一轮结束后,再次初始化地图

mMap = new int [num][num];

visit = new boolean[num][num];

for (int i = 0; i < num; i = i+2) {

for (int j = 0; j < num; j=j+2){

mMap[i][j] = wall;

visit[i][j] = false;

}

}

for (int i = 1; i < num; i = i+2) {//初始化地图的空格

for (int j = 1; j < num; j=j+2){

mMap[i][j] = road;//奇数行奇数列的格子均为路

visit[i][j] = false;

}

}

visit[start.x][start.y] = true;

mMap[start.x][start.y] = road;

dangqian = start; //将当前格标记为开始格

movePerson=new Node(start.x-1,start.y);//设置移动的起始点

drawpath=false;

xpath.clear();//清空行走的路径坐标

ypath.clear();

openList.clear();

closeList.clear();

createMaze();

this.setFocusable(true);

repaint();

}

//深度优先遍历

void createMaze() {

path.push(dangqian); //将当前格压入栈

while(!path.empty()) {

ArrayList<Node> mNei=notVisitedNei(dangqian);

if(mNei.size()==0){//如果该格子没有可访问的邻接格,则跳回上一个格子

dangqian = path.pop();

continue;

}

next = mNei.get(new Random().nextInt(mNei.size()));//随机选取一个邻接格

int x = next.x;

int y = next.y;

if(visit[x][y]){//如果该节点被访问过,则回到上一步继续寻找

dangqian = path.pop();

}

else{//否则将当前格压入栈,标记当前格为已访问,并且在迷宫地图上移除障碍物

path.push(next);

visit[x][y] = true;

mMap[x][y] = road;

mMap[(dangqian.x + x) / 2][(dangqian.y + y) / 2] = road; //打通当前格与下一格

dangqian = next;

}

}

mMap[start.x-1][start.y]=1;

mMap[end.x+1][end.y]=1;

}

public ArrayList<Node> notVisitedNei(Node node)

{

int []nei={2,0,-2,0,2};

ArrayList<Node> list = new ArrayList<Node>();

for(int i = 0; i < nei.length-1; i++)

{

int x = node.x + nei[i];

int y = node.y + nei[i+1];

if( x >= 0 && x < num && y >= 0 && y < num)

{

if(!visit[x][y])//未访问,则入数组

list.add(new Node(x,y));

}

}

return list;

}

public void paintComponent(Graphics g) {

super.paintComponent(g);

this.setBackground(Color.green);

g.setColor(Color.black);

for(int i=0;i<num;i++){

for(int j=0;j<num;j++){

if(mMap[i][j]==0){

g.fillRect(10+i*width,10+j*width,width,width);

}

}

}

g.setColor(Color.BLUE);//画移动的轨迹

for(int i=0;i<xpath.size();i++){

g.fillOval(10+xpath.get(i)*width+width/4 , 10+ypath.get(i)*width+width/4,

width / 2, width / 2);

}

g.setColor(Color.RED);//画点的移动

g.fillOval(10+movePerson.x*width+width/4 , 10+movePerson.y*width+width/4,

width / 2, width / 2);

if(drawpath){//画出A*算法求得的路径

g.setColor(Color.yellow);

Node parent = findPath(start, end); //父节点

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 <num; i++) {

for (int j = 0; j < num; j++) {

if (exists(arrayList, i, j)) {

g.fillOval(10+i*width+width/4 , 10+j*width+width/4,

width / 2, width / 2);

}

}

}

g.fillOval(10+(num-1)*width+width/4, 10+width*(num-2)+width/4, width / 2, width / 2);//终点上色

}

}

private boolean isOutOfBorder(int x, int y) {

if (x > num-1 || y >num-1 || x < 0 || y < 0) {

return true;

}

return false;

}

private void checkWin() {

if (movePerson.x==num-1 && movePerson.y==num-2) {

Object[] options = {"再来一局", "结束"};

int response = JOptionPane.showOptionDialog(this, "恭喜通关","Game Over", JOptionPane.YES_NO_OPTION,

JOptionPane.PLAIN_MESSAGE, null, options, options[0]);

if (response == 0) {

init();

} else {

System.exit(0);

}

}

}

//A*算法

public Node findMinFNodeInOpenList() {//寻找最小移动开销的节点

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 upX = currentNode.x;

int upY = currentNode.y - 1;

if (!isOutOfBorder(upX, upY) && !exists(closeList, upX, upY) && mMap[upX][upY]==1) {

arrayList.add(new Node(upX, upY));

}

int downX = currentNode.x;

int downY = currentNode.y + 1;

if (!isOutOfBorder(downX, downY) && !exists(closeList, downX, downY) && mMap[downX][downY]==1) {

arrayList.add(new Node(downX, downY));

}

int leftX = currentNode.x - 1;

int leftY = currentNode.y;

if (!isOutOfBorder(leftX, leftY) && !exists(closeList, leftX, leftY) && mMap[leftX][leftY]==1) {

arrayList.add(new Node(leftX, leftY));

}

int rightX = currentNode.x + 1;

int rightY = currentNode.y;

if (!isOutOfBorder(rightX, rightY) && !exists(closeList, rightX, rightY) && mMap[rightX][rightY]==1) {

arrayList.add(new Node(rightX, rightY));

}

return arrayList;

}

public Node findPath(Node startNode, Node endNode) {

openList.add(startNode);

while (openList.size()>0){

Node currentNode = findMinFNodeInOpenList();// 遍历 open list ,查找 F值最小的节点,把它作为当前要处理的节点

openList.remove(currentNode);

closeList.add(currentNode);

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 null;

}

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);

}

private int calcG(Node start, Node node) {

int G = sValue;

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 * sValue;

}

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;

}

public static boolean exists(List<Node> nodes, Node node) {//判断节点是否存在某一list中

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) {//判断节点是否存在某一list中

for (Node n : nodes) {

if ((n.x == x) && (n.y == y)) {

return true;

}

}

return false;

}

@Override

public void keyTyped(KeyEvent e) {

}

@Override

public void keyPressed(KeyEvent e) {//响应键盘

int keyCode = e.getKeyCode();

int x=movePerson.x;

int y=movePerson.y;

switch (keyCode){

case KeyEvent.VK_SPACE:

if (drawpath) {

drawpath = false;

} else {

drawpath = true;

}

repaint();

break;

case KeyEvent.VK_LEFT:

x--;

break;

case KeyEvent.VK_RIGHT:

x++;

break;

case KeyEvent.VK_UP:

y--;

break;

case KeyEvent.VK_DOWN:

y++;

break;

}

if(!isOutOfBorder(x,y)&&mMap[x][y]==1){

xpath.add(movePerson.x);

ypath.add(movePerson.y);

movePerson.x=x;

movePerson.y=y;

}

repaint();

checkWin();

}

@Override

public void keyReleased(KeyEvent e) {

}

public static void main(String[] args) {

JPanel p = new Maze();

JFrame frame = new JFrame("迷宫(按空格显示最优路径)");

frame.getContentPane().add(p);//添加画布

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//使用 System exit 方法退出应用程序。

frame.setSize(480, 500);//设置窗口大小

frame.setLocation(550, 150);

frame.setVisible(true);

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值