리메이크 중/C,C++ 실습 중심

C(&C++) 실습 12. 테트리스 1

라이피 (Lypi) 2023. 1. 13. 19:19
반응형


출처 

soen.kr


 

 

#include "Turboc.h"

#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define ESC 27

#define BX 5
#define BY 1
#define BW 10
#define BH 20

void DrawScreen();
void DrawBoard();
bool ProcessKey();
void PrintBrick(bool show);
int GetAround(int x, int y, int b, int r);
bool MoveDown();
void TestFull();

struct Point {
	int x, y;
};

Point Shape[][4][4] = {
     { {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2}, {0,0,1,0,2,0,-1,0}, {0,0,0,1,0,-1,0,-2} },
     { {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1}, {0,0,1,0,0,1,1,1} },
     { {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1}, {0,0,-1,0,0,-1,1,-1}, {0,0,0,1,-1,0,-1,-1} },
     { {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1}, {0,0,-1,-1,0,-1,1,0}, {0,0,-1,0,-1,1,0,-1} },
     { {0,0,-1,0,1,0,-1,-1}, {0,0,0,-1,0,1,-1,1}, {0,0,-1,0,1,0,1,1}, {0,0,0,-1,0,1,1,-1} },
     { {0,0,1,0,-1,0,1,-1}, {0,0,0,1,0,-1,-1,-1}, {0,0,1,0,-1,0,-1,1}, {0,0,0,-1,0,1,1,1} },
     { {0,0,-1,0,1,0,0,1}, {0,0,0,-1,0,1,1,0}, {0,0,-1,0,1,0,0,-1}, {0,0,-1,0,0,-1,0,1} },
};

enum {EMPTY, BRICK, WALL};
const char* arTile[] = { ". ","■", "□" };

int board[BW + 2][BH + 2];
int nx, ny;
int brick, rot;

int main() {

    int nFrame, nStay;

    setcursortype(NOCURSOR);
    randomize();
    clrscr();

    for (int x = 0; x < BW + 2; x++) {
        for (int y = 0; y < BH + 2; y++) {
            board[x][y] = (y == 0 || y == BH + 1 || x == 0 || x == BW + 1) ? WALL : EMPTY;
        }
    }

    DrawScreen();
    nFrame = 20;

    while (true) {
        brick = random(sizeof(Shape) / sizeof(Shape[0]));
        nx = BW / 2;
        ny = 3;
        rot = 0;
        PrintBrick(true);

        if (GetAround(nx, ny, brick, rot) != EMPTY) break;
        nStay = nFrame;
        
        while (true) {
            if (--nStay == 0) {
                nStay = nFrame;
                if (MoveDown()) break;
            }
            if (ProcessKey()) break;
            delay(1000 / 20);
        }
    }

    clrscr();
    gotoxy(30, 12); puts(" G A M E   O V E R");
    setcursortype(NORMALCURSOR);
}

void DrawScreen()
{
    for (int x = 0; x < BW + 2; x++) {
        for (int y = 0; y < BH + 2; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[board[x][y]]);
        }
    }
    
    gotoxy(50, 3); puts("Tetris Ver 1.0");
    gotoxy(50, 5); puts("좌우:이동, 위:회전, 아래:내림");
    gotoxy(50, 6); puts("공백: 전부 내림");
}

void DrawBoard()
{
    for (int x = 1; x < BW + 1; x++) {
        for (int y = 1; y < BH + 1; y++) {
            gotoxy(BX + x * 2, BY + y);
            puts(arTile[board[x][y]]);
        }
    }
}

bool ProcessKey() 
{
    int trot;

    if (_kbhit()) {
        int ch = _getch();
        if (ch == 0xE0 || ch == 0) {
            ch = _getch();
            switch (ch) {
            case LEFT:
                if (GetAround(nx - 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx--;
                    PrintBrick(true);
                }
                break;

            case RIGHT:
                if (GetAround(nx + 1, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    nx++;
                    PrintBrick(true);
                }
                break;

            case UP:
                trot = (rot == 3 ? 0 : rot + 1);
                if (GetAround(nx, ny, brick, rot) == EMPTY) {
                    PrintBrick(false);
                    rot = trot;
                    PrintBrick(true);
                }
                break;

            case DOWN:
                if (MoveDown()) {
                    return true;
                }
                break;
            }
        } else {
            switch (ch) {
            case ' ':
                while (MoveDown() == false) { ; }
                return true;
            }
        }
    }

    return false;
}

void PrintBrick(bool Show) 
{
    for (int i = 0; i < 4; i++) {
        gotoxy(BX + (Shape[brick][rot][i].x + nx) * 2, BY + Shape[brick][rot][i].y + ny);
        puts(arTile[Show ? BRICK : EMPTY]);
    }
}

int GetAround(int x, int y, int b, int r) 
{
    int k = EMPTY;

    for (int i = 0; i < 4; i++) {
        k = max(k, board[x + Shape[b][r][i].x][y + Shape[b][r][i].y]);
    }

    return k;
}

bool MoveDown()
{
    if (GetAround(nx, ny + 1, brick, rot) != EMPTY) {
        TestFull();
        return true;
    }

    PrintBrick(false);
    ny++;
    PrintBrick(true);
    return false;
}

void TestFull() {
    for (int i = 0; i < 4; i++) {
        board[nx + Shape[brick][rot][i].x][ny + Shape[brick][rot][i].y] = BRICK;
    }

    int x, y;
    for (y = 1; y < BH + 1; y++) {
        for (x = 1; x < BW + 1; x++) {
            if (board[x][y] != BRICK) break;
        }
        if (x == BW + 1) {
            for (int ty = y; ty > 1; ty--) {
                for (x = 1; x < BW + 1; x++) {
                    board[x][ty] = board[x][ty - 1];
                }
            }
            DrawBoard();
            delay(200);
        }
    }
}

 

■ 이번 예제는 기능이 함수들로 좀 쪼개져 있어서 나은 편이다.

■ 테트리스는 누구나 아는 게임이라 재밌다.

반응형