package 拼图小游戏;
import javax.swing.*;
import java.awt.*;
public class Cell extends JButton{
private int bw ;
private int bh ;
private int place;
public Cell(Icon icon, int place, int imagewidth, int imagehight)
{
this.bw=imagewidth;
this.bh=imagehight;
this.setSize(bw,bh);//按钮大小
this.setIcon(icon);//图标
this.place = place;//位置
}
public void move(Direction dir)
{
Rectangle rec = this.getBounds();
switch (dir)
{
case UP:
this.setLocation(rec.x,rec.y-bh);
break;
case DOWN:
this.setLocation(rec.x,rec.y+bh);
break;
case LEFT:
this.setLocation(rec.x-bw,rec.y);
break;
case RIGHT:
this.setLocation(rec.x+bw,rec.y);
break;
}
}
public int getX()
{
return this.getBounds().x;
}
public int getY()
{
return this.getBounds().y;
}
public int getPlace()
{
return place;
}
}
2.设计Direction类
package 拼图小游戏;
public enum Direction
{
UP,DOWN,LEFT,RIGHT
}
3.设计GamePanel类
在此类中的outoforder( )函数需要一些数学知识,保证在打乱图片后能够还原。
1、逆序的定义:
逆序是一个与排列相关的概念。
由自然数1,2…,n组成的不重复的每一种有确定次序的排列,称为一个n级排列(简称为排列);或者一般的,n个互不同元素排成一列称为“一个n级排列”。例如,1234和4312都是4级排列,而24315是一个5级排列。
在一个n级排列中,如果一对数的前后位置与大小顺序相反,即前面的数大 于后面的数,那么它们就称为一个“逆序”。
一个排列中逆序的总数就称为这个排列的逆序数。
逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。
如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。
(图形块看做矩阵每一个的元素)图形A与图形B等价<<==>>图形A的排列的逆序数加上0元素行号和列号的奇偶性等于图形B的排列的逆序数加上0元素行号和列号的奇偶性。(同为奇数或者同为偶数都可以还原图片)(0号元素就是空白格)
package 拼图小游戏;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
public class GamePanel extends JPanel implements MouseListener {
private int row=3 ;
private int col=3;
private Cell[] cells = new Cell[row * col];
private Cell cellblank = null;
int Imagew;
int Imageh;
public GamePanel() {
super();
setLayout(null);
init();
}
public void init() {
int num;
int w = 0;
int h = 0;
BufferedImage src = null;
BufferedImage splitpic = null;
ImageIcon icon = null;
try {
src = ImageIO.read(new File("D:\\jdk1.8.0_131\\bin\\girl.jpg"));
//图片路径
Imagew = src.getWidth();
Imageh = src.getHeight();
w = Imagew / col;
h = Imageh / row;
//分割后每一小块的长和宽
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
num = i * col + j;
if (num < row * col - 1) {
splitpic = src.getSubimage(w * j, h * i, w, h);
//getSubimage(1,2,3,4),1,2号确定开始分割的坐标.3,4确定分割图片的宽度和高度
icon = new ImageIcon(splitpic);//图像转化为图标
} else {
icon = new ImageIcon("D:\\jdk1.8.0_131\\bin\\blank.png");
}
cells[num] = new Cell(icon, num, w, h);//添加图标到每一个button上面
cells[num].setLocation(w * j, h * i);
}
}
//初始化空白格
cellblank = cells[row * col - 1];
for (int i = 0; i < cells.length; i++) {
this.add(cells[i]);//将每一个按钮添加到当前面板上
if (i != cells.length - 1) {
cells[i].addMouseListener(this);//空白格不添加监听
}
}
}
//打乱图片的顺序
public void outoforder() {
//定义两个数组存储产生的随机数,也就是任意两个将要交换的图片的编号
int index1[] = new int[row * col];
int index2[] = new int[row * col];
while (true)//利用死循环得到两组满足还原图片的交换序列,存储在index1[]和index2[]中
{
Random random = new Random();
int a[] = new int[col*row];
//将图片映射到数组a[]中,图片的随机交换,也就是数组的随机交换,(便于算出逆序数)
int num1 = 0, num2 = 0;
num1 = (row * col - 1) + (cells[row * col - 1].getX() / (Imagew / col) + cells[row * col - 1].getY() / (Imageh / row));
//图片没打乱之前算出奇偶性num1
System.out.println(num1);
for (int i = 0; i < cells.length; i++) {
a[i] = i;
}
for (int i = 0; i < cells.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
for (int i = 0; i < row * col; i++) {
index1[i] = random.nextInt(cells.length);
index2[i] = random.nextInt(cells.length);
int temp;
temp = a[index1[i]];
a[index1[i]] = a[index2[i]];
a[index2[i]] = temp;
}//数组进行打乱
for (int i = 0; i < row * col; i++) {
System.out.print("index1:" + index1[i] + " ");
}
System.out.println();
for (int i = 0; i < row * col; i++) {
System.out.print("index2:" + index2[i] + " ");
}
for (int i = 0; i < cells.length; i++) {
if (a[i] == row * col - 1) {
a[i] = -1;
num2 = i % col + i / col;
break;
}//找到打乱后的空白格的行列,相加
}
System.out.println();
for (int i = 0; i < cells.length; i++) {
System.out.print(a[i] + " ");
}
for (int i = 0; i < cells.length; i++) {
for (int j = i + 1; j < cells.length; j++) {
if (a[i] > a[j]) num2++;//算出打乱后的逆序数
}
}
System.out.println();
System.out.println(num2);
if ((num1 + num2) % 2 == 0) {
break;
//判断是否同为奇or偶
}
}
//同为奇or偶后,将图片位置进行交换,利用上述的两个数组即可打乱且能还原,(这里cell[]之间也要交换)
for (int i = 0; i < row*col; i++) {
int x = cells[index1[i]].getX();
int y = cells[index1[i]].getY();
int x1 = cells[index2[i]].getX();
int y1 = cells[index2[i]].getY();
cells[index1[i]].setLocation(x1, y1);
cells[index2[i]].setLocation(x, y);
Cell celltemp;
celltemp = cells[index1[i]];
cells[index1[i]] = cells[index2[i]];
cells[index2[i]] = celltemp;
}
}
//判断拼图成功
public boolean iswin() {
for (int i = 0; i < cells.length; i++) {
int x = cells[i].getX();
int y = cells[i].getY();
if ((y / (Imageh / row) * col + x / (Imagew / col)) != cells[i].getPlace())
return false;
}
return true;
}
public void mouseClicked(MouseEvent e) {
Cell cell = (Cell) e.getSource();
int x = cellblank.getX();
int y = cellblank.getY();
if ((x - cell.getX() == Imagew / col) && y == cell.getY()) {
cell.move(Direction.RIGHT);
cellblank.move(Direction.LEFT);
} else if ((x - cell.getX() == -Imagew / col) && y == cell.getY()) {
cell.move(Direction.LEFT);
cellblank.move(Direction.RIGHT);
} else if (cell.getX() == x && (cell.getY() - y == Imageh / row)) {
cell.move(Direction.UP);
cellblank.move(Direction.DOWN);
} else if (cell.getX() == x && (cell.getY() - y == -Imageh / row)) {
cell.move(Direction.DOWN);
cellblank.move(Direction.UP);
}
if (iswin()) {
int i = JOptionPane.showConfirmDialog(this, "success,again?", "拼图成功", JOptionPane.YES_NO_OPTION);
if (i == JOptionPane.YES_OPTION) {
outoforder();
}
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
4.设计MainJFrame类
package 拼图小游戏;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainJFrame extends JFrame{
public MainJFrame()
{
super();
getContentPane().setLayout(new BorderLayout());
setTitle("拼图游戏");
setBounds(300,300,320,400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
JPanel panel = new JPanel();
getContentPane().add(panel,BorderLayout.NORTH);
GamePanel gamepanel = new GamePanel();
getContentPane().add(gamepanel, BorderLayout.CENTER);
JButton button =new JButton();
JButton button1 = new JButton();
panel.add(button);
panel.add(button1);
button.setText("开始");
button1.setText("结束");
button.addActionListener(new ActionListener() {
public void actionPerformed( ActionEvent e) {
gamepanel.outoforder();
}
});
button1.addActionListener(new ActionListener() {
public void actionPerformed( ActionEvent e) {
setVisible(false);
MainJFrame m1 = new MainJFrame();
m1.setVisible(true);
}
});
}
public static void main(String[] args) {
new MainJFrame();
}
}
结果截图:
参考博客:
https://jiankunking.blog.csdn.net/article/details/18081823
https://blog.csdn.net/angry_youth/article/details/71404651