java大作业之拼图游戏

这个拼图游戏是帮同学做的,还是挺不错的,实现功能包括:自动选取图片,自动任意切割图片,且保证生成的一定有解,还有倒计时功能。

还写了那个迪杰斯特拉演示的,过两天再发上来,毕竟要考试了(预习了...)

先说下如何保证有解,两种方法: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);
			}
	}
	
	
}

Game类

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

alert4类

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

java大作业之拼图游戏_第1张图片



java大作业之拼图游戏_第2张图片

你可能感兴趣的:(Java)