JAVA编写拼图小游戏带自动寻路算法

因为课程的关系,要交作业就写了这个小游戏。
下面先看看架构
在这里插入图片描述

对于程序的难点:

  • 对于拼图是否存在解的处理: (查到大佬结论)N×N的棋盘,N为奇数时,与八数码问题相同。逆序奇偶同性可互达
    N为偶数时,空格每上下移动一次,奇偶性改变。称空格位置所在的行到目标空格所在的行步数为空格的距离(不计左右距离),若两个状态的可相互到达,则有,两个状态的逆序奇偶性相同且空格距离为偶数,或者,逆序奇偶性不同且空格距离为奇数数。否则不能。
    也就是说,当此表达式成立时,两个状态可相互到达:(状态1奇偶性状态2奇偶性)(空格距离%2==0)。
  • 切图:因为一开始不知道可以通过JAVA实现切图(JAVA弱渣)一直捣鼓用PPT,PS各种瞎搞,后来知道后大骂自己一句傻逼。
  • 自动寻路算法:原本设想是速学一波启发式搜索赶在交作业前完成的,结果还是高估了自己的智商,到现在依旧没有掌握该算法的精髓。简单写了广搜实现的复原,不过还是得抓紧时间将启发式搜索补好,广搜处理复杂度过不了3阶以上的拼图。

剩下的就只要基本掌握某一门语言基础语法,随便搞搞应该就可以完成了。
下面上代码:
Puzzle窗体类

package demo;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;

import javax.swing.*;

public class Puzzle extends JFrame {
	
	static HashMap<Integer, Puzzle> hash = new HashMap<Integer, Puzzle>();      //哈希表存储游戏窗口
	static GamePanel gamePanel;                                                 //游戏面板
	static TopPanel topPanel;                                                   //原图展示面板+功能面板
	static int _n;                                                              //n阶拼图
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		init();
	
	}
	public Puzzle(int n, boolean isMove) {
		super();
		this.setTitle("Puzzle");                                                //设置游戏名称
		this.setSize(426,760);                                                  //设置窗体大小
		this.setResizable(false);                                               //设置窗体大小无法修改
		this.setLocationRelativeTo(null);                                       //将游戏窗口设置在中间
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                    //关闭游戏窗口设置
		
		this._n = n;                                                                 
		gamePanel = new GamePanel(this._n, isMove);                             //建立游戏面板传递N阶拼图
		topPanel = new TopPanel(hash);                                          //建立游戏功能面板并传递游戏窗体
		this.add(gamePanel,BorderLayout.CENTER);                                //将面板加入窗体
		this.add(topPanel,BorderLayout.NORTH);
		this.setVisible(true);                                                  //将窗体可视
		
		hash.put(0, this);                                                      
	}
	public static void init() {
		Puzzle Game = new Puzzle(3, true);                                      //创建游戏窗体
	}
		
}

TopPanel面板类

package demo;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.HashMap;

import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class TopPanel extends JPanel{
	final String[] src = {"img\\Original.jpg"};
	public TopPanel(HashMap<Integer, Puzzle> hash) {
		// TODO Auto-generated constructor stub
		super();
		this.setBorder(new TitledBorder(null, "",TitledBorder.DEFAULT_JUSTIFICATION,TitledBorder.DEFAULT_POSITION, null, null));
		ImgPanel panel1 = new ImgPanel(src[0]);
		FuncPanel panel2 = new FuncPanel(hash);
		this.add(panel1);
		this.add(panel2); 
	}

}

ImgPanel面板类

package demo;

import java.awt.Dimension;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
//鍘熷浘闈㈡澘
public class ImgPanel extends JPanel {

	public ImgPanel(String src) {
		// TODO Auto-generated constructor stub
		super();
		this.setPreferredSize(new Dimension(300,300));
		final JLabel img = new JLabel(new ImageIcon(src));
		this.add(img);
	}

}

FuncPanel面板类

package demo;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.util.HashMap;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
//功能面板
public class FuncPanel extends JPanel {
	final String[] names = {"开始游戏", "下一关卡", "重置游戏", "复原拼图"};                 //游戏功能项
	public FuncPanel(HashMap<Integer, Puzzle> hash) {
		// TODO Auto-generated constructor stub
		super();
		this.setPreferredSize(new Dimension(100,300));                             //设置面板大小
		
		final FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER, 0, 36);    //设置流布局
		this.setLayout(flowLayout);
		
		JButton start = new JButton();                                             
		start.setText(this.names[0]);
		this.add(start);
		start.addActionListener(new ActionListener() {                             //重新开始游戏,起点为3阶拼图
			public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
				JFrame newGame = new JFrame();
                newGame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                final FlowLayout Flow = new FlowLayout();
                Flow.setAlignment(FlowLayout.CENTER);
                Flow.setHgap(30);
                newGame.getContentPane().setLayout(Flow);
                newGame.setResizable(false);
                newGame.setSize(200,100);
                
                JLabel text = new JLabel();
                text.setText("NewGame Start!!!");
                text.setSize(100,30);
                newGame.getContentPane().add(text);
                JButton label = new JButton("确定");
                label.setBounds(10, 10, 100, 23);
                newGame.getContentPane().add(label);
                
                label.addActionListener(new ActionListener() {
                	@Override
					public void actionPerformed(ActionEvent e) {
                		newGame.dispatchEvent(new WindowEvent(newGame,WindowEvent.WINDOW_CLOSING) );
                		Puzzle Game = hash.get(0);
        				Game.setVisible(false);
        				Game = new Puzzle(3, true);
                	}
                });
                newGame.setLocationRelativeTo(null);
                newGame.setVisible(true);
				
			}
		});
		
		JButton nextGame = new JButton();
		nextGame.setText(this.names[1]);
		this.add(nextGame);
		nextGame.addActionListener(new ActionListener() {                             //进入下一卡关,当通关5阶拼时将不再进入下一卡关并给予游戏者提醒
			public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
				Puzzle Game = hash.get(0);
				if(Game.gamePanel.chack()) {
					if(Game._n == 5) {
						JFrame tipGame = new JFrame();
						tipGame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		                final FlowLayout Flow = new FlowLayout();
		                Flow.setAlignment(FlowLayout.CENTER);
		                Flow.setHgap(30);
		                tipGame.getContentPane().setLayout(Flow);
		                tipGame.setResizable(false);
		                tipGame.setSize(200,100);
		                
		                JLabel text = new JLabel();
		                text.setText("抱歉,您已经通过所有关卡!!!");
		                text.setSize(100,30);
		                tipGame.getContentPane().add(text);
		                JButton label = new JButton("确定");
		                label.setBounds(10, 10, 100, 23);
		                tipGame.getContentPane().add(label);
		                label.addActionListener(new ActionListener() {
		                	@Override
							public void actionPerformed(ActionEvent e) {
		                		tipGame.dispatchEvent(new WindowEvent(tipGame,WindowEvent.WINDOW_CLOSING) );
		                	}
		                });
		                tipGame.setLocationRelativeTo(null);
		                tipGame.setVisible(true);
					}
					else {
						Game.setVisible(false);
						Game = new Puzzle(Game._n+1, true);
					}
					
				}
				else {
					JFrame rtGame = new JFrame();
					rtGame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	                final FlowLayout Flow = new FlowLayout();
	                Flow.setAlignment(FlowLayout.CENTER);
	                Flow.setHgap(30);
	                rtGame.getContentPane().setLayout(Flow);
	                rtGame.setResizable(false);
	                rtGame.setSize(200,100);
	                
	                JLabel lowerTip = new JLabel();
	                lowerTip.setText("抱歉,您暂未通过本关卡!!!");
	                lowerTip.setSize(100,30);
	                rtGame.getContentPane().add(lowerTip);
	                JButton label = new JButton("确定");
	                label.setBounds(10, 10, 100, 23);
	                rtGame.getContentPane().add(label);
	                label.addActionListener(new ActionListener() {
	                	@Override
						public void actionPerformed(ActionEvent e) {
	                		rtGame.dispatchEvent(new WindowEvent(rtGame,WindowEvent.WINDOW_CLOSING) );
	                	}
	                });
	                rtGame.setLocationRelativeTo(null);
	                rtGame.setVisible(true);
				}
			}
		});
		
		JButton reset = new JButton();
		reset.setText(names[2]);
		this.add(reset);
		reset.addActionListener(new ActionListener() {            //重置游戏
			public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
				Puzzle Game = hash.get(0);
				Game.gamePanel.reSet( Game.gamePanel._n);
			}
		});
		
		JButton repair = new JButton();
		repair.setText(names[3]);
		this.add(repair);
		repair.addActionListener(new ActionListener() {        //复原拼图,自动寻路
			public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
//------------------------------------自动寻路算法-------------------------------------------
				Puzzle Game = hash.get(0);
				if(Game.gamePanel._n==3) {
					
					
					int[][] dir = {{1,0},{0,1},{-1, 0},{0,-1}};
					boolean[] vis = new boolean[362881];
					for(int i = 0; i < 362881; i++)  vis[i] = false;
					int head = 0, tail = 1;
	                AiArr[] array = new AiArr[370000];
	                AiArr[] res = new AiArr[370000];
	                int idx = 0, n = Game.gamePanel._n;
	                for(int i = 0; i < n*n; i++) {
	                	if(Game.gamePanel.rondomArr[i] == n*n-1) {
	                		idx = i;
	                		break;
	                	}
	                }
	                array[0] = new AiArr(Game.gamePanel.rondomArr, idx, -1, -1);
	                vis[array[0].calc()] = true;
	                if(vis[1] == true) {
	                	Game.gamePanel.winGame();
	                }
	                else {
		                while(head!=tail) {
		                	AiArr k = array[head];
		                	int x = (k._idx)/n, y = (k._idx)%n;
		                	for(int i = 0; i < 4; i++) {
		                		int tx = x+dir[i][0], ty = y+dir[i][1];
		                		if(tx < 0 || tx >= n || ty < 0 || ty >= n) continue;
		                		AiArr tmp = k.move(i, head);
		                		if(vis[tmp.calc()]==true) continue;
		                		array[tail] = tmp;
		                		vis[array[tail].calc()] = true;
		                		if(vis[1] == true) {
		                			 break;
		                		}
		                		tail+=1;
		                	}
		                	if(vis[1] == true) break;
		                	head++;
		                }
		                int t = 0;
		                res[t] = array[tail];
		                while(res[t]._node!=-1) {
		                	t+=1;
		                	res[t] = array[res[t-1]._node];
		                }
		                final int gbk = t;
		                new Thread(new Runnable(){
		                    @Override
		                    public void run() {
		                        try {
		                            for(int i = gbk-1; i >=0; i--) {
		                            	Game.gamePanel.moveSet(res[i]._dir, res[i+1]._idx);
		                                Thread.sleep(300);    
		                            }
		                        } catch (InterruptedException e) {
		                            e.printStackTrace();
		                        }
		                    }
		                }).start();
	                }
				}
				else {
					JFrame tipWin = new JFrame();
					tipWin.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	                final FlowLayout Flow = new FlowLayout();
	                Flow.setAlignment(FlowLayout.CENTER);
	                Flow.setHgap(30);
	                tipWin.getContentPane().setLayout(Flow);
	                tipWin.setResizable(false);
	                tipWin.setSize(200,100);
	                
	                JLabel text = new JLabel();
	                text.setText("功能暂未实现!!!");
	                text.setSize(100,30);
	                tipWin.getContentPane().add(text);
	                JButton label = new JButton("确定");
	                label.setBounds(10, 10, 100, 23);
	                tipWin.getContentPane().add(label);
	                
	                label.addActionListener(new ActionListener() {
	                	@Override
						public void actionPerformed(ActionEvent e) {
	                		tipWin.dispatchEvent(new WindowEvent(tipWin,WindowEvent.WINDOW_CLOSING) );
	                	}
	                });
	                tipWin.setLocationRelativeTo(null);
	                tipWin.setVisible(true);
				}
			}
		});
	}
}


寻路算法结构类

package demo;

public class AiArr {
	int[] _arr;
	int _idx;
	int _dir;
	int _node;
	private int[][] __dir = {{1,0},{0,1},{-1, 0},{0,-1}};
	public AiArr() {
		
	}
	public AiArr(int[] arr, int idx, int dir, int node) {
		_arr = arr;
		_idx = idx;
		_dir = dir;
		_node = node;
	}
	public AiArr move(int dir, int node) {
		int x = _idx/3, y = _idx%3;
		int tx = x+__dir[dir][0], ty = y+__dir[dir][1];
		int t = _arr[x*3+y];
		int[] newArr = new int[9];
		for(int i = 0; i < 9; i++) newArr[i] = _arr[i];
		newArr[x*3+y] = newArr[tx*3+ty];
		newArr[tx*3+ty] = t;
		return new AiArr(newArr, tx*3+ty, dir, node);
	}
	public int fac(int n) {
		int x = 1;
		for(int i = 1; i <= n; i++) x*=i;
		return x;
	}
	public int calc() {
		int len = 9, ans = 0;
		for(int i = 0; i < len; i++) {
			int Count = 0;
			for(int j = i+1; j < len; j++) {
				if(_arr[i] > _arr[j]) {
					Count+=1;
				}
			}
			ans+=(Count*fac(len-i-1));
		}
		return ans+1;
	}
}

GamePanel面板类

package demo;

import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class GamePanel extends JPanel{
	final String[] srcs = {"img\\easy\\", "img\\mediun\\", "img\\hard\\"};
	String src;
	JButton[] icons;
	JButton[] TMP;
	final JButton[] buttons;
	int _n;
	int[] rondomArr;
	int[] rondomTmpArr;
	int[][] dir = {{1,0},{0,1},{-1, 0},{0,-1}};
	public GamePanel(int n, boolean vis) {
		// TODO Auto-generated constructor stub
		_n = n;
		this.removeAll();
		final GridLayout gridLayout = new GridLayout(n, n);
		gridLayout.setHgap(0);
		gridLayout.setVgap(0);
		this.setLayout(gridLayout);
		
		src = srcs[n-3];
		
		buttons = new JButton[n*n];
		for(int row = 0; row < n; row++) {
			for(int col = 0; col < n; col++) {
				String s = src+row+col+".jpg";
				buttons[row*n+col] = new JButton(new ImageIcon(s));
			}
		} 
		
		
		icons = new JButton[n*n];
		TMP = new JButton[n*n];
		rondomArr = rondom(n*n);
		rondomTmpArr = new int[n*n];
		for(int i = 0; i < n*n; i++) {
			rondomTmpArr[i] = rondomArr[i];
			icons[i] = buttons[rondomArr[i]];
			icons[i].setName(""+i);
			TMP[i] = new JButton(icons[i].getIcon());
			this.add(icons[i]);
			icons[i].addActionListener(new MoveButtonAction());
		}
	}
	public static int[] rondom(int n) {
		Random rondom = new Random();
		int[] rondomArrT = new int[n];
		boolean[] vis = new boolean[n];
		int Count = -1, its = 1;
		
		while(Count%2!=0 && (((int)Math.sqrt(n)-its)%2 == 1 || n%2==1)) {
			for(int i = 0; i < n; i++) vis[i] = false;
			for(int i = 0; i < n; i++) {
				rondomArrT[i] = rondom.nextInt(n);
				while(vis[rondomArrT[i]] == true) {
					rondomArrT[i] = rondom.nextInt(n);
					if(vis[rondomArrT[i]] == false) {
						break;
					}
				}
				vis[rondomArrT[i]] = true;
			}
			Count = 0;
			for(int i = 0; i < n; i++) {
				if(rondomArrT[i] == n-1) {
					its = i/(int)Math.sqrt(n);
					continue;
				}
				for(int j = 0; j < i; j++) {
					if(rondomArrT[i] < rondomArrT[j] && rondomArrT[j]!=n-1) {
						Count+=1;
					}
				}
			}
		}
		return rondomArrT;
	}
	public void reSet(int n) {
		for(int i = 0; i < n*n; i++) {
			icons[i].setIcon(TMP[i].getIcon());
			rondomArr[i] = rondomTmpArr[i];
		}
	}
	public void moveSet(int xdir, int idx) {                     //移动设置
		JButton tmp = new JButton(icons[idx].getIcon());
		int tx = dir[xdir][0]+idx/_n, ty = dir[xdir][1]+idx%_n;
		icons[idx].setIcon(icons[tx*_n+ty].getIcon());
		icons[tx*_n+ty].setIcon(tmp.getIcon());
		
		int TMP = rondomArr[idx];
		rondomArr[idx] = rondomArr[tx*_n+ty];
		rondomArr[tx*_n+ty] = TMP;
		winGame();
	}
	class MoveButtonAction implements ActionListener {           //移动判断
		public void actionPerformed(ActionEvent e) {
			if(chack()) return;
			JButton moveButton = (JButton)e.getSource();
			int idx = Integer.parseInt(moveButton.getName());
			int x = idx/_n, y = idx%_n;
			String target = src+(_n-1)+(_n-1)+".jpg";
			for(int i = 0; i < 4; i++) {
				int tx = x+dir[i][0], ty = y+dir[i][1];
				if(tx < 0 || tx >= _n || ty < 0 || ty >= _n) continue;
				String original = new String(icons[tx*_n+ty].getIcon()+"");
				if(original.equals(target)) {
					moveSet(i, idx);
					winGame();
					break;
				}
			}
		}
	}
	public boolean chack() {                                      //检测是否通关
		// TODO Auto-generated method stub
		for(int i = 0; i < _n*_n; i++) {
			String s = src+(i/_n)+(i%_n)+".jpg";
			if(s.equals(icons[i].getIcon()+"")==false) {
				return false;
			}
		}
		return true;
	}
	public void winGame() {                                       //通关提示通知窗口
		if(chack()) {
			JFrame newGame = new JFrame();
            newGame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            final FlowLayout Flow = new FlowLayout();
            Flow.setAlignment(FlowLayout.CENTER);
            Flow.setHgap(30);
            newGame.getContentPane().setLayout(Flow);
            newGame.setResizable(false);
            newGame.setSize(200,100);
            
            JLabel text = new JLabel();
            text.setText("恭喜你,通关成功!!!");
            text.setSize(100,30);
            newGame.getContentPane().add(text);
            JButton label = new JButton("确定");
            label.setBounds(10, 10, 100, 23);
            newGame.getContentPane().add(label);
            label.addActionListener(new ActionListener() {
            	@Override
				public void actionPerformed(ActionEvent e) {
            		newGame.dispatchEvent(new WindowEvent(newGame,WindowEvent.WINDOW_CLOSING) );
            		System.out.println();
            	}
            });
            
            newGame.setLocationRelativeTo(null);
            newGame.setVisible(true);	
		}
	}
}


展示部分:
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值