{"id":13340488,"url":"https://github.com/gunh0/PlayTetrisByC","last_synced_at":"2025-03-11T18:31:18.947Z","repository":{"id":127668893,"uuid":"164725630","full_name":"gunh0/PlayTetrisByC","owner":"gunh0","description":"🕹 Making of Tetris Game in C","archived":false,"fork":false,"pushed_at":"2021-07-12T03:49:57.000Z","size":31462,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-30T14:18:23.321Z","etag":null,"topics":["console-game","tetris-game","visual-studio"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gunh0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-08T20:16:58.000Z","updated_at":"2021-07-12T03:53:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"5e6c51ad-5adb-40e4-a96f-22a933411b19","html_url":"https://github.com/gunh0/PlayTetrisByC","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gunh0%2FPlayTetrisByC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gunh0%2FPlayTetrisByC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gunh0%2FPlayTetrisByC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gunh0%2FPlayTetrisByC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gunh0","download_url":"https://codeload.github.com/gunh0/PlayTetrisByC/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243090301,"owners_count":20234764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["console-game","tetris-game","visual-studio"],"created_at":"2024-07-29T19:23:00.790Z","updated_at":"2025-03-11T18:31:18.932Z","avatar_url":"https://github.com/gunh0.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PlayTetrisByC \n\n### Environment\n\n- Windows\n- Microsoft Visual Studio\n\n\u003cbr/\u003e\n\n### Screenshot\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/41619898/75116958-bb032600-56b0-11ea-940e-f90005f9ac2d.png\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/41619898/75116960-bdfe1680-56b0-11ea-8ff4-2eed68d785aa.png\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/41619898/75089586-a2eeb200-559d-11ea-8d8d-abd1a9af8dab.png\"/\u003e\n\u003c/p\u003e\n\n\u003e **Best Score by https://github.com/melli0505 (2019.10.28)**\n\n\u003cbr/\u003e\n\n### Code Detail\n\n```c++\n#define _CRT_NONSTDC_NO_WARNINGS    // 비표준 함수를 사용했을 때 에러 방지\n#define _CRT_SECURE_NO_WARNINGS     // scanf 보안 경고로 인한 컴파일 에러 방지\n#include\u003cstdio.h\u003e\n#include\u003cwindows.h\u003e\n#include\u003cconio.h\u003e\n#include\u003ctime.h\u003e\n#include\u003cstdlib.h\u003e\n\n#define LEFT 75 //좌로 이동    //키보드값들 \n#define RIGHT 77 //우로 이동 \n#define UP 72 //회전 \n#define DOWN 80 //soft drop\n#define SPACE 32 //hard drop\n#define p 112 //일시정지 \n#define P 80 //일시정지\n#define ESC 27 //게임종료 \n\n#define false 0\n#define true 1\n\n#define ACTIVE_BLOCK -2 // 게임판배열에 저장될 블록의 상태들 \n#define CEILLING -1     // 블록이 이동할 수 있는 공간은 0 또는 음의 정수료 표현 \n#define EMPTY 0         // 블록이 이동할 수 없는 공간은 양수로 표현 \n#define WALL 1\n#define INACTIVE_BLOCK 2 // 이동이 완료된 블록값 \n\n#define MAIN_X 11 //게임판 가로크기 \n#define MAIN_Y 23 //게임판 세로크기 \n#define MAIN_X_ADJ 3 //게임판 위치조정 \n#define MAIN_Y_ADJ 1 //게임판 위치조정 \n\n#define STATUS_X_ADJ MAIN_X_ADJ+MAIN_X+1 //게임정보표시 위치조정 \n\nint STATUS_Y_GOAL; //GOAL 정보표시위치Y 좌표 저장 \nint STATUS_Y_LEVEL; //LEVEL 정보표시위치Y 좌표 저장\nint STATUS_Y_SCORE; //SCORE 정보표시위치Y 좌표 저장\n\nint blocks[7][4][4][4] = {\n\t{ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },\n\t{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 } },\n\t{ { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },\n\t{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },\n\t{ { 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0 },\n\t{ 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0 } },\n\t{ { 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 },\n\t{ 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 } },\n\t{ { 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },\n\t{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0 } },\n\t{ { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 },\n\t{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },\n\t{ { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0 },\n\t{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 } }\n}; //블록모양 저장 4*4공간에 블록을 표현 blcoks[b_type][b_rotation][i][j]로 사용 \n\nint b_type; //블록 종류를 저장 \nint b_rotation; //블록 회전값 저장 \nint b_type_next; //다음 블록값 저장 \n\nint main_org[MAIN_Y][MAIN_X]; //게임판의 정보를 저장하는 배열 모니터에 표시후에 main_cpy로 복사됨 \nint main_cpy[MAIN_Y][MAIN_X]; //즉 maincpy는 게임판이 모니터에 표시되기 전의 정보를 가지고 있음 \n//main의 전체를 계속 모니터에 표시하지 않고(이렇게 하면 모니터가 깜빡거림) \n//main_cpy와 배열을 비교해서 값이 달라진 곳만 모니터에 고침 \nint bx, by; //이동중인 블록의 게임판상의 x,y좌표를 저장 \n\nint key; //키보드로 입력받은 키값을 저장 \n\nint speed; //게임진행속도 \nint level; //현재 level \nint level_goal; //다음레벨로 넘어가기 위한 목표점수 \nint cnt; //현재 레벨에서 제거한 줄 수를 저장 \nint score; //현재 점수 \nint last_score = 0; //마지막게임점수 \nint best_score = 0; //최고게임점수 \n\nint new_block_on = 0; //새로운 블럭이 필요함을 알리는 flag \nint crush_on = 0; //현재 이동중인 블록이 충돌상태인지 알려주는 flag \nint level_up_on = 0; //다음레벨로 진행(현재 레벨목표가 완료되었음을) 알리는 flag \nint space_key_on = 0; //hard drop상태임을 알려주는 flag \n\nvoid title(void); //게임시작화면 \nvoid reset(void); //게임판 초기화 \nvoid reset_main(void); //메인 게임판(main_org[][]를 초기화)\nvoid reset_main_cpy(void); //copy 게임판(main_cpy[][]를 초기화)\nvoid draw_map(void); //게임 전체 인터페이스를 표시 \nvoid draw_main(void); //게임판을 그림 \nvoid new_block(void); //새로운 블록을 하나 만듦 \nvoid check_key(void); //키보드로 키를 입력받음 \nvoid drop_block(void); //블록을 아래로 떨어트림 \nint check_crush(int bx, int by, int rotation); //bx, by위치에 rotation회전값을 같는 경우 충돌 판단 \nvoid move_block(int dir); //dir방향으로 블록을 움직임 \nvoid check_line(void); //줄이 가득찼는지를 판단하고 지움 \nvoid check_level_up(void); //레벨목표가 달성되었는지를 판단하고 levelup시킴 \nvoid check_game_over(void); //게임오버인지 판단하고 게임오버를 진행 \nvoid pause(void);//게임을 일시정지시킴 \n\nvoid gotoxy(int x, int y) { //gotoxy함수 \n\tCOORD pos = { 2 * x, y };\n\tSetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);\n}\n\ntypedef enum { NOCURSOR, SOLIDCURSOR, NORMALCURSOR } CURSOR_TYPE; //커서숨기는 함수에 사용되는 열거형 \nvoid setcursortype(CURSOR_TYPE c) { //커서숨기는 함수 \n\tCONSOLE_CURSOR_INFO CurInfo;\n\n\tswitch (c) {\n\tcase NOCURSOR:\n\t\tCurInfo.dwSize = 1;\n\t\tCurInfo.bVisible = FALSE;\n\t\tbreak;\n\tcase SOLIDCURSOR:\n\t\tCurInfo.dwSize = 100;\n\t\tCurInfo.bVisible = TRUE;\n\t\tbreak;\n\tcase NORMALCURSOR:\n\t\tCurInfo.dwSize = 20;\n\t\tCurInfo.bVisible = TRUE;\n\t\tbreak;\n\t}\n\tSetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), \u0026CurInfo);\n}\n\nint main() {\n\tint i;\n\n\tsrand((unsigned)time(NULL)); //난수표생성 \n\tsetcursortype(NOCURSOR); //커서 없앰 \n\ttitle(); //메인타이틀 호출 \n\treset(); //게임판 리셋 \n\n\twhile (1) {\n\t\tfor (i = 0; i \u003c 5; i++) { //블록이 한칸떨어지는동안 5번 키입력받을 수 있음 \n\t\t\tcheck_key(); //키입력확인 \n\t\t\tdraw_main(); //화면을 그림 \n\t\t\tSleep(speed); //게임속도조절 \n\t\t\tif (crush_on \u0026\u0026 check_crush(bx, by + 1, b_rotation) == false) Sleep(100);\n\t\t\t//블록이 충돌중인경우 추가로 이동및 회전할 시간을 갖음 \n\t\t\tif (space_key_on == 1) { //스페이스바를 누른경우(hard drop) 추가로 이동및 회전할수 없음 break; \n\t\t\t\tspace_key_on = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tdrop_block(); // 블록을 한칸 내림 \n\t\tcheck_level_up(); // 레벨업을 체크 \n\t\tcheck_game_over(); //게임오버를 체크 \n\t\tif (new_block_on == 1) new_block(); // 뉴 블럭 flag가 있는 경우 새로운 블럭 생성 \n\t}\n}\n\nvoid title(void) {\n\tint x = 5; //타이틀화면이 표시되는 x좌표 \n\tint y = 4; //타이틀화면이 표시되는 y좌표 \n\tint cnt; //타이틀 프레임을 세는 변수  \n\n\tgotoxy(x, y + 0); printf(\"■□□□■■■□□■■□□■■\"); Sleep(100);\n\tgotoxy(x, y + 1); printf(\"■■■□  ■□□    ■■□□■\"); Sleep(100);\n\tgotoxy(x, y + 2); printf(\"□□□■              □■  ■\"); Sleep(100);\n\tgotoxy(x, y + 3); printf(\"■■□■■  □  ■  □□■□□\"); Sleep(100);\n\tgotoxy(x, y + 4); printf(\"■■  ■□□□■■■□■■□□\"); Sleep(100);\n\tgotoxy(x, y + 5); printf(\"       Play Tetris By C\"); Sleep(100);\n\tgotoxy(x + 5, y + 2); printf(\"T E T R I S\"); Sleep(100);\n\tgotoxy(x, y + 7); printf(\"Please Enter Any Key to Start..\");\n\tgotoxy(x, y + 9); printf(\"  △   : Shift\");\n\tgotoxy(x, y + 10); printf(\"◁  ▷ : Left / Right\");\n\tgotoxy(x, y + 11); printf(\"  ▽   : Soft Drop\");\n\tgotoxy(x, y + 12); printf(\" SPACE : Hard Drop\");\n\tgotoxy(x, y + 13); printf(\"   P   : Pause\");\n\tgotoxy(x, y + 14); printf(\"  ESC  : Quit\");\n\tgotoxy(x, y + 16); printf(\"BONUS FOR HARD DROPS / COMBOS\");\n\n\tfor (cnt = 0;; cnt++) { //cnt를 1씩 증가시키면서 계속 반복    //하나도 안중요한 별 반짝이는 애니메이션효과 \n\t\tif (kbhit()) break; //키입력이 있으면 무한루프 종료 \n\t\tif (cnt % 200 == 0) { gotoxy(x + 4, y + 1); printf(\"★\"); }       //cnt가 200으로 나누어 떨어질때 별을 표시 \n\t\tif ((cnt % 200 - 100) == 0) { gotoxy(x + 4, y + 1); printf(\"  \"); } //위 카운트에서 100카운트 간격으로 별을 지움 \n\t\tif ((cnt % 350) == 0) { gotoxy(x + 13, y + 2); printf(\"☆\"); } //윗별과 같지만 시간차를 뒀음 \n\t\tif ((cnt % 350 - 100) == 0) { gotoxy(x + 13, y + 2); printf(\"  \"); }\n\t\tSleep(10); // 00.1초 딜레이  \n\t}\n\n\twhile (kbhit()) getch(); //버퍼에 기록된 키값을 버림 \n\n}\n\nvoid reset(void) {\n\n\tFILE* file = fopen(\"score.dat\", \"rt\"); // score.dat파일을 연결 \n\tif (file == 0) { best_score = 0; } //파일이 없으면 걍 최고점수에 0을 넣음 \n\telse {\n\t\tfscanf(file, \"%d\", \u0026best_score); // 파일이 열리면 최고점수를 불러옴 \n\t\tfclose(file); //파일 닫음 \n\t}\n\n\tlevel = 1; //각종변수 초기화 \n\tscore = 0;\n\tlevel_goal = 1000;\n\tkey = 0;\n\tcrush_on = 0;\n\tcnt = 0;\n\tspeed = 100;\n\n\tsystem(\"cls\"); //화면지움 \n\treset_main(); // main_org를 초기화 \n\tdraw_map(); // 게임화면을 그림\n\tdraw_main(); // 게임판을 그림 \n\n\tb_type_next = rand() % 7; //다음번에 나올 블록 종류를 랜덤하게 생성 \n\tnew_block(); //새로운 블록을 하나 만듦  \n\n}\n\nvoid reset_main(void) { //게임판을 초기화  \n\tint i, j;\n\n\tfor (i = 0; i \u003c MAIN_Y; i++) { // 게임판을 0으로 초기화  \n\t\tfor (j = 0; j \u003c MAIN_X; j++) {\n\t\t\tmain_org[i][j] = 0;\n\t\t\tmain_cpy[i][j] = 100;\n\t\t}\n\t}\n\tfor (j = 1; j \u003c MAIN_X; j++) { //y값이 3인 위치에 천장을 만듦 \n\t\tmain_org[3][j] = CEILLING;\n\t}\n\tfor (i = 1; i \u003c MAIN_Y - 1; i++) { //좌우 벽을 만듦  \n\t\tmain_org[i][0] = WALL;\n\t\tmain_org[i][MAIN_X - 1] = WALL;\n\t}\n\tfor (j = 0; j \u003c MAIN_X; j++) { //바닥벽을 만듦 \n\t\tmain_org[MAIN_Y - 1][j] = WALL;\n\t}\n}\n\nvoid reset_main_cpy(void) { //main_cpy를 초기화 \n\tint i, j;\n\n\tfor (i = 0; i \u003c MAIN_Y; i++) {         //게임판에 게임에 사용되지 않는 숫자를 넣음 \n\t\tfor (j = 0; j \u003c MAIN_X; j++) {  //이는 main_org와 같은 숫자가 없게 하기 위함 \n\t\t\tmain_cpy[i][j] = 100;\n\t\t}\n\t}\n}\n\nvoid draw_map(void) { //게임 상태 표시를 나타내는 함수  \n\tint y = 3;             // level, goal, score만 게임중에 값이 바뀔수 도 있음 그 y값을 따로 저장해둠 \n\t// 그래서 혹시 게임 상태 표시 위치가 바뀌어도 그 함수에서 안바꿔도 되게.. \n\tgotoxy(STATUS_X_ADJ, STATUS_Y_LEVEL = y); printf(\" LEVEL : %5d\", level);\n\tgotoxy(STATUS_X_ADJ, STATUS_Y_GOAL = y + 1); printf(\" GOAL  : %5d\", 10 - cnt);\n\tgotoxy(STATUS_X_ADJ, y + 2); printf(\"+-  N E X T  -+ \");\n\tgotoxy(STATUS_X_ADJ, y + 3); printf(\"|             | \");\n\tgotoxy(STATUS_X_ADJ, y + 4); printf(\"|             | \");\n\tgotoxy(STATUS_X_ADJ, y + 5); printf(\"|             | \");\n\tgotoxy(STATUS_X_ADJ, y + 6); printf(\"|             | \");\n\tgotoxy(STATUS_X_ADJ, y + 7); printf(\"+-- -  -  - --+ \");\n\tgotoxy(STATUS_X_ADJ, y + 8); printf(\" YOUR SCORE :\");\n\tgotoxy(STATUS_X_ADJ, STATUS_Y_SCORE = y + 9); printf(\"        %6d\", score);\n\tgotoxy(STATUS_X_ADJ, y + 10); printf(\" LAST SCORE :\");\n\tgotoxy(STATUS_X_ADJ, y + 11); printf(\"        %6d\", last_score);\n\tgotoxy(STATUS_X_ADJ, y + 12); printf(\" BEST SCORE :\");\n\tgotoxy(STATUS_X_ADJ, y + 13); printf(\"        %6d\", best_score);\n\tgotoxy(STATUS_X_ADJ, y + 15); printf(\"  △   : Shift        SPACE : Hard Drop\");\n\tgotoxy(STATUS_X_ADJ, y + 16); printf(\"◁  ▷ : Left / Right   P   : Pause\");\n\tgotoxy(STATUS_X_ADJ, y + 17); printf(\"  ▽   : Soft Drop     ESC  : Quit\");\n\tgotoxy(STATUS_X_ADJ, y + 20); printf(\"Play Tetris By C\");\n}\n\nvoid draw_main(void) { //게임판 그리는 함수 \n\tint i, j;\n\n\tfor (j = 1; j \u003c MAIN_X - 1; j++) { //천장은 계속 새로운블럭이 지나가서 지워지면 새로 그려줌 \n\t\tif (main_org[3][j] == EMPTY) main_org[3][j] = CEILLING;\n\t}\n\tfor (i = 0; i \u003c MAIN_Y; i++) {\n\t\tfor (j = 0; j \u003c MAIN_X; j++) {\n\t\t\tif (main_cpy[i][j] != main_org[i][j]) { //cpy랑 비교해서 값이 달라진 부분만 새로 그려줌.\n\t\t\t\t//이게 없으면 게임판전체를 계속 그려서 느려지고 반짝거림\n\t\t\t\tgotoxy(MAIN_X_ADJ + j, MAIN_Y_ADJ + i);\n\t\t\t\tswitch (main_org[i][j]) {\n\t\t\t\tcase EMPTY: //빈칸모양 \n\t\t\t\t\tprintf(\"  \");\n\t\t\t\t\tbreak;\n\t\t\t\tcase CEILLING: //천장모양 \n\t\t\t\t\tprintf(\". \");\n\t\t\t\t\tbreak;\n\t\t\t\tcase WALL: //벽모양 \n\t\t\t\t\tprintf(\"▩\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase INACTIVE_BLOCK: //굳은 블럭 모양  \n\t\t\t\t\tprintf(\"□\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase ACTIVE_BLOCK: //움직이고있는 블럭 모양  \n\t\t\t\t\tprintf(\"■\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor (i = 0; i \u003c MAIN_Y; i++) { //게임판을 그린 후 main_cpy에 복사  \n\t\tfor (j = 0; j \u003c MAIN_X; j++) {\n\t\t\tmain_cpy[i][j] = main_org[i][j];\n\t\t}\n\t}\n}\n\nvoid new_block(void) { //새로운 블록 생성  \n\tint i, j;\n\n\tbx = (MAIN_X / 2) - 1; //블록 생성 위치x좌표(게임판의 가운데) \n\tby = 0;  //블록 생성위치 y좌표(제일 위) \n\tb_type = b_type_next; //다음블럭값을 가져옴 \n\tb_type_next = rand() % 7; //다음 블럭을 만듦 \n\tb_rotation = 0;  //회전은 0번으로 가져옴 \n\n\tnew_block_on = 0; //new_block flag를 끔  \n\n\tfor (i = 0; i \u003c 4; i++) { //게임판 bx, by위치에 블럭생성  \n\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = ACTIVE_BLOCK;\n\t\t}\n\t}\n\tfor (i = 1; i \u003c 3; i++) { //게임상태표시에 다음에 나올블럭을 그림 \n\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\tif (blocks[b_type_next][0][i][j] == 1) {\n\t\t\t\tgotoxy(STATUS_X_ADJ + 2 + j, i + 6);\n\t\t\t\tprintf(\"■\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tgotoxy(STATUS_X_ADJ + 2 + j, i + 6);\n\t\t\t\tprintf(\"  \");\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid check_key(void) {\n\tkey = 0; //키값 초기화  \n\n\tif (kbhit()) { //키입력이 있는 경우  \n\t\tkey = getch(); //키값을 받음\n\t\tif (key == 224) { //방향키인경우 \n\t\t\tdo { key = getch(); } while (key == 224);//방향키지시값을 버림 \n\t\t\tswitch (key) {\n\t\t\tcase LEFT: //왼쪽키 눌렀을때  \n\t\t\t\tif (check_crush(bx - 1, by, b_rotation) == true) move_block(LEFT);\n\t\t\t\tbreak;                            //왼쪽으로 갈 수 있는지 체크 후 가능하면 이동\n\t\t\tcase RIGHT: //오른쪽 방향키 눌렀을때- 위와 동일하게 처리됨 \n\t\t\t\tif (check_crush(bx + 1, by, b_rotation) == true) move_block(RIGHT);\n\t\t\t\tbreak;\n\t\t\tcase DOWN: //아래쪽 방향키 눌렀을때-위와 동일하게 처리됨 \n\t\t\t\tif (check_crush(bx, by + 1, b_rotation) == true) move_block(DOWN);\n\t\t\t\tbreak;\n\t\t\tcase UP: //위쪽 방향키 눌렀을때 \n\t\t\t\tif (check_crush(bx, by, (b_rotation + 1) % 4) == true) move_block(UP);\n\t\t\t\t//회전할 수 있는지 체크 후 가능하면 회전\n\t\t\t\telse if (crush_on == 1 \u0026\u0026 check_crush(bx, by - 1, (b_rotation + 1) % 4) == true) move_block(100);\n\t\t\t}                    //바닥에 닿은 경우 위쪽으로 한칸띄워서 회전이 가능하면 그렇게 함(특수동작)\n\t\t}\n\t\telse { //방향키가 아닌경우 \n\t\t\tswitch (key) {\n\t\t\tcase SPACE: //스페이스키 눌렀을때 \n\t\t\t\tspace_key_on = 1; //스페이스키 flag를 띄움 \n\t\t\t\twhile (crush_on == 0) { //바닥에 닿을때까지 이동시킴 \n\t\t\t\t\tdrop_block();\n\t\t\t\t\tscore += level; // hard drop 보너스\n\t\t\t\t\tgotoxy(STATUS_X_ADJ, STATUS_Y_SCORE); printf(\"        %6d\", score); //점수 표시  \n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase P: //P(대문자) 눌렀을때 \n\t\t\tcase p: //p(소문자) 눌렀을때 \n\t\t\t\tpause(); //일시정지 \n\t\t\t\tbreak;\n\t\t\tcase ESC: //ESC눌렀을때 \n\t\t\t\tsystem(\"cls\"); //화면을 지우고 \n\t\t\t\texit(0); //게임종료 \n\t\t\t}\n\t\t}\n\t}\n\twhile (kbhit()) getch(); //키버퍼를 비움 \n}\n\nvoid drop_block(void) {\n\tint i, j;\n\n\tif (crush_on \u0026\u0026 check_crush(bx, by + 1, b_rotation) == true) crush_on = 0; //밑이 비어있으면 crush flag 끔 \n\tif (crush_on \u0026\u0026 check_crush(bx, by + 1, b_rotation) == false) { //밑이 비어있지않고 crush flag가 켜저있으면 \n\t\tfor (i = 0; i \u003c MAIN_Y; i++) { //현재 조작중인 블럭을 굳힘 \n\t\t\tfor (j = 0; j \u003c MAIN_X; j++) {\n\t\t\t\tif (main_org[i][j] == ACTIVE_BLOCK) main_org[i][j] = INACTIVE_BLOCK;\n\t\t\t}\n\t\t}\n\t\tcrush_on = 0; //flag를 끔 \n\t\tcheck_line(); //라인체크를 함 \n\t\tnew_block_on = 1; //새로운 블럭생성 flag를 켬    \n\t\treturn; //함수 종료 \n\t}\n\tif (check_crush(bx, by + 1, b_rotation) == true) move_block(DOWN); //밑이 비어있으면 밑으로 한칸 이동 \n\tif (check_crush(bx, by + 1, b_rotation) == false) crush_on++; //밑으로 이동이 안되면  crush flag를 켬\n}\n\nint check_crush(int bx, int by, int b_rotation) { //지정된 좌표와 회전값으로 충돌이 있는지 검사 \n\tint i, j;\n\n\tfor (i = 0; i \u003c 4; i++) {\n\t\tfor (j = 0; j \u003c 4; j++) { //지정된 위치의 게임판과 블럭모양을 비교해서 겹치면 false를 리턴 \n\t\t\tif (blocks[b_type][b_rotation][i][j] == 1 \u0026\u0026 main_org[by + i][bx + j] \u003e 0) return false;\n\t\t}\n\t}\n\treturn true; //하나도 안겹치면 true리턴 \n};\n\nvoid move_block(int dir) { //블록을 이동시킴 \n\tint i, j;\n\n\tswitch (dir) {\n\tcase LEFT: //왼쪽방향 \n\t\tfor (i = 0; i \u003c 4; i++) { //현재좌표의 블럭을 지움 \n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = EMPTY;\n\t\t\t}\n\t\t}\n\t\tfor (i = 0; i \u003c 4; i++) { //왼쪽으로 한칸가서 active block을 찍음 \n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j - 1] = ACTIVE_BLOCK;\n\t\t\t}\n\t\t}\n\t\tbx--; //좌표값 이동 \n\t\tbreak;\n\n\tcase RIGHT:    //오른쪽 방향. 왼쪽방향이랑 같은 원리로 동작 \n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = EMPTY;\n\t\t\t}\n\t\t}\n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j + 1] = ACTIVE_BLOCK;\n\t\t\t}\n\t\t}\n\t\tbx++;\n\t\tbreak;\n\n\tcase DOWN:    //아래쪽 방향. 왼쪽방향이랑 같은 원리로 동작\n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = EMPTY;\n\t\t\t}\n\t\t}\n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i + 1][bx + j] = ACTIVE_BLOCK;\n\t\t\t}\n\t\t}\n\t\tby++;\n\t\tbreak;\n\n\tcase UP: //키보드 위쪽 눌렀을때 회전시킴. \n\t\tfor (i = 0; i \u003c 4; i++) { //현재좌표의 블럭을 지움  \n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = EMPTY;\n\t\t\t}\n\t\t}\n\t\tb_rotation = (b_rotation + 1) % 4; //회전값을 1증가시킴(3에서 4가 되는 경우는 0으로 되돌림) \n\t\tfor (i = 0; i \u003c 4; i++) { //회전된 블록을 찍음 \n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = ACTIVE_BLOCK;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\tcase 100: //블록이 바닥, 혹은 다른 블록과 닿은 상태에서 한칸위로 올려 회전이 가능한 경우 \n\t\t//이를 동작시키는 특수동작 \n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i][bx + j] = EMPTY;\n\t\t\t}\n\t\t}\n\t\tb_rotation = (b_rotation + 1) % 4;\n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\t\tif (blocks[b_type][b_rotation][i][j] == 1) main_org[by + i - 1][bx + j] = ACTIVE_BLOCK;\n\t\t\t}\n\t\t}\n\t\tby--;\n\t\tbreak;\n\t}\n}\n\nvoid check_line(void) {\n\tint i, j, k, l;\n\n\tint    block_amount; //한줄의 블록갯수를 저장하는 변수 \n\tint combo = 0; //콤보갯수 저장하는 변수 지정및 초기화 \n\n\tfor (i = MAIN_Y - 2; i \u003e 3;) { //i=MAIN_Y-2 : 밑쪽벽의 윗칸부터,  i\u003e3 : 천장(3)아래까지 검사 \n\t\tblock_amount = 0; //블록갯수 저장 변수 초기화 \n\t\tfor (j = 1; j \u003c MAIN_X - 1; j++) { //벽과 벽사이의 블록갯루를 셈 \n\t\t\tif (main_org[i][j] \u003e 0) block_amount++;\n\t\t}\n\t\tif (block_amount == MAIN_X - 2) { //블록이 가득 찬 경우 \n\t\t\tif (level_up_on == 0) { //레벨업상태가 아닌 경우에(레벨업이 되면 자동 줄삭제가 있음) \n\t\t\t\tscore += 100 * level; //점수추가 \n\t\t\t\tcnt++; //지운 줄 갯수 카운트 증가 \n\t\t\t\tcombo++; //콤보수 증가  \n\t\t\t}\n\t\t\tfor (k = i; k \u003e 1; k--) { //윗줄을 한칸씩 모두 내림(윗줄이 천장이 아닌 경우에만) \n\t\t\t\tfor (l = 1; l \u003c MAIN_X - 1; l++) {\n\t\t\t\t\tif (main_org[k - 1][l] != CEILLING) main_org[k][l] = main_org[k - 1][l];\n\t\t\t\t\tif (main_org[k - 1][l] == CEILLING) main_org[k][l] = EMPTY;\n\t\t\t\t\t//윗줄이 천장인 경우에는 천장을 한칸 내리면 안되니까 빈칸을 넣음 \n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse i--;\n\t}\n\tif (combo) { //줄 삭제가 있는 경우 점수와 레벨 목표를 새로 표시함  \n\t\tif (combo \u003e 1) { //2콤보이상인 경우 경우 보너스및 메세지를 게임판에 띄웠다가 지움 \n\t\t\tgotoxy(MAIN_X_ADJ + (MAIN_X / 2) - 1, MAIN_Y_ADJ + by - 2); printf(\"%d COMBO!\", combo);\n\t\t\tSleep(500);\n\t\t\tscore += (combo * level * 100);\n\t\t\treset_main_cpy(); //텍스트를 지우기 위해 main_cpy을 초기화.\n\t\t\t//(main_cpy와 main_org가 전부 다르므로 다음번 draw()호출시 게임판 전체를 새로 그리게 됨) \n\t\t}\n\t\tgotoxy(STATUS_X_ADJ, STATUS_Y_GOAL); printf(\" GOAL  : %5d\", (cnt \u003c= 10) ? 10 - cnt : 0);\n\t\tgotoxy(STATUS_X_ADJ, STATUS_Y_SCORE); printf(\"        %6d\", score);\n\t}\n}\n\nvoid check_level_up(void) {\n\tint i, j;\n\n\tif (cnt \u003e= 10) { //레벨별로 10줄씩 없애야함. 10줄이상 없앤 경우 \n\t\tdraw_main();\n\t\tlevel_up_on = 1; //레벨업 flag를 띄움 \n\t\tlevel += 1; //레벨을 1 올림 \n\t\tcnt = 0; //지운 줄수 초기화   \n\n\t\tfor (i = 0; i \u003c 4; i++) {\n\t\t\tgotoxy(MAIN_X_ADJ + (MAIN_X / 2) - 3, MAIN_Y_ADJ + 4);\n\t\t\tprintf(\"             \");\n\t\t\tgotoxy(MAIN_X_ADJ + (MAIN_X / 2) - 2, MAIN_Y_ADJ + 6);\n\t\t\tprintf(\"             \");\n\t\t\tSleep(200);\n\n\t\t\tgotoxy(MAIN_X_ADJ + (MAIN_X / 2) - 3, MAIN_Y_ADJ + 4);\n\t\t\tprintf(\"☆LEVEL UP!☆\");\n\t\t\tgotoxy(MAIN_X_ADJ + (MAIN_X / 2) - 2, MAIN_Y_ADJ + 6);\n\t\t\tprintf(\"☆SPEED UP!☆\");\n\t\t\tSleep(200);\n\t\t}\n\t\treset_main_cpy(); //텍스트를 지우기 위해 main_cpy을 초기화.\n\t\t//(main_cpy와 main_org가 전부 다르므로 다음번 draw()호출시 게임판 전체를 새로 그리게 됨) \n\n\t\tfor (i = MAIN_Y - 2; i \u003e MAIN_Y - 2 - (level - 1); i--) { //레벨업보상으로 각 레벨-1의 수만큼 아랫쪽 줄을 지워줌 \n\t\t\tfor (j = 1; j \u003c MAIN_X - 1; j++) {\n\t\t\t\tmain_org[i][j] = INACTIVE_BLOCK; // 줄을 블록으로 모두 채우고 \n\t\t\t\tgotoxy(MAIN_X_ADJ + j, MAIN_Y_ADJ + i); // 별을 찍어줌.. 이뻐보이게 \n\t\t\t\tprintf(\"★\");\n\t\t\t\tSleep(20);\n\t\t\t}\n\t\t}\n\t\tSleep(100); //별찍은거 보여주기 위해 delay \n\t\tcheck_line(); //블록으로 모두 채운것 지우기\n\t\t//.check_line()함수 내부에서 level up flag가 켜져있는 경우 점수는 없음.         \n\t\tswitch (level) { //레벨별로 속도를 조절해줌. \n\t\tcase 2:\n\t\t\tspeed = 50;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tspeed = 25;\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tspeed = 10;\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tspeed = 5;\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\tspeed = 4;\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\tspeed = 3;\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tspeed = 2;\n\t\t\tbreak;\n\t\tcase 9:\n\t\t\tspeed = 1;\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\tspeed = 0;\n\t\t\tbreak;\n\t\t}\n\t\tlevel_up_on = 0; //레벨업 flag꺼줌\n\n\t\tgotoxy(STATUS_X_ADJ, STATUS_Y_LEVEL); printf(\" LEVEL : %5d\", level); //레벨표시 \n\t\tgotoxy(STATUS_X_ADJ, STATUS_Y_GOAL); printf(\" GOAL  : %5d\", 10 - cnt); // 레벨목표 표시 \n\n\t}\n}\n\nvoid check_game_over(void) {\n\tint i;\n\n\tint x = 5;\n\tint y = 5;\n\n\tfor (i = 1; i \u003c MAIN_X - 2; i++) {\n\t\tif (main_org[3][i] \u003e 0) { //천장(위에서 세번째 줄)에 inactive가 생성되면 게임 오버 \n\t\t\tgotoxy(x, y + 0); printf(\"▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤\"); //게임오버 메세지 \n\t\t\tgotoxy(x, y + 1); printf(\"▤                              ▤\");\n\t\t\tgotoxy(x, y + 2); printf(\"▤  +-----------------------+   ▤\");\n\t\t\tgotoxy(x, y + 3); printf(\"▤  |  G A M E  O V E R ... |   ▤\");\n\t\t\tgotoxy(x, y + 4); printf(\"▤  +-----------------------+   ▤\");\n\t\t\tgotoxy(x, y + 5); printf(\"▤   YOUR SCORE: %6d         ▤\", score);\n\t\t\tgotoxy(x, y + 6); printf(\"▤                              ▤\");\n\t\t\tgotoxy(x, y + 7); printf(\"▤  Press any key to restart..  ▤\");\n\t\t\tgotoxy(x, y + 8); printf(\"▤                              ▤\");\n\t\t\tgotoxy(x, y + 9); printf(\"▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤\");\n\t\t\tlast_score = score; //게임점수를 옮김 \n\n\t\t\tif (score \u003e best_score) { //최고기록 갱신시 \n\t\t\t\tFILE* file = fopen(\"score.dat\", \"wt\"); //score.dat에 점수 저장                \n\n\t\t\t\tgotoxy(x, y + 6); printf(\"▤  ★★★ BEST SCORE! ★★★   ▤  \");\n\n\t\t\t\tif (file == 0) { //파일 에러메세지  \n\t\t\t\t\tgotoxy(0, 0);\n\t\t\t\t\tprintf(\"FILE ERROR: SYSTEM CANNOT WRITE BEST SCORE ON \\\"SCORE.DAT\\\"\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfprintf(file, \"%d\", score);\n\t\t\t\t\tfclose(file);\n\t\t\t\t}\n\t\t\t}\n\t\t\tSleep(1000);\n\t\t\twhile (kbhit()) getch();\n\t\t\tkey = getch();\n\t\t\treset();\n\t\t}\n\t}\n}\n\nvoid pause(void) { //게임 일시정지 함수 \n\tint i, j;\n\n\tint x = 5;\n\tint y = 5;\n\n\tfor (i = 1; i \u003c MAIN_X - 2; i++) { //게임 일시정지 메세지 \n\t\tgotoxy(x, y + 0); printf(\"▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤\");\n\t\tgotoxy(x, y + 1); printf(\"▤                              ▤\");\n\t\tgotoxy(x, y + 2); printf(\"▤  +-----------------------+   ▤\");\n\t\tgotoxy(x, y + 3); printf(\"▤  |       P A U S E       |   ▤\");\n\t\tgotoxy(x, y + 4); printf(\"▤  +-----------------------+   ▤\");\n\t\tgotoxy(x, y + 5); printf(\"▤  Press any key to resume..   ▤\");\n\t\tgotoxy(x, y + 6); printf(\"▤                              ▤\");\n\t\tgotoxy(x, y + 7); printf(\"▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤\");\n\t}\n\tgetch(); //키입력시까지 대기 \n\n\tsystem(\"cls\"); //화면 지우고 새로 그림 \n\treset_main_cpy();\n\tdraw_main();\n\tdraw_map();\n\n\tfor (i = 1; i \u003c 3; i++) { // 다음블록 그림 \n\t\tfor (j = 0; j \u003c 4; j++) {\n\t\t\tif (blocks[b_type_next][0][i][j] == 1) {\n\t\t\t\tgotoxy(MAIN_X + MAIN_X_ADJ + 3 + j, i + 6);\n\t\t\t\tprintf(\"■\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tgotoxy(MAIN_X + MAIN_X_ADJ + 3 + j, i + 6);\n\t\t\t\tprintf(\"  \");\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n\u003cbr/\u003e\n\n### Year of Coding : 2015","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgunh0%2FPlayTetrisByC","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgunh0%2FPlayTetrisByC","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgunh0%2FPlayTetrisByC/lists"}