这个拼图游戏是帮同学做的,还是挺不错的,实现功能包括:自动选取图片,自动任意切割图片,且保证生成的一定有解,还有倒计时功能。
还写了那个迪杰斯特拉演示的,过两天再发上来,毕竟要考试了(预习了...)
先说下如何保证有解,两种方法:1,先切割然后自己后台让空格自己随机移动。
2,生成全排列,然后判断是否有解:
一个N*M数码是否有解存在以下结论: 1. 如果M为奇数,那么上下移动,左右移动都不会改变序列的逆序值的奇偶性,所以如果begin个end两个状态的逆序值奇偶性一样就有解! 2. 如果M为偶数,左右移动不会改变序列的逆序值的奇偶性,上下移动一次改变奇偶性一次,所以如果begin的空格的行数i与end的空格的行数j的绝对值之差与begin和end的逆序值的绝对值之差的奇偶性一样则有解。 3.其他情况无解!这个其实做poj那道8数码问题应该会有人提到,所以我一开始想到的就是第二种思路,第一种是后来听同学做的,感觉更加方便。
自动选取图片比较简单,套一个JFileChooser就可以,进度条用JProgressBar 难点在于这边这个进度条的线程要和游戏的有关联,我是通过将它的value设为静态成员变量实现的。
自动切割图片是谷歌到一串代码(貌似第二个就是,只不过它那个是存成相片,我这个直接保存为Imagecon即可,稍微修改了下.
puzzle类
public class puzzle extends JFrame implements ActionListener{
Game g;
private JButton jb,jb2,jb3;//依次为开始游戏,显示正确图片
private JTextField jt,jt2;//读入切割的行数和列数
JProgressBar progressbar;//进度条
Progress p;
String file;
public puzzle(){
setTitle("我的拼图");//应用标题
setLayout(null);
setBounds(0,0,900,700);//拼图程序的范围
g= new Game();//如果以后选择图片就从主界面选择好url把url传过去(game有多个构造函数)
g.setBounds(0,0,600,600);
Container container=getContentPane();
jb = new JButton("开始游戏");
jb.setBounds(650,50,200,100);
jb.addActionListener(this);
jb2 = new JButton("显示正确图片");
jb2.setBounds(650,175,200,100);
jb2.addActionListener(this);
jb3=new JButton("选择图片");
jb3.setBounds(650,300,200,100);
jb3.addActionListener(this);
JLabel jl= new JLabel("横向切割数量");
jl.setBounds(650,400,200,50);
container.add(jl);
jt=new JTextField("");
jt.setBounds(650,450,200,50);
JLabel jl2=new JLabel("纵向切割数量");
jl2.setBounds(650,500,200,50);
container.add(jl2);
jt2=new JTextField("");
jt2.setBounds(650,550,200,50);
progressbar =new JProgressBar();
progressbar.setBounds(0,600,800,75);
progressbar.setMinimum(0);
progressbar.setMaximum(100);
progressbar.setValue(0);
progressbar.setBackground(Color.blue);
progressbar.setBorderPainted(true);
container.add(progressbar);
container.add(jt);
container.add(jt2);
container.add(jb);
container.add(jb2);
container.add(jb3);
container.add(g);
container.setBackground(Color.white);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e){
int n,m;
if (e.getSource()==jb){//如果是开始游戏(获得n行,m列)
String s1=jt.getText();
String s2=jt2.getText();
if (s1.matches("\\d+")&&s2.matches("\\d+"))//如果是整数
{
n=Integer.parseInt(s1);
m=Integer.parseInt(s2);
//System.out.println(s1+""+s2);
//new picturecut(n,m);
if(file==null)
new alert4();
else
{
g.start(n,m,file);//传入n行,m列
if (p==null)//只开启一次
{
p=new Progress(progressbar);
p.start();
}
else //如果之前线程已开启
{
if ((Progress.value>=100)||(Progress.value<0))//如果之前那个线程跑完了
{
progressbar.setValue(0);
Progress.value=0;
}
else
//System.out.println("新的p");//关闭之前的线程,开启新的新的线程的方法,不要开启新的线程,直接用之前的那个,只不过修改里面的value值。
{
progressbar.setValue(0);
Progress.value=0;
}
}
}
}
else
new alert3();
}
if (e.getSource()==jb2){//如果是显示图片
g.Display(file);
}
if (e.getSource()==jb3){
JFileChooser fileChooser;
{
fileChooser =new JFileChooser();
FileFilter filter =new FileNameExtensionFilter("图像文件(只能是PNG或JPG)", "JPG","PNG");
fileChooser.setFileFilter(filter);
}
int i=fileChooser.showOpenDialog(getContentPane());
if (i==JFileChooser.APPROVE_OPTION){
File SelectedFile=fileChooser.getSelectedFile();
file=SelectedFile.getAbsolutePath();
System.out.println(file);
g.redraw(file);
progressbar.setValue(0);
Progress.value=-10000;
}
}
}
public static void main(String []args){
new firstapplet();
new puzzle();
}
}
class Progress extends Thread{
static int value=0;
private JProgressBar progressBar;
public Progress(JProgressBar progressBar)
{
this.progressBar=progressBar;
}
public void run()
{
while(value<=100)
{
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
value++;
if (value==100)
{
new alert2();
}
progressBar.setIndeterminate(false);
progressBar.setValue(value);
}
}
}
package puzzle;
import java.awt.Button;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Game extends JPanel implements MouseListener{//创建开始就放张图片,并且打乱,点击开始游戏计时并展示图片,当跑到最终结果时退出线程
private ImageIcon imagecon;
private ImageIcon []pi;
Thread runner;
boolean ok=false;
int time;//判断是第几次调用repaint函数
int []a;//数组里存储着第i个位置放着第几张切割的图片如果是9则为空着的图片.
int currentx;//当前为空的横坐标
int currenty;//当前为空的纵坐标
int number;//当前是第几个位置为空
int n;//n行
int m;//m列
public Game(){
imagecon=new ImageIcon("./picture/bg2.png");//记录完整图片
time=1;
repaint();
}
public void init(int n,int m){//初始化图片位置信息(1~9个位置存储9张图片中的12张),要保证逆序对为偶数(注意计算机n行m列与人是颠倒的)
int flag,c;
boolean f=true;
pi=new ImageIcon[n*m+1];
while(f)//若m为奇数,则逆序对为偶数可行,如果为偶数,则空格行数的差值与逆序对差值奇偶性一样
{
System.out.println("n为"+n+"m为"+m);
for (int i=1;i<=n*m;i++)
{
a[i]=(int)(1+Math.random()*(n*m-1+1));//随机一个1到n*m的数
flag=1;
for (int j=1;ja[i])
sum++;
}
}
System.out.println(sum);
if ((sum%2==0)&&(m%2==1))//如果是奇数有解
f=false;
else
if ((m%2==0)&&(n-(number-1)/m-1)%2==sum%2)//如果是偶数
f=false;
for (c=1;c<=n;c++)//不能一样
if (a[c]!=c)
break;
if (c==n+1) f=true;
}
for (int i=1;i<=n*m;i++)
System.out.println(a[i]);
}
@Override
public void paint(Graphics g){
if (time==1)
{
Image r=imagecon.getImage();
g.drawImage(r,0,0,600,600,this);//画出原来的完整图案
}
else if (!isfinish()){
g.clearRect(0,0,600,600);
for (int i=1;i<=n*m;i++)
{
if (a[i]!=n*m)
{
int temp=a[i];//第i个位置是第原来的第a[i]块图片
Image r=pi[temp].getImage();
g.drawImage(r,(i-1)%m*(600/m),(i-1)/m*(600/n),600/m,600/n,this);
}
else
{
currentx=(i-1)%m*(600/m);
currenty=(i-1)/m*(600/n);//空格的横纵左上角坐标
g.clearRect((i-1)%m*(600/m),(i-1)/m*(600/n),600/m,600/n);//设置第9为空格
}
}
}
else{
g.clearRect(0,0,600,600);
for (int i=1;i<=n*m;i++)//全部输出
{
Image r=pi[i].getImage();
g.drawImage(r,(i-1)%m*(600/m),(i-1)/m*(600/n),600/m,600/n,this);
}
Progress.value=-10000;//游戏结束让进度条设为负值
new alert();
}
}
public void start(int n,int m,String file)//传入m行n列,开始切图
{
this.n=n;
this.m=m;
a=new int[n*m+1];//n行m列
init(n,m);
String srcImageFile=file;
int cols,rows;
cols=m;
rows=n;
Progress.value=0;
if (time==1)
time=2;
try{
// 读取源图像
BufferedImage bi = ImageIO.read(new File(srcImageFile));
// 源图宽度
int srcWidth = bi.getWidth();
// 源图高度
int srcHeight = bi.getHeight();
if (cols >= 1 && rows >=1){
Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
// 切片横向数量
// 切片纵向数量
// 计算切片的横向和纵向数量
double destWidth = srcWidth / cols;
double destHeight = srcHeight /rows;
Image img;
ImageFilter cropFilter;
// 循环建立切片
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
// 四个参数分别为图像起点坐标和宽高
cropFilter = new CropImageFilter((int)(j * destWidth), (int)(i * destHeight),
(int)((j+1)* destWidth), (int)((i+1) * destHeight));
img = Toolkit.getDefaultToolkit().createImage(
new FilteredImageSource(image.getSource(), cropFilter));
BufferedImage tag = new BufferedImage((int)destWidth, (int)destHeight,
BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(img, 0, 0, null); // 绘制缩小后的图
g.dispose();
int c=j+1+i*cols;
pi[c]=new ImageIcon(tag);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
this.addMouseListener(this);
repaint();
}
public boolean isfinish(){//说明已经完成了
for (int i=1;i<=n*m;i++)
{
if (a[i]!=i)
return false;
}
return true;
}
@Override
public void mousePressed(MouseEvent e){
int tempx,tempy;
System.out.println("鼠标触摸");
tempx=e.getX();//当前所在位置
tempy=e.getY();//
System.out.println(tempx);
System.out.println(tempy);
System.out.println("原来的长度为:"+currentx+"原来的高度:"+currenty);
if ((tempx-currentx>=0)&&(tempx-currentx<=600/m)&&(currenty-tempy<=600/n)&&(currenty-tempy>=0)){//如果点击按钮在当前的上方
int temp=a[number];//上下交换自己的图片
a[number]=a[number-m];
a[number-m]=temp;
number=number-m;//更新当前所在的位置
currentx=tempx/(600/m)*(600/m);//第几行
currenty=tempy/(600/n)*(600/n);//第几列
System.out.println("向上边"+currentx+" "+currenty);
}
else if ((currentx-tempx>=0)&&(currentx-tempx<=600/m)&&(tempy-currenty>=0)&&(tempy-currenty<=600/n)){//如果点击按钮在当前的左边
int temp=a[number];
a[number]=a[number-1];
a[number-1]=temp;
number=number-1;
currentx=tempx/(600/m)*(600/m);
currenty=tempy/(600/n)*(600/n);
System.out.println("向左边"+currentx+" "+currenty);
}
else if ((tempx-currentx<=2*(600/m))&&(tempx-currentx>=600/m)&&(tempy-currenty>=0)&&(tempy-currenty<=600/n)){//如果点击按钮在当前的右边
int temp=a[number];
a[number]=a[number+1];
a[number+1]=temp;
number=number+1;
currentx=tempx/(600/m)*(600/m);
currenty=tempy/(600/n)*(600/n);
System.out.println("向右边"+currentx+" "+currenty);
}
else if ((tempy-currenty>=600/n)&&(tempy-currenty<=2*(600/n))&&(tempx-currentx>=0)&&(tempx-currentx<=600/m)){//如果点击按钮在当前的下边
int temp=a[number];
a[number]=a[number+m];
a[number+m]=temp;
number=number+m;
currentx=tempx/(600/m)*(600/m);
currenty=tempy/(600/n)*(600/n);
System.out.println("向下边"+currentx+" "+currenty);
}
repaint();//至于要在每一次最后重新绘制即可
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void Display(String file){
String s=file;
new display(s);
}
public void redraw(String s) {
imagecon=new ImageIcon(s);//记录完整图片
time=1;
repaint();
}
public class display extends JDialog{//展示图片
Congra jp;
public display(String s){
setTitle("展示图片");
setLayout(null);
setBounds(400,300,300,300);
Container container=getContentPane();
JLabel jl= new JLabel("原图片");
jl.setBounds(50,50,300,200);
container.add(jl);
container.setBackground(Color.white);
jp=new Congra(s);
jp.setBounds(0,0,250,250);
container.add(jp);
setVisible(true);
}
}
public class alert extends JDialog {
ImageIcon li;
public alert(){
win g=new win();
g.setBounds(0,0,400,400);
setTitle("you win!");
setLayout(null);
setBounds(400,300,450,400);
Container container=getContentPane();
container.add(g);
container.setBackground(Color.white);
setVisible(true);
}
}
public class win extends JPanel{
ImageIcon li;
public win(){
li=new ImageIcon("./picture/you win.png");
repaint();
}
public void paint(Graphics g)
{
Image r=li.getImage();
g.drawImage(r,0,0,400,400,this);
}
}
}
alert2类
public class alert2 extends JDialog {
public alert2(){
setTitle("游戏结束!");
setLayout(null);
setBounds(400,300,450,400);
Container container=getContentPane();
container.setBackground(Color.white);
JLabel jl= new JLabel("时间到,游戏结束!");
jl.setBounds(50,50,200,100);
container.add(jl);
setVisible(true);
}
}
alert3类
public class alert3 extends JDialog {
public alert3(){
setTitle("注意");
setLayout(null);
setBounds(400,300,300,200);
Container container=getContentPane();
container.setBackground(Color.white);
JLabel jl= new JLabel("请输入正确的横向纵向切割数量!");
jl.setBounds(50,50,200,100);
container.add(jl);
setVisible(true);
}
}
public class alert4 extends JDialog {
public alert4(){
setTitle("注意!");
setLayout(null);
setBounds(400,300,300,200);
Container container=getContentPane();
container.setBackground(Color.white);
JLabel jl= new JLabel("请先选择图片");
jl.setBounds(50,50,200,100);
container.add(jl);
setVisible(true);
}
}