๐ฎ C์ธ์ด ํ ํธ๋ฆฌ์ค ํ๋ก์ ํธ
C์ธ์ด ํ ํธ๋ฆฌ์ค ์ฝ์ ๊ฒ์
๐ ๊ฐ๋ฐ ํ๊ฒฝ
โ ์ธ์ด(Language) : C
โ ๊ฐ๋ฐ ๋๊ตฌ(IDE) : Visual Studio
โ ์ด์์ฒด์ (OS) : Windows
์ค๊ณ ๋ฐ ๊ตฌ์กฐ
โ Main.c : ๊ฒ์ ๋ฃจํ ๋ฐ ์ ์ฒด ํ๋ฆ ์ ์ด
โ Console.c : ์ฝ์ ์ปค์ ์ ์ด ๋ฐ ์ถ๋ ฅ ๊ด๋ จ ํจ์
โ Data.c : ๋ธ๋ก ๋ฐ์ดํฐ, ์ ์ ์ฒ๋ฆฌ
โ Tetris.h : ์ ์ญ ์์ ๋ฐ ํจ์ ์ ์ธ
ํต์ฌ ๊ธฐ๋ฅ ๊ตฌํ
โ ์๋ ๋ธ๋ก ํ๊ฐ : ์ผ์ ์๊ฐ๋ง๋ค ๋ธ๋ก์ด ํ ์นธ์ฉ ๋ด๋ ค๊ฐ
if (check_time()) // ํ๋ฉด๊ฐฑ์ ์๊ฐ์ ๋๋ฌํ๋ฉด
key = DOWNKEY; // ์๋์ชฝ์ผ๋ก ์ทจ๊ธ
โ ์ข์ฐ ์ด๋ ํ์ : ๋ฐฉํฅํค๋ก ๋ธ๋ก์ ์์ ๋กญ๊ฒ ์ด๋ ๋ฐ ํ์ ๊ฐ๋ฅ
// ์
๋ ฅ์ ๋ฐ๋ผ ๋ธ๋ก์ ์ด๋ํ๊ฑฐ๋ ํ์
int process_event(int key)
{
int addy; // ๊ณต๋ฐฑํค ์ฒ๋ฆฌ ๋ณ์
int ret = 0; // ๋ฆฌํด๊ฐ
if (check_time()) // ํ๋ฉด๊ฐฑ์ ์๊ฐ์ ๋๋ฌํ๋ฉด
key = DOWNKEY; // ์๋์ชฝ์ผ๋ก ์ทจ๊ธ
switch (key)
{
case RIGHTKEY:
if (can_move(blockx + 1, blocky, current_block, block_rotation)) // ์ค๋ฅธ์ชฝ์ผ๋ก ๊ฐ ์ ์์ผ๋ฉด
{
delete_block(blockx, blocky, current_block, block_rotation); // ์ง์ฐ๊ณ
blockx += 1; // ์ฎ๊ธฐ๊ณ
draw_block(blockx, blocky, current_block, block_rotation); // ๋ค์ ๊ทธ๋ฆผ
}
break;
case LEFTKEY:
if (can_move(blockx - 1, blocky, current_block, block_rotation)) // ์ผ์ชฝ์ผ๋ก ๊ฐ ์ ์์ผ๋ฉด
{
delete_block(blockx, blocky, current_block, block_rotation); // ์ง์ฐ๊ณ
blockx -= 1; // ์ฎ๊ธฐ๊ณ
draw_block(blockx, blocky, current_block, block_rotation); // ๋ค์ ๊ทธ๋ฆผ
}
break;
case UPKEY:
if (can_move(blockx, blocky, current_block, (block_rotation + 1) % 4)) // ํ์
{
delete_block(blockx, blocky, current_block, block_rotation); // ์ง์ฐ๊ณ
block_rotation = (block_rotation + 1) % 4;
draw_block(blockx, blocky, current_block, block_rotation); // ๋ค์ ๊ทธ๋ฆผ
}
break;
case DOWNKEY:
if (can_move(blockx, blocky + 1, current_block, block_rotation)) // ์๋์ชฝ์ผ๋ก ๊ฐ ์ ์์ผ๋ฉด
{
delete_block(blockx, blocky, current_block, block_rotation); // ์ง์ฐ๊ณ
blocky = blocky + 1;
draw_block(blockx, blocky, current_block, block_rotation); // ๋ค์ ๊ทธ๋ฆผ
}
else // ๋ธ๋ก์ด ๋งจ๋ฐ์ด๋ฉด
{
set_block(blockx, blocky, current_block, block_rotation);
ret = 1; // 1 ๋ฆฌํด
}
break;
case SPACE:
addy = blocky;
do {
addy = addy + 1;
} while (can_move(blockx, addy, current_block, block_rotation));
delete_block(blockx, blocky, current_block, block_rotation);
blocky = addy - 1;
draw_block(blockx, blocky, current_block, block_rotation);
set_block(blockx, blocky, current_block, block_rotation);
ret = 1;
default:
break;
}
return ret;
}
โ ๋ผ์ธ ์ญ์ ๊ธฐ๋ฅ : ๊ฐ๋ ์ฐฌ ๋ผ์ธ์ ์๋์ผ๋ก ์ญ์ ํ๊ณ ์ ์๋ฅผ ๊ณ์ฐ
// ๊ฒ์ํ์์ ํ ์ค ๋ผ์ธ์ ์ฐพ์ ์ง์ฐ๊ณ , ์ ์ ๋ฐ ๋ ๋ฒจ์ ์
๋ฐ์ดํธ
int check_line()
{
int dlines = 0;
int checky, checkx; // ๊ฒ์ํ ์ขํ
int filled; // ํ ๋ผ์ธ์ ๋ธ๋ญ ์กฐ๊ฐ ์ฑ์์ง ์
checky = blocky + 4; // ๋ผ์ธ ๊ฒ์ฌ ์ด๊ธฐ๊ฐ
do
{
if (checky >= PLATEY) // ๋ผ์ธ์ด ๋ฐ๊นฅ์ด๋ฉด
checky -= 1; // ํ ์ค ์๋ฅผ ๊ฒ์ฌ
else
{
filled = 0; // ๋ผ์ธ ๋ด ๋ธ๋ญ ์กฐ๊ฐ ์ 0์ผ๋ก ์ด๊ธฐํ
for (checkx = 1; checkx < PLATEX - 1; checkx++)
if (game_plate[checky][checkx] == 1) // ํ์ค์ ๋ํ์ฌ ๋ธ๋ก ์กฐ๊ฐ ์๋ฅผ ์
filled += 1;
if (filled == PLATEX - 2) // ํ์ค ๋ค ์ฑ์ฐ๋ฉด
{
move_block(checky); // ์์ชฝ ๋ธ๋ก์ ์ฎ๊น
game_score += 10;
dlines += 1;
}
else
checky -= 1; // ์๋๋ฉด ์์ค ๊ฒ์ฌ
}
} while (checky >= blocky);
if (dlines > 0) // ์ง์์ง ๋ผ์ธ์ด ํ ๊ฐ ์ด์์ด๋ฉด
{
game_score += (dlines - 1) * 4;
deleted_lines += dlines;
game_level = deleted_lines / 4 + 1; // ๊ฒ์ ๋ ๋ฒจ ์ค์
if (game_level > 9)
game_level = 9;
block_delay = 500 - (50 * (game_level - 1)); // ํ๋ฉด๊ฐฑ์ ์๊ฐ ์กฐ์
print_score(game_score);
print_level(game_level);
if (game_high_score < game_score)
{
game_high_score = game_score;
}
print_high_score(game_high_score);
}
if ((checky <= 1) && (filled != 0))
return 1;
else
return 0;
}
โ ๊ฒ์ ์ค๋ฒ ํ์ : ๋ธ๋ก์ด ํ๋ฉด ์๋จ์ ๋๋ฌํ๋ฉด ๊ฒ์ ์ข ๋ฃ
if ((checky <= 1) && (filled != 0))
return 1;
else
return 0;
โ ์ต๊ณ ์ ์(High Score) : ์ ์ ์ ์ฅ ๋ฐ ์ฝ์ ํ๋ฉด์ ์ถ๋ ฅ
void print_high_score(int high_score)
{
char buf[10];
sprintf(buf, "%4d", high_score);
print_at(48, 20, buf);
}
โ NEXT ๋ธ๋ญ ํ์ : ๋ค์์ ๋์ฌ ๋ธ๋ญ์ ์ค๋ฅธ์ชฝ ํจ๋์ ์๊ฐ์ ์ผ๋ก ์ถ๋ ฅ
// ๋ค์์ ๋ธ๋ญ์ ์์ํด์ ์ถ๋ ฅ
void get_nextblock()
{
// ์๊ณ ๋ ๋ธ๋ก์ ๊ทธ๋ฆผ์๋ฅผ ์ง์ฐ๊ณ
textcolor(15); delete_block(20, 8, next_block, 0);
// ์๊ณ ๋ ๋ธ๋ก์ ๋๋ค์ผ๋ก ์ค์ ํ๊ณ ์ถ๋ ฅ
next_block = rand() % 18;
textcolor(15); draw_block(20, 8, next_block, 0);
}
// ๋ค์ ๋ธ๋ญ ์ถ๋ ฅ๋ ๊ณต๊ฐ
char* nextblock[9] = {
" NEXT Block ",
"โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ ",
"โ โ ",
"โ โ ",
"โ โ ",
"โ โ ",
"โ โ ",
"โ โ ",
"โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ "
};
// ๋ค์ ๋ธ๋ญ, ์ด๊ธฐํ๋ฉด, ์ ์ ์ถ๋ ฅ
void init_screen()
{
int n = 0;
for (n = 0; n < 9; n++)
{
textcolor(15); print_at(18 * 2, 5 + n, nextblock[n]); // ๋ค์ ๋ธ๋ก ์๊ณ
textcolor(15); print_at(28 * 2, 5 + n, gamemenu[n]); // ๊ฒ์ ๋ฉ๋ด
}
textcolor(15); print_at(18 * 2, 18, " LEVEL : ");
textcolor(15); print_at(18 * 2, 19, " SCORE : ");
textcolor(15); print_at(18 * 2, 20, "HIGH SCORE : ");
}
โ ๊ฒ์ ์๊ฐ ํ์ : ํ๋ ์ด ํ์ด๋จธ๋ฅผ ์ค์๊ฐ์ผ๋ก ์ฝ์์ ์ถ๋ ฅ
void myClock() {
int hour = 0, minute = 0, second = 0, i = 0;
while (1) {
if (state != GAMEOVER) {
second++;
if (second == 60) {
second = 0;
minute++;
}
if (minute == 60) {
minute = 0;
hour++;
}
if (hour == 24) {
hour = 0;
}
gotoxy(36, 0);
printf("%02d:%02d:%02d", hour, minute, second);
Sleep(1000);
for (i = 1; i <= minute; i++) {
if (game_score <= i * 100) {
textcolor(12);
print_at(8, 10, "โป GAME OVER โป");
state = GAMEOVER;
break;
}
}
}
else {
if (key == ENTER) {
hour = 0;
minute = 0;
second = 0;
}
}
}
}
HANDLE hClockThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)myClock, NULL, 0, NULL);
โ ๊ฒ์ ๋ ๋ฒจ ๋ฐ ์๋ ์กฐ์ : ์ ์ ๋๋ ๋ผ์ธ ์์ ๋ฐ๋ผ ์๋์ผ๋ก ์๋ ์ฆ๊ฐ
if (dlines > 0) // ์ง์์ง ๋ผ์ธ์ด ํ ๊ฐ ์ด์์ด๋ฉด
{
game_score += (dlines - 1) * 4; // ์ถ๊ฐ ์ ์
deleted_lines += dlines; // ์ง์์ง ๋ผ์ธ ์ ๋์
game_level = deleted_lines / 4 + 1; // ๋ ๋ฒจ ๊ณ์ฐ (4๋ผ์ธ๋ง๋ค 1๋ ๋ฒจ ์ฆ๊ฐ)
if (game_level > 9)
game_level = 9; // ์ต๋ ๋ ๋ฒจ ์ ํ
block_delay = 500 - (50 * (game_level - 1)); // ๋ธ๋ก ๋จ์ด์ง๋ ์๋ ์กฐ์
print_score(game_score); // ์ ์ ์ถ๋ ฅ
print_level(game_level); // ๋ ๋ฒจ ์ถ๋ ฅ
if (game_high_score < game_score)
{
game_high_score = game_score;
}
print_high_score(game_high_score); // ์ต๊ณ ์ ์ ์ถ๋ ฅ
}
โ ํ ์คํธ ์์ ์ ์ฉ : ๋ธ๋ญ๊ณผ UI ํ ์คํธ์ ์์์ ์ ํ ๊ฐ๋ ์ฑ ํฅ์
// ํ
์คํธ ์์์ ๋ณ๊ฒฝํ๋ ํจ์
// ์๋์ฐ์ฆ ํค๋ํ์ผ ์ฌ์ฉ
void textcolor(int color_number) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_number);
}
// ์์์ ๋ํ๋ด๋ ์ด๊ฑฐํ ๊ตฌ์กฐ์ฒด
typedef enum Color {
GRAY = 8,
WHITE = 15
} COLOR;
// ์์์ ์ ์งํ๋ฉด์ "โ "์ ์ถ๋ ฅํ๋ ํจ์
void colorRetention(int colorType) {
// ๋ง์ฝ colorType์ด 1์ด๋ฉด
if (colorType == 1) {
textcolor(GRAY); // ํ
์คํธ ์์์ ํ์(GRAY)์ผ๋ก ๋ณ๊ฒฝ
printf("โ "); // "โ " ์ถ๋ ฅ
textcolor(WHITE); // ํ
์คํธ ์์์ ํฐ์(WHITE)์ผ๋ก ๋ณ๊ฒฝ
}
}
โ ์ ํ ์๊ฐ : ์ ํ ์๊ฐ ์์ ๋ชฉํ ์ ์ ๋ฏธ๋ฌ ์ ๊ฒ์ ์ข ๋ฃ
for (i = 1; i <= minute; i++) {
if (game_score <= i * 100) { // ์ ํ ์๊ฐ(๋ถ)๋ง๋ค ๋ชฉํ ์ ์ ์ฒดํฌ
textcolor(12);
print_at(8, 10, "โป GAME OVER โป");
state = GAMEOVER; // ๊ฒ์ ์ข
๋ฃ ์ํ๋ก ๋ณ๊ฒฝ
break;
}
}
โ ๊ทธ๋ฆผ์ ๋ธ๋ญ : ๋ธ๋ญ์ด ๋จ์ด์ง ์์น๋ฅผ ๋ฏธ๋ฆฌ ๋ณด์ฌ์ฃผ์ด ์ฌ์ฉ์๊ฐ ์ฐฉ์ง ์์น๋ฅผ ํ๋จํ ์ ์์ต๋๋ค.
// ๋ธ๋ก ๊ทธ๋ฆฌ๊ธฐ
void draw_block(int sx, int sy, int btype, int rotation)
{
int bx, by;
for (by = 0; by < 4; by++) // ๋ธ๋ก๋ด๋ถ y์ถ
for (bx = 0; bx < 4; bx++) // ๋ธ๋ก๋ด๋ถ x์ถ
if (tet_block[btype][rotation][by][bx] == 1) // ๊ฐ์ด 1์ธ ์์น์
PUT_BS(2 * (sx + bx), sy + by); // ๊ฒ์ ๋ธ๋ก
// ๊ทธ๋ฆผ์ ๋ธ๋ก ๊ทธ๋ฆฌ๊ธฐ
if (sx != 20 || sy != 8) {
if (can_move(sx, sy + 1, btype, rotation)) {
shadow_blockx = sx; // ๊ทธ๋ฆผ์์ x์ขํ๋ ํ์ฌ ๋ธ๋ก์ x์ขํ์ ๋์ผํ๊ฒ ์ค์
shadow_blocky = sy;
while (can_move(shadow_blockx, shadow_blocky + 1, btype, rotation)) {
shadow_blocky++; // ๊ทธ๋ฆผ์๋ฅผ ์๋๋ก ์ด๋
}
// ๋ฉ๋ด ์ฐฝ ์์ญ์ ๋ฒ์ด๋๋์ง ํ์ธ ํ ๊ทธ๋ฆฌ๊ธฐ
for (by = 0; by < 4; by++)
for (bx = 0; bx < 4; bx++)
if (tet_block[btype][rotation][by][bx] == 1)
PUT_SS(2 * (shadow_blockx + bx), shadow_blocky + by);
}
}
}
// ๋ธ๋ก ์ง์ฐ๊ธฐ
void delete_block(int sx, int sy, int btype, int rotation)
{
int bx, by;
for (by = 0; by < 4; by++) // ๋ธ๋ก๋ด๋ถ y์ถ
for (bx = 0; bx < 4; bx++) // ๋ธ๋ก๋ด๋ถ x์ถ
if (tet_block[btype][rotation][by][bx] == 1) // ๊ฐ์ด 1์ธ ์์น์
print_at(2 * (sx + bx), sy + by, " "); // ๊ณต๋ฐฑ ์ถ๋ ฅ
// ๊ทธ๋ฆผ์ ๋ธ๋ญ ์ญ์
if (sx != 20 || sy != 8) {
shadow_blockx = sx; // ๊ทธ๋ฆผ์์ x์ขํ๋ ํ์ฌ ๋ธ๋ก์ x์ขํ์ ๋์ผํ๊ฒ ์ค์
shadow_blocky = sy;
while (can_move(shadow_blockx, shadow_blocky + 1, btype, rotation)) {
shadow_blocky++; // ๊ทธ๋ฆผ์๋ฅผ ์๋๋ก ์ด๋
}
for (by = 0; by < 4; by++)
for (bx = 0; bx < 4; bx++)
if (tet_block[btype][rotation][by][bx] == 1)
print_at(2 * (shadow_blockx + bx), shadow_blocky + by, " "); // ๋ธ๋ก์ ์ญ์ ํ๋ ํจ์ ํธ์ถ (์ ์ ํ ํจ์๋ช
์ผ๋ก ๋ณ๊ฒฝ ํ์)
}
}
๋๋ฒ๊น [๊ฒ์ ์๊ฐ ํ์ ์ ๋ฉ์ธ ๋ฃจํ ์ ์ง ์๋ฌ]
๊ฒ์ ๋ด ์๊ฐ์ ํ์ํ๋ ์ฝ๋๋ฅผ ์ถ๊ฐ ์ค์ ๊ฒ์ ์์์ ์ฝ์์ฐฝ์ด ๋ฉ์ถ๋ ์๋ฌ๊ฐ ๋ฐ์
์ ์ ๋ ์ค๋ ๋
๊ฒ์ ๋ด ์๊ฐ์ ํ์ํ๊ธฐ ์ํด myClock() ํจ์๋ฅผ ํธ์ถํ์ ๋, ํด๋น ํจ์ ๋ด๋ถ์ ๋ฌดํ ๋ฃจํ๊ฐ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ ์ ํด๋ฒ๋ฆผ

myClock() ํจ์๋ฅผ ๋ฉ์ธ ๋ฃจํ์ ๋์์ ์คํํ ์ ์๋๋ก, CreateThread()๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๋์ ์ค๋ ๋๋ก ์คํ๋๋๋ก ์์
์ด๋ฅผ ํตํด ๋ฉ์ธ ์ค๋ ๋๋ ๊ฒ์ ์งํ(์ ๋ ฅยท์ด๋ยทํ๋ฉด ๊ฐฑ์ )์ ๋ด๋นํ๊ณ , ๋ณด์กฐ ์ค๋ ๋๋ ๊ฒฝ๊ณผ ์๊ฐ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ธก์ ๋ฐ ์ถ๋ ฅํ๊ฒ ๋จ
์ ์์ ์ผ๋ก ์คํ๋๋ ์ค๋ ๋
์คํ ํ๋ฉด
์์ํ๋ฉด

๊ฒ์ ์ค ํ๋ฉด

๋๊ธ๋จ๊ธฐ๊ธฐ