#include <iostream>
#include <conio.h>
#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define ESC 27
using namespace std;
void initializeArray(int **arr, int n); // 동적 2차원 배열 초기화
void mixArray(int** arr, int n, int& zero_i, int& zero_j); // 2차원 배열 섞기
void moveZero(int** arr, int& zero_i, int& zero_j, int n); // 0 옮기기
void main(){
int **arr, n, temp, zero_i,zero_j; // 2차원 포인터 arr, temp, 0위치 저장 zero_i,j ,key값 저장용
cout<<"배열 크기 입력: (n*n)";
cin>>n; // n by n 배열값 입력
arr = (int**) calloc ( sizeof(int*) , n ); // 행 생성
initializeArray(arr, n); // 2차원 배열 만들기 위한 열 생성 함수
cout<<"\n변경 전\n"; // 섞기 전 배열 출력
for(int i=0; i<n; ++i){
for(int j=0; j<n; ++j) printf("%d ", arr[i][j]);
printf("\n");
}
cout<<"\n변경 후\n";
mixArray(arr,n,zero_i,zero_j); // 섞기 함수
for(int i=0; i<n; i++){ // 섞은 배열 출력
for(int j=0; j<n; j++) printf("%d ", arr[i][j]);
printf("\n");
}
while(1){
moveZero(arr, zero_i, zero_j, n); // 배열, 0위치, 배열길이 전달 후 게임 시작
for(int i=0; i<n; i++){
for(int j=0; j<n; j++)
printf("%d ", arr[i][j]); // 출력
printf("\n");
}
}
}
void initializeArray(int **arr, int n){ // 배열 선언 & 초기화 함수
for(int i=0, a=0; i<n; i++, a++) { //
arr[i] = (int*) malloc ( sizeof(int) * n ); // 2차원 배열 위한 열 생성
for(int j=0; j<n; ++j, a++){ // 초기화
arr[i][j] = a; // a를 인덱스로 초기화
}
}
}
void mixArray(int** arr, int n, int& zero_i, int& zero_j){ // 배열 섞기 함수
int temp;
for (int i=0; i<n; i++)
for(int j=0; j<n; j++){
int rnd1 = rand() % n; // 0~n-1 까지 난수 발생 후 초기화
int rnd2 = rand() % n;
temp = arr[rnd1][rnd2]; // temp에 저장 후
arr[rnd1][rnd2] = arr[rnd2][rnd1]; // 행 열 바꿔준걸로 초기화 후
arr[rnd2][rnd1] = temp; // temp값을 초기화 해줌
if(arr[i][j] == 0) { // 0이라면 제로값 좌표 초기화
zero_i=i;
zero_j=j;
}
}
}
void moveZero(int** arr, int& zero_i, int& zero_j, int n){ // 0위치 변경 함수
int key[2], temp; // 키값 입력용, temp 변수 선언
key[0]=getch();
key[1]=getch(); // 키값 받아오고
system("cls");
switch(key[1]) {
case LEFT:
if (zero_j == 0) { // 왼쪽으로 가다가 벽을 만난다면 (j가 0 이라면)
temp = arr[zero_i][zero_j]; // 임시저장 후
arr[zero_i][zero_j] = arr[zero_i][n-1]; // n-1 즉 j를 오른쪽 끝 벽 값을 초기화 하고
arr[zero_i][n-1] = temp; // 끝벽에 임시값 초기화
zero_j=(n-1); // 그리고 j값을 끝벽값으로 초기화
break; // 탈출
}
temp = arr[zero_i][zero_j]; // 왼쪽으로 이동 위한 현재값 임시 저장
arr[zero_i][zero_j] = arr[zero_i][zero_j-1]; // 현재값과 왼쪽값 변경
arr[zero_i][zero_j-1] = temp; // 왼쪽값에 현재값 저장
zero_j--; // 행 위치 하락
break;
case RIGHT:
if (zero_j == n-1) { // 만약 오른쪽 끝벽을 만났다면
temp = arr[zero_i][zero_j]; // 임시저장 후
arr[zero_i][zero_j] = arr[zero_i][0]; // 가장 왼쪽 벽 값을 초기화 하고
arr[zero_i][0] = temp; // 왼쪽벽 값은 오른쪽 끝벽 값으로 초기화
zero_j=0; // j값 오른쪽 끝 벽으로 초기화
break;
}
temp = arr[zero_i][zero_j]; // 현재 값 임시저장
arr[zero_i][zero_j] = arr[zero_i][zero_j+1]; // 오른쪽 값을 초기화 하고
arr[zero_i][zero_j+1] = temp; // 오른쪽 값에 다시 임시 저장값 초기화
zero_j++; // j값 상승
break;
case DOWN:
if (zero_i == n-1) { // 만약 열 좌표 값이 넘어갈 수 없는 최대치 라면
temp = arr[zero_i][zero_j]; // 임시저장 후
arr[zero_i][zero_j] = arr[0][zero_j]; // 열이 0인 행렬과 값 스위치
arr[0][zero_j] = temp; // 0 행렬은 끝벽값 초기화
zero_i=0; // i값 초기화
break;
}
temp = arr[zero_i][zero_j]; // 임시저장 후
arr[zero_i][zero_j] = arr[zero_i+1][zero_j]; // 아래 행렬과 값 스위치
arr[zero_i+1][zero_j] = temp; // 아래 행렬에 현재 값이었던 임시저장값 초기화
zero_i+=1; // 열값 상승
break;
case UP:
if (zero_i == 0) { // 만약 위로 넘어갈 수 없다면
temp = arr[zero_i][zero_j]; // 현재 값 임시 저장 후
arr[zero_i][zero_j] = arr[n-1][zero_j]; // i가 n-1인 아래 끝 벽의 행렬값과 스위칭 후
arr[n-1][zero_j] = temp; // 끝벽 행렬값을 임시저장값으로 초기화
zero_i=n-1; // 열값 갱신
break;
}
temp = arr[zero_i][zero_j]; // 현재 값 임시 저장 후
arr[zero_i][zero_j] = arr[zero_i-1][zero_j]; // 위 행렬값과 스위칭
arr[zero_i-1][zero_j] = temp; // 위 행렬값엔 임시저장값 초기화
zero_i-=1; // 열값 갱신
break;
}
}