스택(Stack)과 큐(Queue)를 이용한 지렁이 게임
- 프로그래밍/C/C++
- 2018. 7. 29.
스택(Stack)과 큐(Queue)를 이용한 지렁이 게임
이번에는 스택(Stack)과 큐(Queue)를 이용한 지렁이 게임을 만들어 보겠다.
스택은 LIFO (Last In First Out) 나중에 들어온 것이 제일 먼저 나간다라는 뜻이다.
스택을 이용한 계산기도 있으니 이 게시물을 통해서 스택의 구조를 먼저 익히고 오기를 바란다.
그리고 큐는 FIFO (First In First Out) 먼저들어온게 먼저 나간다라는 뜻이다.
큐를 이용한 계산기가 마찬가지로 있으니 이 게시물을 통해서 큐의 구조를 먼저 익히고 오기를 바란다.
[프로그래밍/C] - 큐(Queue)를 이용한 계산기 프로그램
이 두개를 알아보았으니 스택과 큐를 이용해서 지렁이 게임을 만들어보자.
지렁이 게임 만들거는 대략 이런 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <time.h> #include <conio.h> #define LEFT 75 #define RIGHT 77 #define UP 72 #define DOWN 80 #define MAP_X 38 #define MAP_Y 23 #define ESC 27 #define SEE_UP 1 #define SEE_DOWN 2 #define SEE_LEFT 3 #define SEE_RIGHT 4 typedef struct xy { int x; int y; }XY; typedef struct NODE { int t; int x; int y; struct NODE *tail; }Node; void gotoxy(int x, int y); void insertNode(Node **head, int x, int y); void insertObs(Node **Obs, int x, int y); void createTail(XY *tails, Node *obs); void createObs(Node *Head, Node **obs, XY *tails); void init_Game(Node ** HEAD, XY *tails); void end_Game(); void checkWall(Node *HEAD); void checkObject(Node **HEAD, XY *tails, Node **obs); void moveSnake(Node *HEAD, int s); void start_Game(Node **HEAD, XY *tails); | cs |
일단 main.h파일이다.
헤더파일에는 함수의 원형과 구조체, define으로 설정해준것을 넣어줬다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #include "main.h" void start_Game(Node **HEAD, XY *tails) // 게임 시작 { Node *obs = NULL; char ip = '\0'; int s_see = SEE_LEFT, count = 0; int gameSpd = 250, score = 0; short ctime = (short)time(0); short mtime; while (1) { if (_kbhit()) { ip = _getch(); switch (ip) { case LEFT: s_see = SEE_LEFT; break; case RIGHT: s_see = SEE_RIGHT; break; case UP: s_see = SEE_UP; break; case DOWN: s_see = SEE_DOWN; break; case ESC: exit(1); break; } ip = '\0'; } else { // 키 입력이 없을 때 moveSnake(*HEAD, s_see); checkObject(HEAD, tails, &obs); gotoxy(tails->x * 2, tails->y); printf("⊙"); if (obs != NULL) { gotoxy(obs->x * 2, obs->y); printf("▩"); } Sleep(gameSpd); } mtime = (short)time(0); if (mtime - ctime >= 1) // 게임 속도 조절 { ctime = mtime; count++; if (count == 10) { count = 0; if (gameSpd - (*HEAD)->t * 2 > 40) gameSpd -= (*HEAD)->t * 2; } score += ((*HEAD)->t * (*HEAD)->t) * 10 + (*HEAD)->t; // 점수 계산 gotoxy(0, MAP_Y + 1); // 점수 출력 printf("YOUR SCORE [ %d ] / TAILS [ %d ] / GAME SPEED [ %d ]", score, (*HEAD)->t, gameSpd); } } } void end_Game() { gotoxy(0, MAP_Y / 2); printf("[ 게임 오버 ][ 게임 오버 ][ 게임 오버 ][ 게임 오버 ][ 게임 오버 ][ 게임 오버 ]"); _getch(); exit(1); } main() { Node *HEAD = NULL; XY tails = { 0,0 }; srand((unsigned)time(NULL)); printf("┏━━━━━━━━━━┓\n"); printf("┃ ┃\n"); printf("┃ 지렁이게임 ┃\n"); printf("┃ (스택,큐 연습) ┃\n"); printf("┃ ┃\n"); printf("┗━━━━━━━━━━┛\n\n"); printf("> 게임키 : 방향키 좌( ← ), 우( → ), 위( ↑ ), 아래( ↓ )\n"); printf(" - 게임종료 ESC\n\n"); printf("> 게임을 시작하시려면 아무키나 눌러주세요 <"); _getch(); system("cls"); init_Game(&HEAD, &tails); start_Game(&HEAD, &tails); } | cs |
main.c 파일이다.
73~74행에서 Node 포인터 변수와 XY 구조체를 0으로 초기화 해준다. (main.h파일을 보면 알수있다.)
75행에서 시간을 초기화 해준다.
87행에서 게임 초기화를 해준다. 맵을 만들어주는 것이다.
88행에서 게임을 시작한다.
나머지는 다 코드를 분석해보면 안다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include "main.h" void init_Game(Node ** HEAD, XY *tails) // 게임 초기화 { int i = 0, k = 0; for (i = 0; i <= MAP_Y; i++) // 맵 테두리 만들기 { for (k = 0; k <= MAP_X; k++) { if (i == 0 || i == MAP_Y || k == 0) { printf("▩"); } if (k == MAP_X) { gotoxy((MAP_X) * 2, i); printf("▩"); } } printf("\n"); } insertNode(&(*HEAD), MAP_X - 2, MAP_Y / 2); createTail(tails, NULL); } void checkWall(Node *HEAD) { if (HEAD->x < 1 || HEAD->x >= MAP_X || HEAD->y < 1 || HEAD->y >= MAP_Y) end_Game(); } | cs |
map.c 파일이다.
5행에서 MAP_Y는 23으로 지정되어 있다.
7행에서 MAP_Y는 38으로 지정되어 있다.
9행에서 i가 0이거나 MAP_Y 이거나 k가 0이면 ▩를 출력해준다.
13행에서 k가 MAP_X면 MAP_X * 2, i 좌표로 이동해서 ▩를 출력해준다.
21행에서 큐에다가 삽입을 해준다.
코드 분석을 내가 일일이 해주니 너무 시간이 오래걸린다. 그러므로 직접 코드를 분석해보기를 바란다.
모르는 곳이 있으면 책을 찾아보든 물어보든가 하자. 그래야 실력이 오른다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | #include "main.h" void checkObject(Node **HEAD, XY *tails, Node **obs) { Node *tmp = (*HEAD)->tail; checkWall(*HEAD); // 벽 while (tmp != NULL) // 자기 꼬리 { if (tmp->x == (*HEAD)->x && tmp->y == (*HEAD)->y) end_Game(); tmp = tmp->tail; } if ((tails->x == (*HEAD)->x) && (tails->y == (*HEAD)->y)) // 꼬리 { insertNode(&(*HEAD), (*HEAD)->x, (*HEAD)->y); (*HEAD)->t++; createTail(tails, *obs); createObs(*HEAD, &(*obs), tails); createObs(*HEAD, &(*obs), tails); } while (*obs != NULL) // 장애물 { if ((*obs)->x == (*HEAD)->x && (*obs)->y == (*HEAD)->y) end_Game(); obs = &(*obs)->tail; } } void moveSnake(Node *HEAD, int s) // 뱀의 이동 { Node *tmp = HEAD; XY tmp1 = { HEAD->x,HEAD->y }; XY tmp2 = tmp1; if (s == SEE_LEFT) // 바라보는 방향으로 이동 HEAD->x -= 1; else if (s == SEE_RIGHT) HEAD->x += 1; else if (s == SEE_UP) HEAD->y -= 1; else HEAD->y += 1; HEAD = HEAD->tail; while (HEAD != NULL) // 꼬리들 좌표 전달 { tmp2.x = HEAD->x; tmp2.y = HEAD->y; HEAD->x = tmp1.x; HEAD->y = tmp1.y; tmp1.x = tmp2.x; tmp1.y = tmp2.y; HEAD = HEAD->tail; } gotoxy(tmp2.x * 2, tmp2.y); // 맨 뒤 꼬리 지우기 printf(" "); gotoxy(tmp->x * 2, tmp->y); // 머리 출력 printf("◎"); if (tmp->tail != NULL) // 전 머리부분 몸통 출력 { gotoxy(tmp->tail->x * 2, tmp->tail->y); printf("⊙"); } } void createTail(XY *tails, Node *obs) // 보너스 꼬리 아이템 생성 { int flag = 1; while (flag) { flag = 0; tails->x = rand() % (MAP_X - 1) + 1; tails->y = rand() % (MAP_Y - 1) + 1; while (obs != NULL) // 장애물하고 위치 중복 체크 { if (obs->x == tails->x && obs->y == tails->y) { flag = 1; break; } obs = obs->tail; } } gotoxy(tails->x * 2, tails->y); printf("⊙"); } void createObs(Node *Head, Node **obs, XY *tails) // 장애물 생성 { Node *tmp = *obs; int flag = 1; XY oxy = { 0,0 }; while (flag) { flag = 0; oxy.x = rand() % (MAP_X - 1) + 1; oxy.y = rand() % (MAP_Y - 1) + 1; if ((oxy.x == tails->x && oxy.y == tails->y) || // 뱀의 머리, 보너스 꼬리 아이템하고 위치 중복 체크 (oxy.x == Head->x && oxy.x == Head->y)) { flag = 1; continue; } while (tmp != NULL) // 이전에 생성된 장애물들과 위치 중복 체크 { if (tmp->x == oxy.x && tmp->y == oxy.y) { flag = 1; break; } tmp = tmp->tail; } } insertObs(&(*obs), oxy.x, oxy.y); // 장애물 추가 gotoxy(oxy.x * 2, oxy.y); printf("▩"); } | cs |
snake.c 파일이다.
뱀의 부분에 해당하는 부분이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include "main.h" void gotoxy(int x, int y) { COORD pos = { x, y }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } Node* getNode() // 노드 생성 { Node *newNode = (Node*)malloc(sizeof(Node)); newNode->tail = NULL; return newNode; } void insertNode(Node **head, int x, int y) // 큐 { if (*head == NULL) { *head = getNode(); (*head)->x = x; (*head)->y = y; (*head)->t = 0; } else insertNode(&(*head)->tail, x, y); } void insertObs(Node **Obs, int x, int y) // 스택 { Node *tmp = *Obs; *Obs = getNode(); (*Obs)->x = x; (*Obs)->y = y; if (*Obs != NULL) (*Obs)->tail = tmp; } | cs |
StackQueue.c 파일이다.
스택과 큐 부분에 있는 소스파일이다.
이렇게 스택과 큐를 이용해 지렁이 게임을 만들어보았다.
모르는 부분은 댓글로 물어보기를 바란다.
실시간으로 답을 해줄것이다.