Java制作智能拼图游戏原理及代码
今天突发奇想,想做一个智能拼图游戏来给哄女友。
需要实现这些功能
第一图片自定义
第二宫格自定义,当然我一开始就想的是3*34*45*5,没有使用3*5这样的宫格。
第三要实现自动拼图的功能,相信大家知道女人耍游戏都不是很厉害,所以这个自动拼图功能得有。
其他什么暂停、排行就不写了!
现在重点问题出来了
要实现自动拼图功能似乎要求有点高哦!计算机有可不能像人一样只能:
先追究下本质
拼图游戏其实就是排列问题:
排列有这么一个定义:在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。
再来一个定义:交换一个排列中的两个数,则排列的奇偶性发生改变。
以上定义都摘自《高等代数》。
拼图排列必须是偶排列。这个在我参考文献中可以找到。
所以我的只能拼图是这样实现的!
后续在写
参考:http://en.wikipedia.org/wiki/Fifteen_puzzle
自动拼图:
首先自动拼图应该有一定的规则,根据我拼图的经验,要完成拼图,不同区域使用的拼图规则是不同的,所以:
我的宫格图分为了4个区域(假如宫格图是n*n个格子)
第一个区域:x坐标范围0到n-2,y坐标范围0到n-3
第二个区域:x坐标n-1,y坐标范围0到n-3
第三个区域:x坐标范围0到n-3,y坐标范围n-2和n-1
第四个区域:x坐标范围n-2到n-1,y坐标范围n-2和n-1;即最后四格
每个区域按照各自区域的规则即可完成
Puzzle.java
importjava.io.FileNotFoundException; importjava.io.PrintStream; importjava.io.UnsupportedEncodingException; importjava.util.Random; publicclassPuzzle{ privatelongstep=0; privateintn=6;//宫格基数 privateint[][]puzzle; privateintresetBlock=0;// //空白块位置 privateintwhiteBlockX; privateintwhiteBlockY; //当前要准备移动的块的坐标即复位块 privateintresetBlockX; privateintresetBlockY; privatebooleanisPrint=false; publicPuzzle(){ init(); } publicPuzzle(intn){ this.n=n; init(); } privatevoidinit(){ puzzle=newint[n][n]; for(inty=0;y<n;y++){ for(intx=0;x<n;x++){ puzzle[y][x]=x+y*n; } } whiteBlockX=n-1; whiteBlockY=n-1; inttimes=100;//打乱次数,必须是偶数 Randomrandom=newRandom(); while(times>0){ intx0=random.nextInt(n); inty0=random.nextInt(n); intx1=random.nextInt(n); inty1=random.nextInt(n); if(x0!=x1&&y0!=y1){//保证是偶排序 if((x0==n-1&&y0==n-1)||(x1==n-1&&y1==n-1)){//最后一个不调换 continue; } times--; intt=puzzle[x0][y0]; puzzle[x0][y0]=puzzle[x1][y1]; puzzle[x1][y1]=t; } } //int[][]p={{22,9,1,5,0,25},{ //33,23,20,26,18,21},{ //6,16,17,10,34,31},{ //19,28,32,7,3,2},{ //11,4,12,14,27,24},{ //15,29,30,8,13,35}}; //puzzle=p; } publicvoidsort(){ for(inty=0;y<n;y++){ for(intx=0;x<n;x++){ if(x==n-1&&y==n-1){//最后一个为空白, }else{ reset(x,y); } } } } //把块复位移动目标位置 privatevoidreset(inttargetX,inttargetY){ //找到复位块当前的位置 initResetBlock(targetX,targetY); /* *复位顺序是从左到右,从上到下 *移动方式先上移动,再左移动 *当前复位块,它要复位的位置可分为四种情况 *1、不在最右边一行也不是最下面两行 *2、最右边一行x=n-1,但不是下面两行; *3、最下面两行y=n-2,但不是最右边一行; *4、即使最右边的一行也是最下面两行 */ if(targetX<n-1&&targetY<n-2){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } resetBlockToTarget(targetX,targetY); }elseif(targetX==n-1&&targetY<n-2){//第二种情况 if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } reset2(targetX,targetY); }elseif(targetX<n-2&&targetY==n-2){ //isPrint=true; reset3(targetX); return; }else{ initResetBlock(n-2,n-2); resetBlockToTarget(n-2,n-2); if(whiteBlockX<n-1){ whiteBlockRight(); } if(whiteBlockY<n-1){ whiteBlockDown(); } if(whiteBlockX==n-1&&whiteBlockY==n-1){ return; } } reset(targetX,targetY);//递归 } privatevoidinitResetBlock(inttargetX,inttargetY){ resetBlock=targetX+targetY*n; for(inty=0;y<n;y++){ for(intx=0;x<n;x++){ if(puzzle[y][x]==resetBlock){//x,y就是复位块的位置 resetBlockX=x; resetBlockY=y; break; } } } } privatevoidreset3(inttargetX){ //if(targetX>=2){ //} initResetBlock(targetX,n-1); resetBlockToTarget(targetX,n-2); initResetBlock(targetX,n-2); resetBlockToTarget(targetX+1,n-2); l: while(!(whiteBlockX==targetX&&whiteBlockY==n-1)){ if(whiteBlockY<n-1){ whiteBlockDown(); continuel; } if(whiteBlockX>targetX){ whiteBlockLeft(); continuel; } break; } whiteBlockUp(); swapWhiteBlockAndCurrentBlock(); if(puzzle[n-2][targetX]!=resetBlock||puzzle[n-1][targetX]!=(resetBlock+n)){//没有复位成功 //isPrint=true; swapWhiteBlockAndCurrentBlock(); reset3_0(); reset3(targetX); } } privatevoidreset3_0(){ if(resetBlockX<n-1){ whiteBlockDown(); whiteBlockRight(); whiteBlockRight(); whiteBlockUp(); swapWhiteBlockAndCurrentBlock(); reset3_0(); return; } return; } privatevoidreset2_3(){ if(whiteBlockX==resetBlockX&&whiteBlockY==resetBlockY+1){ return;//满足条件,退出递归 } //白块可能在复位块的:左方、左下、下方 if(whiteBlockY==resetBlockY){//左方 whiteBlockDown(); }elseif(whiteBlockX<resetBlockX){//左下 whiteBlockRight(); }else{ whiteBlockUp(); } reset2_3();//递归 } privatevoidreset2_2(inttargetX,inttargetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//2、把复位块移到目标位置正下方 return;//退出递归 } //复位块可能位置,目标位置左方、正下方、左下方 if(resetBlockX==targetX){//正下方上移 resetBlockUp(targetX,targetY); }else{//左方或左下方;先右移再上移 resetBlockRight(targetX,targetY); } reset2_2(targetX,targetY);//递归 } privatevoidreset2(inttargetX,inttargetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } /*1、如果白块正好占了目标位置:如果复位块正好在下方,交换及完成复位,如果下方不是复位块,把白块移开目标位置 *2、把复位块移到目标位置正下方 *3、把白块移动复位块下方 *4、按照规定的步骤复位 */ //第一步 if(whiteBlockX==targetX&&whiteBlockY==targetY){ if(whiteBlockX==resetBlockX&&whiteBlockY==resetBlockY+1){//复位块在下方 swapWhiteBlockAndCurrentBlock(); return; }else{ whiteBlockDown(); } } //第二步把复位块移到目标位置正下方 reset2_2(targetX,targetY+1); //第三步把白块移动复位块下方 reset2_3(); //第四步按照规定的步骤复位 swapWhiteBlockAndCurrentBlock(); whiteBlockLeft(); whiteBlockUp(); whiteBlockRight(); whiteBlockDown(); whiteBlockLeft(); whiteBlockUp(); whiteBlockRight(); whiteBlockDown(); swapWhiteBlockAndCurrentBlock(); whiteBlockLeft(); whiteBlockUp(); whiteBlockUp(); whiteBlockRight(); swapWhiteBlockAndCurrentBlock(); } privatevoidresetBlockToTarget(inttargetX,inttargetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } if(resetBlockY==targetY){//正左 resetBlockLeft(targetX,targetY); }else{//左下,下,右下 if(resetBlockX>=targetX){//右下||下;上移 if(resetBlockX==n-1){//复位块在最右边,先左移;方便上移时统一的采用白块逆时针方式 resetBlockLeft(targetX,targetY); }else{ resetBlockUp(targetX,targetY); } }else{//左下;右移 resetBlockRight(targetX,targetY); } } resetBlockToTarget(targetX,targetY);//递归 } privatevoidresetBlockRight(inttargetX,inttargetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } if(resetBlockX==n-1){//复位块在最右边了,无法右移,直接退出 return; } //System.out.println("resetBlockRight"); if(whiteBlockY<resetBlockY){//上方 if(whiteBlockY<resetBlockY-1){//上方多行 whiteBlockDown(); }else{//上方一行 if(whiteBlockX<resetBlockX+1){//左上和正上 whiteBlockRight(); }else{//右上 whiteBlockDown(); } } }elseif(whiteBlockY==resetBlockY){//同一行 if(whiteBlockX<resetBlockX){//左方 if(whiteBlockY==n-1){//到底了,只能往上 whiteBlockUp(); }else{ whiteBlockDown(); } }else{//右方 if(whiteBlockX==resetBlockX+1){ swapWhiteBlockAndCurrentBlock(); return;//退出递归 }else{ whiteBlockLeft(); } } }else{//下方 if(whiteBlockX<=resetBlockX){//左下、下 whiteBlockRight(); }else{//右下 whiteBlockUp(); } } resetBlockRight(targetX,targetY);//递归 } privatevoidresetBlockLeft(inttargetX,inttargetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } if(resetBlockX==0){//在左边边界复位块无法左移,直接退出递归 return; } //System.out.println("resetBlockLeft"); if(whiteBlockY<resetBlockY){//上方 if(whiteBlockY<resetBlockY-1){//上方多行 whiteBlockDown(); }else{//上方一行 if(whiteBlockX==resetBlockX){//上方 if(whiteBlockX==n-1){//最右边,白块无法右移,只能左移 whiteBlockLeft(); }else{ if(resetBlockY==n-1){//复位块在最低端,白块不能顺时针移动 whiteBlockLeft(); }else{ whiteBlockRight(); } } }elseif(whiteBlockX>resetBlockX){//右上方 if(resetBlockY==n-1){//复位块在最低端,白块不能顺时针移动 whiteBlockLeft(); }else{ whiteBlockDown(); } }else{//左上方 whiteBlockDown(); } } }elseif(whiteBlockY==resetBlockY){//左方、右方 if(whiteBlockX<resetBlockX){//左方 if(whiteBlockX==resetBlockX-1){//左边一格 swapWhiteBlockAndCurrentBlock();//退出递归 return; }else{ whiteBlockRight(); } }else{//右方 if(whiteBlockY==n-1){//到底了,不能下移。只能上移 whiteBlockUp(); }else{ whiteBlockDown(); } } }else{//左下、下方、右下 if(whiteBlockX<resetBlockX){//左下 if(whiteBlockX==resetBlockX-1){ whiteBlockUp(); }else{ whiteBlockRight(); } }else{//下方、右下 whiteBlockLeft(); } } resetBlockLeft(targetX,targetY);//递归 } privatevoidresetBlockUp(inttargetX,inttargetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正确不用移动 return;//退出递归 } if(resetBlockY==0){//复位块到顶了,无法上移 return; } //System.out.println("resetBlockUp"); if(whiteBlockY<resetBlockY){//上方 if(whiteBlockY<resetBlockY-1){//上方多行 whiteBlockDown(); }else{//上方一行 if(whiteBlockX==resetBlockX){//白块和复位块在同一列(竖列)白块和复位块直接交换位置 swapWhiteBlockAndCurrentBlock();//退出递归 return; }else{ if(whiteBlockX<resetBlockX){//白块在复位块的左边;白块右移 whiteBlockRight(); }else{//白块在复位块的右边;白块左移 whiteBlockLeft(); } } } }elseif(whiteBlockY==resetBlockY){//白块和复位块同一行;白块上移 if(whiteBlockX<resetBlockX){//正左 if(whiteBlockX<resetBlockX-1){//正左多格 whiteBlockRight(); }else{//正左一格 if(whiteBlockY==n-1){//到底了 whiteBlockUp(); }else{ if(resetBlockX==n-1){//复位块在最右边,无法逆时针,只有顺指针移动白块 whiteBlockUp(); }else{ whiteBlockDown(); } } } }else{//正右 whiteBlockUp(); } }else{//白块在复位块下方,白块需要饶过复位块上移,白块逆时针绕到白块上面 //三种情况:左下,下,右下 if(whiteBlockX<=resetBlockX){//左下,下;白块右移 if(resetBlockX==n-1){//复位块在最右边,无法逆时针,只有顺指针移动白块 if(whiteBlockX==resetBlockX){//正下方 whiteBlockLeft(); }else{//左下方 whiteBlockUp(); } }else{ whiteBlockRight(); } }else{//右下;白块上移 whiteBlockUp(); } } resetBlockUp(targetX,targetY);//递归 } //白块和复位块交换位置 privatevoidswapWhiteBlockAndCurrentBlock(){ step++; inttempX=whiteBlockX,tempY=whiteBlockY; inttemp=puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX]=puzzle[resetBlockY][resetBlockX]; puzzle[resetBlockY][resetBlockX]=temp; whiteBlockX=resetBlockX; whiteBlockY=resetBlockY; resetBlockX=tempX; resetBlockY=tempY; println("swap"); } privatevoidwhiteBlockDown(){ step++; inttemp=puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX]=puzzle[whiteBlockY+1][whiteBlockX]; puzzle[whiteBlockY+1][whiteBlockX]=temp; whiteBlockY++; println("↓"); } privatevoidwhiteBlockUp(){ step++; inttemp=puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX]=puzzle[whiteBlockY-1][whiteBlockX]; puzzle[whiteBlockY-1][whiteBlockX]=temp; whiteBlockY--; println("↑"); } privatevoidwhiteBlockLeft(){ step++; inttemp=puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX]=puzzle[whiteBlockY][whiteBlockX-1]; puzzle[whiteBlockY][whiteBlockX-1]=temp; whiteBlockX--; println("←"); } privatevoidwhiteBlockRight(){ step++; inttemp=puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX]=puzzle[whiteBlockY][whiteBlockX+1]; puzzle[whiteBlockY][whiteBlockX+1]=temp; whiteBlockX++; println("→"); } @Override publicStringtoString(){ StringBuildersb=newStringBuilder(); sb.append("resetBlock=("+resetBlock+","+resetBlockX+","+resetBlockY+")\n"); if(puzzle!=null){ intlen=String.valueOf(n*2-1).length(); for(inty=0;y<n;y++){ for(intx=0;x<n;x++){ if(x>0){ sb.append(","); } sb.append(_str(String.valueOf(puzzle[y][x]),len)); } sb.append("\n"); } sb.append("---------------------------------------"); }else{ sb.append("puzzleisnull"); } returnsb.toString(); } privateString_str(Stringstr,intlen){ str=str==null?"":str; if(str.length()<len){ return_str(str+"",len); } returnstr; } privatevoidprintln(Stringstr){ if(isPrint){ System.out.println(str); System.out.println(this); } } publicstaticvoidmain(String[]args)throwsFileNotFoundException,UnsupportedEncodingException{ //System.setOut(newPrintStream("e:/puzzle.txt","UTF-8")); Puzzlep=newPuzzle(); System.out.println(p); try{ p.sort(); }catch(Exceptione){ e.printStackTrace(); System.out.println("Exception:"); }finally{ System.out.println(p); } } }
以上所述就是本文的全部内容了,希望大家能够喜欢。