#include <stdio.h>
#include <conio.h> //getch함수헤더
#include <windows.h> //gotoxy함수헤더
#define LEFT 75
#define RIGHT 77
#define ENTER 13
#define ESC 27
void gotoxy(int x, int y)
{
COORD pos = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
typedef enum { NOCURSOR, SOLIDCURSOR, NORMALCURSOR } CURSOR_TYPE; //커서숨기기 함수
void setcursortype(CURSOR_TYPE c) {
CONSOLE_CURSOR_INFO CurInfo;
switch (c) {
case NOCURSOR:
CurInfo.dwSize = 1;
CurInfo.bVisible = FALSE;
break;
case SOLIDCURSOR:
CurInfo.dwSize = 100;
CurInfo.bVisible = TRUE;
break;
case NORMALCURSOR:
CurInfo.dwSize = 20;
CurInfo.bVisible = TRUE;
break;
}
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &CurInfo);
}
int cursor_p; //커서의 위치(0:첫번째 장대, 1:두번재 장대, 2:세번째 장대)
int cursor_s; //커서가 가지고 있는 블록의 크기값
int cnt; // 몇번 이동했는지를 저장
int x, y; // 좌표값
int key; // 키 입력을 저장하는 변수
int hanoi[4][3]; //hanoi tower 블록 위치, 갯수를 저장하는 이차원 배열
void reset(void); // 게임을 초기화
void draw(void); // 화면을 그리는 함수
void getblock(void); //블록을 잡는 함수
void dropblock(void); //블록을 떨어트리는 함수
void win(void); // 승리조건 확인
void menu(void); //메뉴를 호출
int main() {
reset(); //게임 초기화
while (1) {
key = getch();//getch함수는 문자키가 눌려졌을 때 문자를 리턴.
if (key == 0xE0 || key == 0) { //문자가 할당되지 않은 확장키는 0xE0또는 0의 특이값을 리턴하도록 함
key = getch(); //그래서 한번더 getch를 호출해야 확장키의 코드를 구할수있음
switch (key) {
case LEFT:
if (cursor_p>0) cursor_p--; //커서가 장대 1,2번째에 있으면 누른만큼 왼쪽으로 커서 이동
break;
case RIGHT://커서가 장대 0,1번째에 있으면 오른쪽으로 이동
if (cursor_p<2) cursor_p++;
break;
}
}
else if (key == ENTER && cursor_s == 0) getblock(); //엔터눌렀을 때 커서가 0이면(블록을 안가지고 있음) get으로 커서가 블록을 잡음
else if (key == ENTER && cursor_s != 0) dropblock();//엔터눌렀을 때 커서가 0이 아니면(블록을 가지고 있음)drop으로 블록을 내림
else if (key == ESC) menu(); //esc를 누르면 메뉴호출
draw();
if (hanoi[0][2] == 3) win(); // 오른쪽 젤 윗칸에 3칸짜리 블록이 위치하면 승리
}
}
void reset(void)//초기화
{ int i, j;
setcursortype(NOCURSOR);
for (i = 0; i<4; i++) {
for (j = 0; j<3; j++) {
hanoi[i][j] = 0;
} //옮겨진 블록을 다 0으로 만듦
}
hanoi[0][0] = 3; //i가 세로 맨위층 j가 0번째 장대의미
hanoi[1][0] = 5; //i가 세로 그밑층 j가 0번째 장대의미
hanoi[2][0] = 7;
hanoi[3][0] = 9;
cursor_p = 0;
cursor_s = 0;
cnt = 0;
draw();
}
void draw(void) {
int i, j, k;
x = 24;
y = 3;
gotoxy(x, y);
switch (cursor_p) { //커서부분을 그리는 부분
case 0:
if (cursor_s == 0) {
printf(" * ");
}
else {
for (k = 0; k<(11 - cursor_s) / 2; k++) {
putchar(' ');
}
for (k = 0; k<cursor_s; k++) {
putchar('#');
}
for (k = 0; k<(11 - cursor_s) / 2; k++) {
putchar(' ');
}
printf(" ");
}
break;
case 1:
if (cursor_s == 0) {
printf(" * ");
}
else {
printf(" ");
for (k = 0; k<(11 - cursor_s) / 2; k++) {
putchar(' ');
}
for (k = 0; k<cursor_s; k++) {
putchar('#');
}
for (k = 0; k<(11 - cursor_s) / 2; k++) {
putchar(' ');
}
printf(" ");
}
break;
case 2:
if (cursor_s == 0) {
printf(" * ");
}
else {
printf(" ");
for (k = 0; k<(11 - cursor_s) / 2; k++) {
putchar(' ');
}
for (k = 0; k<cursor_s; k++) {
putchar('#');
}
for (k = 0; k<(11 - cursor_s) / 2; k++) {
putchar(' ');
}
}
break;
}
y += 2;
gotoxy(x, y++);
printf(" | | | "); //이건 그냥 장식용 장대입니다..
for (i = 0; i<4; i++) { // 하노이 타워 그리는 부분
gotoxy(x, y + i);
for (j = 0; j<3; j++) {
if (hanoi[i][j] == 0) {
printf(" | ");
}
else {
for (k = 0; k<(11 - hanoi[i][j]) / 2; k++) {
putchar(' ');
}
for (k = 0; k<hanoi[i][j]; k++) {
putchar('#');
}
for (k = 0; k<(11 - hanoi[i][j]) / 2; k++) {
putchar(' ');
}
}
}
}
y += 4;
gotoxy(x - 2, y);
printf("──────────────────"); //타워 받침
gotoxy(x - 2, ++y);
printf("MOVES : %3d", cnt);
y++;
gotoxy(x + 4, ++y);
printf("┌─────────┐");
gotoxy(x + 4, ++y);
printf("│ HANOI TOWER GAME │");
gotoxy(x + 4, ++y);
printf("└─────────┘");
y++;
y++;
gotoxy(x - 2, ++y); printf("KEYS : ENTER, ←, →, ESC (MENU)");
y++;
}
void getblock(void) {
int i;
for (i = 0; i<4; i++) { //위에서 부터 아래로 체크해가면서
if (hanoi[i][cursor_p] != 0) { //블록이 나타나면 (값이 0이 아니면)?
cursor_s = hanoi[i][cursor_p]; //그 값을 저장하고
hanoi[i][cursor_p] = 0; // 그 칸을 지움(값을 0으로)
return;
}
}
}
void dropblock(void) {
int i;
for (i = 1; i<4; i++) {
if (hanoi[i][cursor_p] != 0 && hanoi[i][cursor_p]>cursor_s) {
// 블록값이 있고 잡고있는 블록값보다 높은 경우
hanoi[i - 1][cursor_p] = cursor_s; // 그 블록 위에(i-1) 블록값을 전달
cursor_s = 0; //잡고 있는 블록값은 0으로
cnt++; //턴수 증가
return;
}
}
if (hanoi[3][cursor_p] == 0) { // 장대에 블록이 하나도 없는 경우
hanoi[3][cursor_p] = cursor_s; // 제일 바닥칸에 블록을 넣음
cursor_s = 0; // 잡고 있는 불록값은 0으로
cnt++; //턴수 증가
return;
}
}
void win(void) {
int ch;
gotoxy(7, 1);
printf("Completed! Your move : %3d", cnt);
gotoxy(7, 2);
printf("Play again?(Y/N) : ");
setcursortype(NORMALCURSOR);
while (1) {
fflush(stdin);
ch = getch();
switch (ch) {
case 89:
case 121:
system("cls");
setcursortype(NOCURSOR);
reset();
return;
case 78:
case 110:
system("cls");
exit(0);
}
}
}
void menu(void) {
int ch;
setcursortype(NORMALCURSOR);
gotoxy(7, 1);
printf("MENU: RESUME(ENTER), RESTART(1), QUIT(2) :");
while (1) {
ch = getch();
switch (ch) {
case 49:
system("cls");
setcursortype(NOCURSOR);
reset();
return;
case 50:
system("cls");
exit(0);
case ENTER:
system("cls");
setcursortype(NOCURSOR);
draw();
return;
}
}
}