재수강 중인 C언어 과목에서 처음으로 어려운 프로젝트가 나왔다. 오픈소스를 참고해서 하라고 하셨지만 실력도 길러볼겸 처음부터 짜봤다. 더럽게 오래걸렸다,,,, 후 하루종일 이것만 잡고 있던 것 같다.
게임의 법칙:
절대 규칙:
(4점) 게임에서 반듯이 따라야 하는 규칙
1. 게임의 울타리 크기는 x 방향(오른쪽)으로 “-”가 40개, y 방향(화면 아래)으로 “|”가 30개 로 구성된다.
2. 실행 프로그램을 로딩하면 게임이 자동으로 시작된다.
3. 뱀을 화살표를 사용하여 움직이도록 한다. 방향키를 한번 누룰 때 마다 1 좌표씩 이동한 다.
4. 프로그램 소스와 실행파일(exe)을 업로드 한다. 실행파일 이름에 자신의 학번 또는 이름이 포함되도록 한다.
5. cheating을 하지 않는다.
상대 규칙:
1. (1점) 뱀의 머리는 “>”로 표현한다. 초기 몸통의 길이는 “=”를 1개로 한다. 초기 뱀의 위치 는 울타리의 중앙(20,15)에서 시작하고 우측(x)으로 향한다.
2. (1점) 화면상의 여러 좌표에 임의적(random)으로 먹이를 공급한다.
3. (1점) 뱀이 그 먹이를 먹을 때마다 뱀의 몸통 길이는 1씩 증가하는데 “=” 1개로 뱀 몸통길 이 증가를 표현한다.
4. (1점) 게임 기회로 4번의 목숨이 있으며, 울타리나 뱀 자신의 몸통에 부닥치면 게임 기회는 1씩 감소한다. 새로운 기회로 게임을 재 시작 할 때 뱀은 화면의 중앙(20,15)에서 시작하고 우측(x)으로 향한다.
5. (1점) 한 번 게임을 시작하면 목숨이 목숨을 다하거나 또는 ESC 키를 누를 때까지 진행된 다.
6. (1점) 게임자들의 점수를 파일로 기록하도록 한다. 파일의 형태는 plain 텍스트 파일로 저 장하여 메모장으로 저장 내용을 확인 할 수 있어야 한다. 파일 저장 예) record.txt
#include <stdio.h> //15051038 이태희
#include <Windows.h>
#include <conio.h>
#include<time.h>
#include<stdlib.h>
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_ESC 27
#define fence_ROW 30
#define fence_COLUNM 42
#define SNAKE_ROW 29
#define SNAKE_COLUNM 41
#define LIFE 4;
FILE *fp = NULL; //정보 저장을 위한 파일
int tail = (29 * 41)-3; //초기 뱀의 꼬리를 설정시 필요
int life = LIFE;
int score = 0;
int super_score = 0;
bool UP=false;
bool DOWN= false;
bool LEFT= false;
bool RIGHT=true;
bool ExitOutLoop = true; //먹이 변수
bool GAME_OVER=false;
bool esc = false; // ESC를 누를시 종료를 위한 불대수
char fence[fence_ROW][fence_COLUNM];
//int x = 2;
typedef struct snake
{
int x, y;
}
SNAKE;
SNAKE body_location[SNAKE_ROW][SNAKE_COLUNM]; //뱀의 최대 몸길이 29*41
SNAKE body_l_temp[SNAKE_ROW][SNAKE_COLUNM]; //머리가 지나간 자리를 따라 올 수 있게 해주는 temp
SNAKE Food;
char SNAKE_LENGTH[SNAKE_ROW][SNAKE_COLUNM]; //뱀의 길이가 들어있는 배열
void SNAKE_BODY(); //뱀의 몸통의 갯수와 좌표 초기화 함수
void gotoxy(int x, int y);//좌표 찍어주는 함수
void Drow_fence(void); //울타리 그리기
void MAKE_fence(void); //울타리 만들기
void KEY_INPUT(void); //키 입력 받기 귀찮더라도 불대수로 비교해줘야 딜레이가 적게 생긴다.
void CursorView(char show); //커서숨기기
void PRINT_SNAKE(); //뱀그리기
void MOVE();//움직이기
void FOOD();
void RESET();//리셋 조건
void RESET_OVER(); //리셋 식
void END(); //종료
int KEY; int X = 20; int Y = 15;
int main(void) {
gotoxy(50, 5);
printf("15051038 이태희");
gotoxy(50, 10);
printf("남은목숨 = %d 현제점수 = %d 최고점수 = %d", life, score, super_score);
gotoxy(100, 100);
CursorView(0);
gotoxy(0, 0);
MAKE_fence();
SNAKE_BODY();
while (1) {
FOOD(); PRINT_SNAKE(); KEY_INPUT(); Sleep(150); MOVE(); RESET(); RESET_OVER();
if (life <= 0 || esc) {
END(); break;
}
}
}
void gotoxy(int x, int y) {
COORD CursorPosition = { x, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CursorPosition);
}
void MAKE_fence(void) {
int i = 0, j = 0;
for (i = 0; i < fence_ROW; i++)
for (j = 0; j < fence_COLUNM; j++) {
fence[i][j] = ' '; }
for (i = 0; i < fence_COLUNM; i++) {
fence[0][i]='-'; fence[fence_ROW -1][i]='-'; }
for (i = 0; i < fence_ROW; i++) {
fence[i][0] = '|'; fence[i][fence_COLUNM -1]= '|';
}
Drow_fence();
}
void Drow_fence(void) {
int i, j;
for (i = 0; i < fence_ROW; i++) {
for (j = 0; j < fence_COLUNM; j++) {
printf("%c", fence[i][j]);
}
printf("\n");
}
}
void KEY_INPUT(void) {
if (_kbhit()) { // 키보드가 눌렸니? 체크
KEY = _getch();
switch (KEY) {
case KEY_UP:
if (DOWN != true) {
UP = true;
DOWN = false;
LEFT = false;
RIGHT = false;
break;
}
case KEY_DOWN:
if (UP != true) {
UP = false;
DOWN = true;
LEFT = false;
RIGHT = false;
break;
}
case KEY_LEFT:
if (RIGHT != true) {
UP = false;
DOWN = false;
LEFT = true;
RIGHT = false;
break;
}
case KEY_RIGHT:
if (LEFT != true) {
UP = false;
DOWN = false;
LEFT = false;
RIGHT = true;
break;
}
case KEY_ESC: {
UP = false;
DOWN = false;
LEFT = false;
RIGHT = true;
esc = true;
break;
}
}
}
}
void CursorView(char show)//커서숨기기 {
HANDLE hConsole;
CONSOLE_CURSOR_INFO ConsoleCursor;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
ConsoleCursor.bVisible = show;
ConsoleCursor.dwSize = 1;
SetConsoleCursorInfo(hConsole, &ConsoleCursor);
}
void SNAKE_BODY() {
int i, j;
for (i = 0; i < SNAKE_ROW; i++)
for (j = 0; j < SNAKE_COLUNM; j++)
SNAKE_LENGTH[i][j] = ' ';
SNAKE_LENGTH[SNAKE_ROW-1][SNAKE_COLUNM-1] = '>';
SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 2] = '=';
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 3] = '='; //초기에 꼬리 늘리기
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 4] = '=';
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 5] = '=';
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 6] = '=';
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 7] = '=';
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 8] = '=';
//SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 9] = '=';
body_location[SNAKE_ROW - 1][SNAKE_COLUNM -1].x = 20;
body_location[SNAKE_ROW - 1][SNAKE_COLUNM -1].y = 15;
body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 2].x = 19;
body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 2].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 3].x = 18;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 3].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 4].x = 17;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 4].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 5].x = 16;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 5].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 6].x = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 6].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 7].x = 14;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 7].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 8].x = 13;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 8].y = 15;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 9].x = 12;
//body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 9].y = 15;
for (i = SNAKE_ROW - 1; i >= 0; i--) {
for (j = SNAKE_COLUNM - 2; j >= 0; j--) {
{ gotoxy(body_location[i][j].x, body_location[i][j].y);
printf(" ");
body_location[i][j].x = 0;
body_location[i][j].y = 0;
}
}
}
}
void PRINT_SNAKE() {
int i, j;
bool escape = false;
for (i = SNAKE_ROW - 1; i >= 0; i--) {
for (j = SNAKE_COLUNM - 1; j >= 0; j--) {
if (SNAKE_LENGTH[i][j] != ' ') {
gotoxy(body_location[i][j].x, body_location[i][j].y);
printf("%c", SNAKE_LENGTH[i][j]);
}
else {
gotoxy(body_location[i][j].x, body_location[i][j].y);
printf(" ");
body_location[i][j].x = 0; body_location[i][j].y = 0;
escape = true;
gotoxy(0, 0);
printf("|");
break;
}
}
if (escape) {
escape = false; break;
}
}
}
void MOVE() {
int i, j;
int z = 0;
SNAKE *t = &body_l_temp[0][0]; //속도와 인덱스의 통일을 위해 포인터로 한다.
SNAKE *l = &body_location[0][0];
if (UP == true)
for (i = 0; i < SNAKE_ROW; i++) //내가짠 건데도 뭔가 잘 모르겠다,,,, 의식의 흐름대로 하다보니 되버렸다.
for (j = 0; j < SNAKE_COLUNM; j++) {
if (SNAKE_LENGTH[i][j] != ' ') {
SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 1] = '^';
*(t+z) = *(l+z); *(l+z - 1) = *(t+z); (*(l + z)).y--;
//body_l_temp[i][j] = body_location[i][j]; //혹시 헷갈릴까봐 직관적인 배열을 적어논다
//body_location[i][j - 1] = body_l_temp[i][j];
//body_location[i][j].y--;
}
z++;
}
if (DOWN == true)
for (i = 0; i < SNAKE_ROW; i++)
for (j = 0; j < SNAKE_COLUNM; j++) {
if(SNAKE_LENGTH[i][j] != ' ') {
SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 1] = 'v'; *(t + z) = *(l + z); *(l + z - 1) = *(t + z); (*(l + z)).y++;
} z++;
}
if (LEFT == true)
for (i = 0; i < SNAKE_ROW; i++)
for (j = 0; j < SNAKE_COLUNM; j++) {
if (SNAKE_LENGTH[i][j] != ' ') {
SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 1] = '<'; *(t + z) = *(l + z); *(l + z - 1) = *(t + z); (*(l + z)).x--;
} z++;
}
if (RIGHT == true)
for (i = 0; i < SNAKE_ROW; i++)
for (j = 0; j < SNAKE_COLUNM; j++) {
if (SNAKE_LENGTH[i][j] != ' ') {
SNAKE_LENGTH[SNAKE_ROW - 1][SNAKE_COLUNM - 1] = '>'; *(t + z) = *(l + z); *(l + z - 1) = *(t + z); (*(l + z)).x++;
}
z++;
} z = 0;
}
void DELET() {
int i, j;
for (i = SNAKE_ROW - 1; i >= 0; i--)
for (j = SNAKE_COLUNM - 1; j >= 0; j--) {
if (SNAKE_LENGTH[i][j] == ' ') {
gotoxy(body_location[i][j].x, body_location[i][j].y);
printf(" "); break;
}
}
}
void FOOD() {
char *x = &SNAKE_LENGTH[0][0];
srand(time(NULL));
if (ExitOutLoop == true) {
Food.x = (rand() % (SNAKE_COLUNM-2))+1;
Food.y = (rand() % (SNAKE_ROW-2))+1;
gotoxy(Food.x, Food.y);
printf("@"); ExitOutLoop = false;
}
if (body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 1].x == Food.x && body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 1].y == Food.y) {
gotoxy(Food.x, Food.y);
*(x+ tail)= '=';
printf(" ");
ExitOutLoop = true;
tail--;
score++;
if (score >= super_score)
super_score = score; gotoxy(50, 5);
printf("15051038 이태희");
gotoxy(50, 10);
printf("남은목숨 = %d 현제점수 = %d 최고점수 = %d", life, score, super_score);
if (tail == 0)
printf("게임 클리어!!!!!!!!!!!!!!!!!!!!");
}
}
void RESET() {
int i, j;
if (fence[body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 1].y][body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 1].x] != ' ') {
GAME_OVER = true;
}
for (i = SNAKE_ROW - 1; i >= 0; i--)
for (j = SNAKE_COLUNM - 2; j >= 0; j--) {
if (body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 1].x == body_location[i][j].x && body_location[SNAKE_ROW - 1][SNAKE_COLUNM - 1].y == body_location[i][j].y) {
GAME_OVER = true;
}
}
}
void RESET_OVER() {
int i=10;
if (GAME_OVER) {
life--;
SNAKE_BODY();
UP = false;
DOWN = false;
LEFT = false;
RIGHT = true;
gotoxy(0, 0);
MAKE_fence();
gotoxy(Food.x, Food.y);
printf("@");
score = 0;
gotoxy(50, 5);
printf("15051038 이태희");
gotoxy(50, 10);
printf("남은목숨 = %d 현제점수 = %d 최고점수 = %d", life, score, super_score);
tail = (29 * 41) - 3;
GAME_OVER = false;
while(i){
if (_kbhit()) // 남아있는 버퍼를 지우기 위해
_getch(); i--;
}
}
}
void END() {
int i, j;
bool z = true;
char name[30];
char SUPER_S[30];
time_t t = time(NULL);
struct tm tm;
localtime_s(&tm, &t);
for (i = 0; i < 115; i++)
for (j=0;j<40;j++){
gotoxy(i, j); printf("&&&&&&&");
}
for (i = 0; i < 115; i++)
for (j = 0; j < 40; j++) {
gotoxy(i, j); printf(" ");
}
gotoxy(20, 20);
printf("점수 등록을 위한 사용자 이름을 입력하시오 : ");
gets_s( name);
fopen_s(&fp," record.txt", "a+"); //recorde.txt에 파일저장
if (fp == NULL)
printf("파일열기실패\n");
while(z){
fprintf(fp, "Player Name : %s\n", name);
fprintf(fp, "Player Date : %d-%d-%d %d:%d:%d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
fprintf(fp,"Player Super Score : %d\n", super_score);
fprintf(fp, "\n\n----------------------------------------------------------------------------\n");
z = false;
}
fclose(fp);
}