오늘 갑자기 여자친구를 위한 똑똑한 퍼즐 게임을 만들어줘야겠다는 생각이 떠올랐습니다.
이러한 기능을 구현해야 하는데 첫 번째는 그림을 사용자 정의하는 것이고 두 번째는 그리드를 사용자 정의하는 것입니다. 물론 처음에 생각한 것은 3*3 4*4 5*5 였고 사용하지 않았습니다. 3*5와 같은 그리드.
세 번째는 자동 퍼즐 기능을 실현하는 것입니다. 여성은 게임을 잘 못한다는 것은 누구나 다 알고 있을 것이기 때문에 이 자동 퍼즐 기능이 필요합니다.
다른 정지 및 순위에 대해서는 쓰지 않겠습니다!
이제 핵심 질문이 나옵니다. 자동 퍼즐 기능을 구현하기 위한 요구 사항이 좀 높은 것 같습니다! 컴퓨터가 인간과 같을 수 있습니까?
먼저 본질을 살펴보자
직소 퍼즐은 실제로 배열의 문제입니다.
순열의 정의는 다음과 같습니다. 1, 2,...,n의 배열에서 한 쌍의 숫자의 앞뒤 위치가 역순이면, 즉 앞의 숫자가 뒤의 숫자보다 큰 경우, 그런 다음 역순이라고합니다. 순열의 총 역순 수를 이 순열의 역순 수라고 합니다. 반대의 숫자가 짝수인 배열을 짝수 배열이라 하고, 반대의 숫자가 홀수인 배열을 홀수 배열이라고 합니다. 예를 들어 2431에서는 21, 43, 41, 31이 역순이고, 역순이 4이므로 짝수 배열이다.
또 다른 정의는 다음과 같습니다. 순열에서 두 숫자를 교환하면 순열의 패리티가 변경됩니다.
위의 정의는 모두 "Advanced Algebra"에서 가져온 것입니다.
퍼즐 배열은 고르게 배열되어야 합니다. 이는 내 참조에서 찾을 수 있습니다.
이것이 내 퍼즐이 구현되는 방법입니다!
나중에 쓸 예정
참조: 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, 즉 마지막 4개 셀
각 영역은 해당 영역의 규칙에 따라 완료할 수 있습니다.
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;//플랫폼 기반 private int [][] puzzle; private int resetBlock = 0;///빈 블록 위치 private int whiteBlockX; whiteBlockY; //현재 이동하려는 블록의 좌표는 private int ResetBlockY; private boolean isPrint=false; public Puzzle(int()); 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; int times = 100; // 셔플 횟수는 짝수여야 합니다. Random random = new Random(); while (times > 0) { int x0 = random.nextInt(n); 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)){//마지막 것은 대체되지 않습니다.계속; 시간--; int t = puzzle[x0][y0] = 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}};// 퍼즐 = 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 { 재설정(x, y ) ; } } } } //블록을 목표 위치로 재설정 private void Reset(int targetX, int targetY) { //재설정 블록의 현재 위치 찾기 initResetBlock(targetX, targetY) /* * 재설정 순서는 왼쪽에서 오른쪽, 위에서 아래*입니다. 이동 방법은 먼저 위로 이동한 다음 왼쪽으로 이동하는 것입니다* 현재 재설정 블록, 재설정하려는 위치는 네 가지 상황으로 나눌 수 있습니다* 1. 가장 오른쪽 행 또는 맨 아래 두 행 * 2. 가장 오른쪽 행 x=n-1, 맨 아래 두 행은 아님 * 3. 맨 아래 두 행 y=n-2, 맨 오른쪽 행은 아님 * 4. 가장 오른쪽 행은 아래쪽 두 행이기도 합니다. OK*/ 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) }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; } } 재설정(targetX, targetY);//recursion} 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 (퍼즐[y][x] == ResetBlock) {// x, y는 재설정 블록의 위치입니다. ResetBlockX = x; ResetBlockY = y break; if(targetX>=2){// } initResetBlock(targetX, n-1); resetBlockToTarget(targetX, n-2); resetBlockToTarget(targetX+1, n-2); : while (!(whiteBlockX==targetX && whiteBlockY==n-1)) { if(whiteBlockY<n-1){ whiteBlockDown(); 계속 l; } if(whiteBlockX>targetX){ whiteBlockLeft(); 계속 l; } break; } swapWhiteBlockAndCurrentBlock(); puzzle[n-1][targetX]!=(resetBlock+n)){//재설정 성공 안 됨// isPrint=true; Reset3_0(); Reset3(targetX); } } private void Reset3_0(){ if(resetBlockX<n-1){ whiteBlockRight(); swapWhiteBlockAndCurrentBlock(); 재설정3_0() } 반환; void Reset2_3(){ if(whiteBlockX==resetBlockX && whiteBlockY==resetBlockY+1){ return;//조건이 충족되면 재귀를 종료} //흰색 블록은 왼쪽, 왼쪽 아래 또는 아래에 있을 수 있습니다. 재설정 블록의 측면 if(whiteBlockY= =resetBlockY){//왼쪽 whiteBlockDown() }else if(whiteBlockX < ResetBlockX){//왼쪽 아래 whiteBlockRight(); }else { whiteBlockUp(); } Reset2_3();//recursion} private void Reset2_2(int targetX, int targetY){ if(resetBlockX==targetX&&resetBlockY==targetY){//2. 아래로 돌아가기;//재귀 종료} //리셋 블록의 가능한 위치, 대상 위치 왼쪽, 바로 아래, 왼쪽 아래 if(resetBlockX==targetX){//바로 아래 및 위로 이동합니다. ResetBlockUp(targetX, targetY) }else{//왼쪽 또는 왼쪽 아래 먼저; 오른쪽으로 이동한 다음 위로 이동합니다.resetBlockRight(targetX, targetY); } Reset2_2(targetX, targetY);//recursion} private void Reset2(int targetX, int targetY){ if (resetBlockX == target 아래쪽이 재설정 블록이 아닌 경우 흰색 블록을 대상 위치로 이동* 2. 재설정 블록을 대상 위치 바로 아래로 이동* 3. 흰색 블록을 재설정 블록 아래로 이동* 4. 다음에 따라 재설정 지정된 단계로*/ //첫 번째 단계 if(whiteBlockX==targetX&& whiteBlockY==targetY){ if(whiteBlockX==resetBlockX&&whiteBlockY==resetBlockY+1){//재설정 블록은 swapWhiteBlockAndCurrentBlock() 아래에 있습니다. }else{ whiteBlockDown(); } } //두 번째 단계는 재설정 블록을 목표 위치 바로 아래로 이동하는 것입니다.reset2_2(targetX, targetY+1); //세 번째 단계에서는 흰색 블록을 재설정 블록 아래로 이동합니다.reset2_3(); //네 번째 단계에서는 규정된 단계에 따라 swapWhiteBlockAndCurrentBlock()을 재설정합니다. whiteBlockUp(); ); 화이트블록업(); 화이트블록다운(); whiteBlockLeft(); whiteBlockUp(); swapWhiteBlockAndCurrentBlock(); } private void ResetBlockToTarget(int targetX, int targetY){ if(resetBlockX==targetX&&resetBlockY==targetY){// ;//재귀 종료} if(resetBlockY==targetY){//양수 왼쪽 ResetBlockLeft(targetX, targetY); }else{//왼쪽 아래, 오른쪽 아래 if(resetBlockX>=targetX){//오른쪽 아래||아래로 이동 if (resetBlockX==n-1){//리셋 블록은 맨 오른쪽에 있으며 위쪽 이동을 용이하게 하려면 먼저 왼쪽으로 이동합니다. 흰색 블록은 시계 반대 방향입니다. targetY); }else{ ResetBlockUp(targetX, targetY); } }else{//오른쪽 아래 이동 ResetBlockRight(targetX, targetY);//Recursion} private void ResetBlockRight(int , int targetY){ if (resetBlockX == target ; }// System.out.println("resetBlockRight"); if(whiteBlockY<resetBlockY){//위 if(whiteBlockY<resetBlockY-1){//whiteBlockDown() 위의 여러 줄 }else{//위의 행 if(whiteBlockX<resetBlockX+1){//왼쪽 상단 및 whiteBlockRight 바로 위(); }else{//오른쪽 위 whiteBlockDown() } } }else; if(whiteBlockY==resetBlockY){//같은 줄 if(whiteBlockX<resetBlockX){//왼쪽 if(whiteBlockY==n-1){//마지막에는 위로만 올라갈 수 있습니다 whiteBlockUp(); { whiteBlockDown () } }else{//right if(whiteBlockX==resetBlockX+1){ swapWhiteBlockAndCurrentBlock(); return;//재귀 종료}else{ whiteBlockLeft(); } } }else{//하단 if(whiteBlockX <= ResetBlockX){//하단 왼쪽, 하단 whiteBlockRight() }else{//하단 오른쪽 whiteBlockUp(); } } ResetBlockRight(targetX, targetY);//recursion} private void ResetBlockLeft(int targetX, int targetY){ if (resetBlockX == 대상 / 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(); whiteBlockDown(); } }else{//왼쪽 위 whiteBlockDown(); } } }else if(whiteBlockY==resetBlockY){//왼쪽, 오른쪽 if(whiteBlockX<resetBlockX){//left if(whiteBlockX= =resetBlockX- 1){//왼쪽에 공백 하나 swapWhiteBlockAndCurrentBlock();//재귀 반환을 종료합니다. }else{ whiteBlockRight(); } }else{//오른쪽 if(whiteBlockY==n-1){//하단에 있으므로 아래로 이동할 수 없습니다. 위로만 이동할 수 있습니다. }else{ whiteBlockDown(); } } }else{//왼쪽 아래, 오른쪽 아래 if(whiteBlockX<resetBlockX){//왼쪽 아래 if(whiteBlockX==resetBlockX-1) { whiteBlockUp( ); }else{ whiteBlockRight() } }else{//하단, 오른쪽 하단 whiteBlockLeft(); } } ResetBlockLeft(targetX, targetY);//Recursion} private void ResetBlockUp(int targetX, int targetY){ 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() } } } else if (whiteBlockY == ResetBlockY) {//흰색 블록과 재설정 블록은 같은 행에 있습니다. 흰색 블록은 위로 이동합니다. if(whiteBlockX<resetBlockX){//왼쪽으로 전달 if(whiteBlockX<resetBlockX-1){//왼쪽으로 전달 다중 -cell whiteBlockRight(); } else{//왼쪽으로 한 칸 if(whiteBlockY==n-1){//끝 whiteBlockUp() }else; if(resetBlockX==n-1){//리셋 블록은 맨 오른쪽에 있으며 시계 반대 방향으로 이동할 수 없습니다. 흰색 블록만 시계 방향으로 이동할 수 있습니다. whiteBlockUp() }else{ whiteBlockDown() }else{/ /오른쪽 화이트블록업() } }else{//흰색 블록은 재설정 블록 아래에 있습니다. 흰색 블록은 흰색 블록 상단까지 시계 반대 방향으로 회전해야 합니다. //세 가지 상황: 왼쪽 아래, 아래, 아래 right if(whiteBlockX<=resetBlockX) {//왼쪽 아래, 흰색 블록이 오른쪽으로 이동합니다. 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[resetBlockY][resetBlockX] = temp; whiteBlockY = ResetBlockX; ; ResetBlockY = 임시; println("swap"); } private void whiteBlockDown(){ step++; int temp = puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY+1][whiteBlockY+1 ][whiteBlockX] = temp; whiteBlockY++; println("↓"); whiteBlockUp(){ step++; int temp = puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY-1][whiteBlockX] = temp; ; println("↑"); } private void whiteBlockLeft(){ step++; puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY][whiteBlockX-1] = temp; whiteBlockX--; private void whiteBlockRight(){ step++; int temp = puzzle[whiteBlockY][whiteBlockX]; puzzle[whiteBlockY][whiteBlockX] = puzzle[whiteBlockY][whiteBlockX+1] = temp; whiteBlockX++; println("→") } @Override public String toString() { StringBuilder sb = 새로운 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("퍼즐이 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) FileNotFoundException, UnsupportedEncodingException 발생 {// System.setOut(new PrintStream("e:/puzzle.txt","UTF-8")) Puzzle p = new Puzzle(); p.sort(); } catch (예외 e) { e.printStackTrace(); System.out.println("예외:"); }마지막으로{ System.out.println(p) } }}
이상이 이 글의 전체 내용입니다. 모두 마음에 드셨으면 좋겠습니다.