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);
}
}
}
以上所述就是本文的全部内容了,希望大家能够喜欢。