콘솔 게임 맵 이동
이모지 링크
https://kr.piliapp.com/twitter-symbols/
https://www.unicode.org/emoji/charts/full-emoji-list.html
https://kr.piliapp.com/symbol/#graphic
1)
#include <stdio.h>
#define emoji_Size sizeof "🔚" // icon size == 5byte
#define movable 8
#define x_Blocks (movable + 2) // 이동 블럭 수 + 양쪽 벽 2개
#define x_Total (emoji_Size * x_Blocks) // x 축 전제 크기
int main(void)
{
char map[x_Total] = {"⬛🔚🔙🔚🔙🔚🔙🔚🔙⬛"};
printf("emoji size: %ld Byte\n", sizeof "🔚");
printf("x axis cnt : %d\n", x_Blocks);
printf("array size : %ld Byte\n", sizeof map);
printf("%s\n\n", map);
}
// icon size: 5Byte
// x axis cnt: 10
// array size: 50Byte
// ⬛🔚🔙🔚🔙🔚🔙🔚🔙⬛
2)
#include <stdio.h>
int main(void)
{
// 1차원 배열
char map1[10] = {"1 2 3 4 5"};
printf("%s\n", map1);
printf("%ld Byte\n\n", sizeof map1); // 9+1
// 2차원 배열
char map2[2][10] = {
"0 1 2 3 4",
"5 6 7 8 9"};
printf("%s\n", map2[0]);
printf("%s\n", map2[1]);
printf("%ld Byte\n\n", sizeof map2); // (9+1)*2
// 좌표 평면상의 x축, y축과 인덱스 값 간의 차이점 확인
// 아래 출력분을 중첩된 반복문으로 출력할 수 있으면, 콘솔 게임 맵 출력 완성
printf("%c %c %c %c %c\n", map2[0][0], map2[0][2], map2[0][4], map2[0][6], map2[0][8]);
printf("%c %c %c %c %c\n", map2[1][0], map2[1][2], map2[1][4], map2[1][6], map2[1][8]);
}
// 1 2 3 4 5
// 10 Byte
// 0 1 2 3 4
// 5 6 7 8 9
// 20 Byte
// 0 1 2 3 4
// 5 6 7 8 9
3)
#include <stdio.h>
int main(void)
{
/* Case 1. [↖방향] 좌표 0,0 시작 2차원 배열 계산이 편한경우 */
\
char map1[5][10] = {
"0 1 2 3 4",
"1 a b c d",
"2 e f g h",
"3 i j k l",
"4 m n o p"};
int maxRow = sizeof map1 / sizeof map1[0]; // [1 시작 정수 계산 사용]
int y_MaxIdx = maxRow - 1; // [0 시작 index 계산 사용] 행 마지막 인덱스
int block_sz = 2; // 열의 블록 한칸 사이즈(띄어쓰기 고려)
printf("2차원 맵 사이즈: %ld, 행 사이즈: %ld\n\n", sizeof map1, sizeof map1[0]);
// [step1] 키 입력
int x_Input = 4; // x 축으로 4칸
int y_Input = 3; // y 축으로 3칸
// [step2] 키 입력값이 유효하면, 계산후 할당
int _x = 0;
int _y = 0;
// [step3] 아이콘 사이즈 반영을 위한 공백 반영
_x = x_Input * block_sz; // block * 2
_y = y_Input;
printf("map1[%d][%d], 값: %c\n", _y, _x / block_sz, map1[_y][_x]);
/* Case 12. [↙방향] 좌표 0,4 시작 좌표 계산이 편한경우 */
char map2[5][10] = {
"4 m n o p",
"3 i j k l",
"2 e f g h",
"1 a b c d",
"* 1 2 3 4"};
_x = 0;
_y = 4;
_x = x_Input * block_sz; // block * 2
_y = y_MaxIdx - y_Input; //
printf("map2[%d][%d], 값: %c\n", _y, _x / block_sz, map2[_y][_x]);
}
4) 출력
#include <stdio.h>
int main(void)
{
/* Case 1. [↖방향] 좌표 0,0 시작 2차원 배열 계산이 편한경우 */
char map1[5][10] = {
"01234",
"1abcd",
"2efgh",
"3ijkl",
"4mnop"};
int rowSZ = sizeof map1[0];
int colSZ = sizeof map1 / rowSZ; // [1 시작 정수 계산 사용]
int y_MaxIdx = colSZ - 1; // [0 시작 index 계산 사용] 행 마지막 인덱스
int block_sz = 2; // 열의 블록 한칸 사이즈(띄어쓰기 고려)
printf("2차원 맵 사이즈: %ld, 행 사이즈: %d\n\n", sizeof map1, rowSZ);
// [1] 키 입력
int x_Input = 1; // x 축으로 x칸
int y_Input = 3; // y 축으로 y칸
// [2] 케릭터 위치 초기값
int _x = 0;
int _y = 0;
// [3] 키 입력값이 유효하면, 케릭터 좌표값 계산후 할당
_x = x_Input;
_y = y_Input;
// [4] 맵 출력 시, 배열에 공백이 없다면,
// 컬러 아이콘은 글자2.5~3개 정도로 표시되므로 중첩되어 깨짐. 3+양쪽 공백 1칸 출력시 추가해야 함
char level[5][5] = {"🤺", "🏇", "♖ ", "♕ ", "♔ "};
for (size_t i = 0; i < colSZ; i++)
{
for (size_t j = 0; j < rowSZ; j++)
{
if(i == _y && j == _x)
printf("%5s", level[1]);
else
printf("%3c", map1[i][j]);
}
printf("\n");
}
}
5) 콘솔 게임 만들기
1)키를 입력받고,
2)캐릭터 이모지의 위치를 변경하는 로직 동작 후,
3)이동된 결과를 출력하도록 구현하시오
(맵 모양 및 크기와 이모지는 개인 선택)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
int getch();
int main(void)
{
char map3[16][64] = {
"10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 ",
"10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 2 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 2 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 2 0 2 2 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 2 2 2 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 0 2 2 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 0 0 0 0 2 0 0 0 0 0 10 ",
"10 0 0 0 0 0 0 0 0 2 0 0 0 2 0 10 ",
"10 0 0 0 0 0 0 0 0 2 2 2 0 2 0 10 ",
"10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 ",
"10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 ",
"10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 "};
// 🟥🟧🟨🟩🟦🟫🟪⬛⬜🛡⚔🗡🔪🚬🧪🪓💍💰🔫💎⛲🦺♻🔰
// 🗻🌁 🚢🏄🐳🌊⛵🌌🎇🎆🌠🌴🌱🌿🍀🎍🎋🍃🐉🐲🦕🟩🌿🍀🐍🚧🌳🌲🦴🟨🦑
char emoji[11][5] = {"🟥", "🟧", "🟨", "🟩", "🟦", "🟫", "🟪", "⬛", "⬜", "🌑", "🗻"};
char emoji_items[15][5] = {"🔪", "🚬", "🧪", "🪓", "💍", "💰", "🔫", "💎", "🎴", "🦺", "🏹"};
char four[5] = "\0";
char level[5][5] = {"🤺", "🏇", "♖ ", "♕ ", "♔ "};
// player start point
int x = 4;
int y = 10;
char move = 0;
char arrow_list[8][5] = {"↖", "↟", "↗", "↞", "↠", "↙", "↡", "↘"};
char arrow = 0;
char temp_char[5] = "\0";
int emoji_num = 0;
int max_X = sizeof(map3[16]);
int max_Y = sizeof(map3) / sizeof(map3[16]);
for (;;)
{
printf(" ");
printf("\n");
printf("\n");
printf("q w e \n");
printf(" ↖ ↟↗ \n");
printf("a↞ ↠ d 플레이어(x,y) %d,%d\n", (x / 4), y);
printf(" ↙ ↡↘ 이동방향: %s %s\n", arrow_list[arrow], emoji[atoi(temp_char)]);
printf("z x c ");
printf(" 입력 키값 >> ");
printf("%c\n", move);
move = getch();
system("clear");
}
}
int getch()
{
int c;
struct termios oldattr, newattr;
tcgetattr(STDIN_FILENO, &oldattr); // 현재 터미널 설정 읽음
newattr = oldattr;
newattr.c_lflag &= ~(ICANON | ECHO); // CANONICAL과 ECHO 끔
newattr.c_cc[VMIN] = 1; // 최소 입력 문자 수를 1로 설정
newattr.c_cc[VTIME] = 0; // 최소 읽기 대기 시간을 0으로 설정
tcsetattr(STDIN_FILENO, TCSANOW, &newattr); // 터미널에 설정 입력
c = getchar(); // 키보드 입력 읽음
tcsetattr(STDIN_FILENO, TCSANOW, &oldattr); // 원래의 설정으로 복구
return c;
}
move = getch();
printf("%c\n", move);
if (move == 65 || move == 97) // ↞a
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 68 || move == 100) // d↠
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 'x' || move == 'X' || move == 's' || move == 'S') // x↡
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 87 || move == 119) // w↟
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 81 || move == 113) // ↖q
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 69 || move == 101) // e↗
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 90 || move == 122) // ↙z
{
// 케릭터 좌표 변경 로직
break;
}
else if (move == 67 || move == 99) // c↘
{
// 케릭터 좌표 변경 로직
break;
}
else
{
printf("이동할 수 없는 지역입니다.\n다시 입력해주세요");
break;
}
6) kbhit
#include <termios.h> // 터미널 I/O 속성 제어
#include <unistd.h> // STDIN_FILENO, usleep 등 POSIX 함수
#include <fcntl.h> // 파일 디스크립터 제어(fcntl)
#include <stdio.h> // getchar, ungetc, EOF
#include <stdio_ext.h> // __fpurge (GNU 확장)
/*-----------------------------------------------------------
1) getch()
- Windows의 _getch()와 비슷하게, 한 글자를 즉시 읽어 반환
- 내부에서 터미널을 ‘비차단·비에코·단문자’ 모드로 잠깐 변경
-----------------------------------------------------------*/
int getch(void)
{
int c; // 읽어 올 문자
struct termios oldattr, newattr;
tcgetattr(STDIN_FILENO, &oldattr); // 현재 터미널 속성 백업
newattr = oldattr; // 복사 후 수정
newattr.c_lflag &= ~(ICANON | ECHO); // Canonical(라인 버퍼)·Echo 해제
newattr.c_cc[VMIN] = 1; // 최소 1문자 입력 시 즉시 반환
newattr.c_cc[VTIME] = 0; // 대기 시간 0 (즉시)
tcsetattr(STDIN_FILENO, TCSANOW, &newattr); // 수정 상태 적용
c = getchar(); // **블로킹**: 문자 입력까지 대기
tcsetattr(STDIN_FILENO, TCSANOW, &oldattr); // 원상 복구
return c; // 읽은 문자 반환
}
/*-----------------------------------------------------------
2) kbhit()
- Windows의 _kbhit()처럼, 입력 버퍼에 문자가 *존재*하는지만 확인
- Non-blocking 모드로 getchar() 시도 → EOF 아니면 입력이 있음
-----------------------------------------------------------*/
int kbhit(void)
{
/* 참고용: sleep(1) = 1초, usleep(1 000 000) = 1초 (µs 단위) */
struct termios oldt, newt; // 터미널 속성
int ch; // getchar 결과
int oldf; // 원래 파일 플래그
/* 1) 터미널 속성 백업 후 Canonical·Echo 해제 (라인 버퍼 off) */
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
/* 2) STDIN을 Non-blocking 플래그(O_NONBLOCK)로 변경 */
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
/* 3) 실제로 문자 읽기 시도 ― 입력 없으면 EOF 즉시 반환 */
ch = getchar();
/* 4) 터미널 속성·파일 플래그 모두 원상 복구 */
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
/* 5) 문자 있으면 다시 버퍼에 넣고 1 리턴, 없으면 0 */
if (ch != EOF)
{
ungetc(ch, stdin); // 다음 getchar()가 동일 문자 읽도록 복원
return 1; // 입력 존재
}
return 0; // 입력 없음
}
/*-----------------------------------------------------------
3) getKey()
- kbhit()로 먼저 입력 유무 확인
- 있으면 getch()로 실제 문자 읽어 반환
- 없으면 0 반환 (호출 측에서 '키 없음'으로 간주)
-----------------------------------------------------------*/
char getKey(void)
{
__fpurge(stdin); // 표준 입력 버퍼 비우기 (GNU 확장)
// → 불필요하면 제거해도 무방
if (kbhit()) { // 입력이 존재한다면
return getch(); // 즉시 문자 한 개 읽어 반환
}
return 0; // 아무 입력도 없을 때
}