今天突發奇想,想做一個智慧拼圖遊戲給哄女友。
需要實現這些功能第一圖片自訂第二宮格自訂,當然我一開始就想的是3*3 4*4 5*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
import java.io.FileNotFoundException;import java.io.PrintStream;import java.io.UnsupportedEncodingException;import java.util.Random; public class Puzzle { private long step = 0; private int n = 6;/ 宮格基數int[][] puzzle; private int resetBlock = 0;// //空白區塊位置private int whiteBlockX; private int whiteBlockY; //目前要準備移動的區塊的座標即重設區塊private int resetBlockX; private int resetBlockY; private boolean isPrint { init(); } public Puzzle(int n) { this.n = n; init(); } private void init() { puzzle = new int[n][n]; for (int y = 0; y < n; y++) { for (int x = 0; x < n; x++) { puzzle[y][x] = x + y * n; } } whiteBlockX = n-1; whiteBlockY = n-1; int times = 100;// 打亂次數,必須是偶數Random random = new Random(); while (times > 0) { int x0 = random.nextInt(n); int y0 = random.nextInt(n); int x1 = random.nextInt(n); int y1 = random.nextInt(n); if (x0 != x1 && y0!=y1) {// 保證是偶排序if((x0==n-1&&y0==n-1)||(x1==n-1&&y1==n-1)){//最後一個不規則換continue; } times--; int t = 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; } public void sort(){ for (int y = 0; y < n; y++) { for (int x = 0; x < n; x++) { if (x == n - 1 && y == n - 1) {// 最後一個為空白, } else { reset(x, y); } } } } //把區塊重設移動目標位置private void reset(int targetX, int targetY) { / / 找到重設區塊目前的位置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); }else if(targetX==n-1 && targetY < n-2){//第二種情況if(resetBlockX==targetX&&resetBlockY==targetY){//位置正確不用移動return;//退出遞迴} reset2(targetX, targetY); }else if(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);//遞歸} private void initResetBlock(int targetX,int targetY){ resetBlock = targetX + targetY * n; for (int y = 0; y < n; y++) { for (int x = 0 ; x < n; x++) { if (puzzle[y][x] == resetBlock) {// x,y就是複位區塊的位置resetBlockX = x; resetBlockY = y; break; } } } } private void reset3(int targetX){// 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(); continue l; } if(whiteBlockX>targetX){ whiteBlockLeft(); continue l; } break; } whiteBlockUp(); swapWhiteBlockAndCurrentBlock(); if(puzzle[n-2][targetX]!=resetBlock||puzzle[n-1][targetX]!=(resetBlock+n)){//沒有重設成功// isPrint=true; swapWhiteBlockAndCurrentBlock(); reset3_0(); reset3(targetX); } } private void reset3_0(){ if(resetBlockX<n-1){ whiteBlockDown(); whiteBlockRight(); whiteBlockRight(); whiteBlockUp(); ; } private void reset2_3(){ if(whiteBlockX==resetBlockX && whiteBlockY==resetBlockY+1){ return;//滿足條件,退出遞歸} //白塊可能在重設區塊的:左方、左下、下方if(whiteBlockY== resetBlockY){//左方whiteBlockDown(); }else if(whiteBlockX < resetBlockX){//左下whiteBlockRight(); }else { whiteBlockUp(); } reset2_3();//遞迴} private void reset2_2(int targetX, int targetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//2、把重設區塊移到目標位置正下方return;//退出遞迴} //重設區塊可能位置,目標位置左方、正下方、左下方if( resetBlockX==targetX){//正下方上移resetBlockUp(targetX, targetY); }else{//左方或左下方;先右移再上移resetBlockRight(targetX, targetY); } reset2_2(targetX, targetY);//遞歸} private void reset2(int targetX, int targetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//位置正確不用移動return;//退出遞歸} /* 1、如果白塊正好佔了目標位置:如果復位塊正好在下方,交換及完成復位,如果下方不是複位塊,把白塊移開目標位置* 2、把復位塊移到目標位置正下方* 3、把白塊移動復位塊下方* 4.依照規定的步驟重設*/ //第一步if(whiteBlockX==targetX&& whiteBlockY==targetY){ if(whiteBlockX==resetBlockX&&whiteBlockY==resetBlockY+1){//重設區塊在下方swapBlockAndC returnBlock( ; }else{ whiteBlockDown(); } } //第二步把重設區塊移到目標位置正下方reset2_2(targetX, targetY+1); //第三步驟把白區塊移動重設區塊下方reset2_3(); //第四步驟依照規定的步驟重設swapWhiteBlockAndCurrentBlock (); whiteBlockLeft(); whiteBlockUp(); whiteBlockRight(); whiteBlockDown(); whiteBlockLeft(); whiteBlockUp(); whiteBlockRight(); whiteBlockDown(); swapWhiteBlockAndCurrentBlock(); whiteBlockLeft(); whiteBlockUp(); whiteBlockUp(); whiteBlockRight(); targetY){ 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);//遞歸} private void resetBlockRight(int targetX, int targetY){ 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){//左上和正上witeBwhiteBlockX<resetBlockX+1){//左上和正上witeBwhiteBlockX<resetBlockX+1){//左上和正上witeBwhiteBlockX<resetBlockX+1){//左上、正上witeBwhiteBlockX (); }else{//右上whiteBlockDown(); } } }else if(whiteBlockY==resetBlockY){//同一行if(whiteBlockX<resetBlockX){//左方if(whiteBlockY==n-1){//到底了,只能往上whiteBlockUp(); }else { whiteBlockDown(); } }else{//右方if(whiteBlockX==resetBlockX+1){ 。 (); } } resetBlockRight(targetX, targetY);//遞歸} private void resetBlockLeft(int targetX, int targetY){ 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(); } } }else if(whiteBlockX>resetBlockX){//右上方if(resetBlockY==n-1){//重設區塊在最低端,白塊不能順時針移動whiteBlockLeft(); }else{ whiteBlockDown(); } }else{//左上方whiteBlockDown(); } } }else if(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);//遞歸} private void resetBlockUp(int targetX, int targetY){ if(resetBlockX==target位置正確不用移動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(); } } } } else if (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) {//左下,下;白塊右移i f(resetBlockX==n-1){//重設塊在最右邊,無法逆時針,只有順指針移動白塊if(whiteBlockX==resetBlockX){//正下方whiteBlockLeft(); }else{//左下方whiteBlockUp(); } }else{ whiteBlockRight(); } }else{//右下;白塊上移whiteBlockUp(); } } resetBlockUp(targetX, targetY);//遞歸} / /白塊與重設區塊交換位置private void swapWhiteBlockAndCurrentBlock(){ step++; int tempX = whiteBlockX,tempY = whiteBlockY; int temp = puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX] = puzzle[resetBlockY][resetBlockX]; whiteBlockY = resetBlockY; resetBlockX = tempX; resetBlockY = tempY; println("swap"); } private void whiteBlockDown(){ step++; int temp = puzzle[whiteBlockY][whiteBlockY]; puzzle[whiteBlockY+1][whiteBlockX]; puzzle[whiteBlockY+1][whiteBlockX] = temp; whiteBlockY++; println("↓"); } private void whiteBlockUp(){ stan++++++; ; puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY-1][whiteBlockX]; puzzle[whiteBlockY-1][whiteBlockX] = temp; whiteBlockY--; println("""); int temp = puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY][whiteBlockX-1]; puzzle[whiteBlockY][whiteBlockX-1] =Xtemper; private void whiteBlockRight(){ step++; int temp = puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY][whiteBlockX+1]; println("→"); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("resetBlock=("+resetBlock+","+resetBlockX+","+resetBlockY+")/n" ); if(puzzle!=null){ int len = String.valueOf(n*2-1).length(); for (int y = 0; y < n; y++) { for (int x = 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("puzzle is null"); } return sb.toString(); } private String _str(String str,int len){ str=str==null?" ":str; if(str.length()<len){ return _str(str+" ", len); } return str; } private void println(String str){ if(isPrint){ System.out.println(str); System.out.println(this); } } public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {// System.setOut(new PrintStream("e:/puzzle.txt","UTF-8")); Puzzle p = new Puzzle(); System.out.println(p); try { p.sort(); } catch (Exception e) { e.printStackTrace(); System.out.println("Exception:"); }finally{ System.out.println(p); } }}
以上所述就是本文的全部內容了,希望大家能夠喜歡。