标签:
这个拼图游戏是帮同学做的,还是挺不错的,实现功能包括:自动选取图片,自动任意切割图片,且保证生成的一定有解,还有倒计时功能。
还写了那个迪杰斯特拉演示的,过两天再发上来,毕竟要考试了(预习了...)
先说下如何保证有解,两种方法: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;j<i;j++) if (a[i]==a[j])//判重 flag=0; if (flag==0)//如果不符合 i--; } int sum=0;//计算逆序对 number=0; for (int i=1;i<=n*m;i++) { if (a[i]==n*m) { number=i;//记录下是第几个为空 continue; } for (int j=1;j<i;j++) { if (j==number) continue; if (a[j]>a[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); } }
标签:
原文地址:http://blog.csdn.net/fengsigaoju/article/details/51734863