[TetrisManager 클래스의 Class Diagram]


테트리스의 전반적인 로직 부분을 담당하는 클래스인 TetrisManager 에 대해서 살펴볼 차례입니다. TetrisManager.h 와 TetrisManager.c 를 분석하겠습니다.


[TetrisManager.h]

#ifndef _BOARD_H
#define _BOARD_H

#include "Block.h"

enum GameStatus{
	PLAYING, END
};

#define BOARD_ROW_SIZE 20
#define BOARD_COL_SIZE 14

typedef struct _tetrisManager{
	char board[BOARD_ROW_SIZE][BOARD_COL_SIZE];
	Block block;
	int deletedLineCount;
	int speedLevel;
}TetrisManager;

void TetrisManager_Init(TetrisManager* tetrisManager, int speedLevel); 
int TetrisManager_CheckValidPosition(TetrisManager* tetrisManager, int direction);
void TetrisManager_ChangeBoardByDirection(TetrisManager* tetrisManager, int direction);
void TetrisManager_ChangeBoardByAuto(TetrisManager* tetrisManager);
void TetrisManager_ProcessDirectDown(TetrisManager* tetrisManager);
void TetrisManager_ProcessDeletingLines(TetrisManager* tetrisManager);
int TetrisManager_IsReachedToBottom(TetrisManager* tetrisManager);
int TetrisManager_ProcessReachedCase(TetrisManager* tetrisManager);
void TetrisManager_Sleep(TetrisManager* tetrisManager);
void TetrisManager_Print(TetrisManager* tetrisManager);

#endif


1 ~ 2, 31 라인

헤더파일을 중복 포함되게 하지 않기 위한 guard 입니다.


4 라인

본 헤더파일에서 필요한 헤더파일을 include 합니다.


6 ~ 8 라인

GameStatus 열거형 상수를 정의합니다. 이는 게임 상태에 대한 내용들이 있는데, PLAYING (게임을 끝내지 않고, 계속 진행함) 과 END (게임 종료) 가 정의되어 있습니다.


10 ~ 11 라인

테트리스판의 가로 행의 개수와, 세로 열의 개수를 매크로 상수로 정의합니다.


13 ~ 18 라인

TetrisManager 구조체를 정의합니다. 멤버로는, 2 차원 배열인 board (테트리스 판) 이 있고, block (현재, 다음 블럭) 이 정의되어 있습니다. 또, deletedLineCount (삭제한 줄 수) 와 speedLevel (블럭이 떨어지는 속도 레벨) 이 있습니다.


20 ~ 29 라인

TetrisManager.c 에서 정의될 함수의 선언부입니다.


[TetrisManager.c]

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "TetrisManager.h"
#include "Util.h"
#include "Constant.h"

#define INITIAL_SPEED 500
#define SPEED_LEVEL_OFFSET 100
#define LEVELP_UP_CONDITION 3
#define STATUS_POSITION_X_TO_PRINT 40
#define STATUS_POSITION_Y_TO_PRINT 6

static void _TetrisManager_ClearBoard(TetrisManager* tetrisManager);
static void _TetrisManager_ChangeBoardByStatus(TetrisManager* tetrisManager, int status);
static void _TetrisManager_UpSpeedLevel(TetrisManager* tetrisManager);
static void _TetrisManager_SearchLineIndexesToDelete(TetrisManager* tetrisManager, int* indexes, int* count);
static void _TetrisManager_DeleteLines(TetrisManager* tetrisManager, int* indexes, int count);

void TetrisManager_Init(TetrisManager* tetrisManager, int speedLevel){
	Block block;
	block.current = -1;
	memset(tetrisManager->board, 0, sizeof(char)* BOARD_ROW_SIZE * BOARD_COL_SIZE);
	_TetrisManager_ClearBoard(tetrisManager);
	tetrisManager->block = Block_Make(True, block);
	tetrisManager->deletedLineCount = 0;
	tetrisManager->speedLevel = speedLevel;
}

int TetrisManager_CheckValidPosition(TetrisManager* tetrisManager, int direction){
	Block temp = Block_Move(tetrisManager->block, direction);
	int i;
	for (i = 0; i < POSITIONS_SIZE; i++){
		int x = Block_GetPositions(temp)[i].x;
		int y = Block_GetPositions(temp)[i].y;
		if (tetrisManager->board[x][y] != EMPTY && tetrisManager->board[x][y] != MOVING_BLOCK){
			return tetrisManager->board[x][y];
		}
	}
	return EMPTY;
}

void TetrisManager_ChangeBoardByDirection(TetrisManager* tetrisManager, int direction){
	int tempDirection = DOWN;
	int tempCheckResult = EMPTY;
	_TetrisManager_ClearBoard(tetrisManager);
	int checkResult = TetrisManager_CheckValidPosition(tetrisManager, direction);
	if (checkResult == EMPTY){
		tetrisManager->block = Block_Move(tetrisManager->block, direction);
	}
	else{
		if (direction == UP){
			switch (checkResult){
			case TOP_WALL:
				tempDirection = DOWN;
				tempCheckResult = TOP_WALL;
				break;
			case RIGHT_WALL:
				tempDirection = LEFT;
				tempCheckResult = RIGHT_WALL;
				break;
			case LEFT_WALL:
				tempDirection = RIGHT;
				tempCheckResult = LEFT_WALL;
				break;
			}
			do{
				tetrisManager->block = Block_Move(tetrisManager->block, tempDirection);
			} while (TetrisManager_CheckValidPosition(tetrisManager, direction) == tempCheckResult);
			tetrisManager->block = Block_Move(tetrisManager->block, direction);
		}
		else{
			if (direction == RIGHT && checkResult == RIGHT_WALL ||
				direction == LEFT && checkResult == LEFT_WALL || 
				direction == RIGHT && checkResult == FIXED_BLOCK ||
				direction == LEFT && checkResult == FIXED_BLOCK){
				TetrisManager_Sleep(tetrisManager);
				tetrisManager->block = Block_Move(tetrisManager->block, DOWN);
			}
		}
	}
	_TetrisManager_ChangeBoardByStatus(tetrisManager, MOVING_BLOCK);
}

void TetrisManager_ChangeBoardByAuto(TetrisManager* tetrisManager){
	TetrisManager_ChangeBoardByDirection(tetrisManager, DOWN);
}

void TetrisManager_ProcessDirectDown(TetrisManager* tetrisManager){
	while (!TetrisManager_IsReachedToBottom(tetrisManager)){
		TetrisManager_ChangeBoardByDirection(tetrisManager, DOWN);
	}
}

void TetrisManager_ProcessDeletingLines(TetrisManager* tetrisManager){
	int indexes[BOARD_ROW_SIZE];
	int count;
	int i;
	_TetrisManager_SearchLineIndexesToDelete(tetrisManager, indexes, &count);
	if (count > 0){
		_TetrisManager_DeleteLines(tetrisManager, indexes, count);
		for (i = tetrisManager->speedLevel; i <= tetrisManager->deletedLineCount / LEVELP_UP_CONDITION; i++){
			_TetrisManager_UpSpeedLevel(tetrisManager);
		}
	}
}

int TetrisManager_IsReachedToBottom(TetrisManager* tetrisManager){
	int i;
	for (i = 0; i < POSITIONS_SIZE; i++){
		int x = Block_GetPositions(tetrisManager->block)[i].x;
		int y = Block_GetPositions(tetrisManager->block)[i].y;
		if (tetrisManager->board[x + 1][y] != EMPTY && tetrisManager->board[x + 1][y] != MOVING_BLOCK){
			return True;
		}
	}
	return False;
}

int TetrisManager_ProcessReachedCase(TetrisManager* tetrisManager){
	_TetrisManager_ChangeBoardByStatus(tetrisManager, FIXED_BLOCK);
	tetrisManager->block = Block_Make(False, tetrisManager->block);
	if (TetrisManager_IsReachedToBottom(tetrisManager)){
		return END;
	}
	else{
		return PLAYING;
	}
}

void TetrisManager_Sleep(TetrisManager* tetrisManager){
	int i;
	DWORD milliSecond = INITIAL_SPEED;
	for (i = MIN_SPEED_LEVEL; i < tetrisManager->speedLevel; i++){
		if (i < MAX_SPEED_LEVEL / 2){
			milliSecond -= SPEED_LEVEL_OFFSET;
		}
		else{
			milliSecond -= (SPEED_LEVEL_OFFSET / 5);
		}
	}
	Sleep(milliSecond);
}

void TetrisManager_Print(TetrisManager* tetrisManager){
	int i;
	int j;
	CursorUtil_GotoXY(0, 0);
	for (i = 0; i < BOARD_ROW_SIZE; i++){
		for (j = 0; j < BOARD_COL_SIZE; j++){
			switch (tetrisManager->board[i][j]){
			case LEFT_TOP_EDGE:
				printf("┎");
				break;
			case RIGHT_TOP_EDGE:
				printf("┒");
				break;
			case LEFT_BOTTOM_EDGE:
				printf("┖");
				break;
			case RIGHT_BOTTOM_EDGE:
				printf("┚");
				break;
			case EMPTY:
				printf("  ");
				break;
			case MOVING_BLOCK:
				printf("■");
				break;
			case FIXED_BLOCK:
				printf("▧");
				break;
			case LEFT_WALL:
			case RIGHT_WALL:
				printf("|");
				break;
			case TOP_WALL:
			case BOTTOM_WALL:
				printf("―");
				break;
			}
		}
		printf("\n");
	}
	CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT);
	printf("***** Tetris *****\n");
	CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 1);
	printf("Current speed level : %d level\n", tetrisManager->speedLevel);
	CursorUtil_GotoXY(STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 2);
	printf("Deleted lines : %d lines", tetrisManager->deletedLineCount);
	Block_PrintNext(tetrisManager->block, STATUS_POSITION_X_TO_PRINT, STATUS_POSITION_Y_TO_PRINT + 4);
	CursorUtil_Hide();
}

static void _TetrisManager_ClearBoard(TetrisManager* tetrisManager){
	int i;
	int j;
	for (i = 0; i < BOARD_ROW_SIZE; i++){
		tetrisManager->board[i][0] = LEFT_WALL;
		tetrisManager->board[i][BOARD_COL_SIZE - 1] = RIGHT_WALL;
	}
	for (i = 0; i < BOARD_COL_SIZE; i++){
		tetrisManager->board[0][i] = TOP_WALL;
		tetrisManager->board[BOARD_ROW_SIZE - 1][i] = BOTTOM_WALL;
	}
	for (i = 1; i < BOARD_ROW_SIZE - 1; i++){
		for (j = 1; j < BOARD_COL_SIZE - 1; j++){
			if (tetrisManager->board[i][j] != FIXED_BLOCK){
				tetrisManager->board[i][j] = EMPTY;
			}
		}
	}
	tetrisManager->board[0][0] = LEFT_TOP_EDGE;
	tetrisManager->board[0][BOARD_COL_SIZE - 1] = RIGHT_TOP_EDGE;
	tetrisManager->board[BOARD_ROW_SIZE - 1][0] = LEFT_BOTTOM_EDGE;
	tetrisManager->board[BOARD_ROW_SIZE - 1][BOARD_COL_SIZE - 1] = RIGHT_BOTTOM_EDGE;
}

static void _TetrisManager_ChangeBoardByStatus(TetrisManager* tetrisManager, int status){
	int i;
	for (i = 0; i < POSITIONS_SIZE; i++){
		int x = Block_GetPositions(tetrisManager->block)[i].x;
		int y = Block_GetPositions(tetrisManager->block)[i].y;
		tetrisManager->board[x][y] = status;
	}
}

static void _TetrisManager_UpSpeedLevel(TetrisManager* tetrisManager){
	if (tetrisManager->speedLevel < MAX_SPEED_LEVEL){
		tetrisManager->speedLevel++;
	}
}

static void _TetrisManager_SearchLineIndexesToDelete(TetrisManager* tetrisManager, int* indexes, int* count){
	int i;
	int j;
	int toDelete;
	memset(indexes, -1, sizeof(int)* (BOARD_ROW_SIZE - 2));
	*count = 0;
	for (i = 1; i < BOARD_ROW_SIZE - 1; i++){
		toDelete = True;
		for (j = 1; j < BOARD_COL_SIZE - 1; j++){
			if (tetrisManager->board[i][j] != FIXED_BLOCK){
				toDelete = False;
				break;
			}
		}
		if (toDelete){
			indexes[(*count)++] = i;
		}
	}
}

static void _TetrisManager_DeleteLines(TetrisManager* tetrisManager, int* indexes, int count){
	int i;
	int j;
	int k = BOARD_ROW_SIZE - 2;
	int toDelete;
	char temp[BOARD_ROW_SIZE][BOARD_COL_SIZE] = { EMPTY };
	for (i = BOARD_ROW_SIZE - 2; i > 0; i--){
		toDelete = False;
		for (j = 0; j < BOARD_COL_SIZE; j++){
			if (i == indexes[j]){
				toDelete = True;
				break;
			}
		}
		if (!toDelete){
			for (j = 0; j < BOARD_COL_SIZE; j++){
				temp[k][j] = tetrisManager->board[i][j];
			}
			k--;
		}
	}
	for (i = 1; i < BOARD_ROW_SIZE - 1; i++){
		for (j = 1; j < BOARD_COL_SIZE - 1; j++){
			tetrisManager->board[i][j] = temp[i][j];
		}
	}
	tetrisManager->deletedLineCount += count;
}


1 ~ 6 라인

필요한 헤더파일들을 include 합니다.


8 라인

초기 시작 스피드를 매크로 상수로 정의합니다.


9 라인

속도 레벨이 하나씩 증가할수록 벌어질 offset 을 매크로 상수로 정의합니다.


10 라인

라인을 몇 줄 지워야 속도 레벨이 1 증가하는지 (3 줄 삭제시 1 레벨 증가) 매크로 상수로 정의합니다.


11 ~ 12 라인

게임의 전반적인 상태를 출력할 위치의 좌표 (x, y) 를 매크로 상수로 정의합니다.


14 ~ 18 라인

현재 소스 파일 내부에서만 사용될 static 함수들의 선언부입니다.


20 라인

TetrisManager_Init 함수의 정의부입니다. 매개변수로 tetrisManager 와 speedLevel (사용자가 입력한 속도 레벨) 이 넘어옵니다. 이 함수는, Tetris 가 시작되면 처음 불리며, tetrisManager 의 멤버 변수들을 초기화 하는 역할을 합니다.


21 ~ 22 라인

Block 을 하나 생성하고, current 를 -1 로 초기화합니다. (아직 현재 블럭을 안 설정한 상태라서)


23 라인

memset 함수를 호출하여 tetrisManager 의 board 를 0 으로 초기화합니다. 

(변수 or 배열을 특정 값으로 한번에 초기화하기 참고)

http://kkikkodev.tistory.com/50


24 라인

_TetrisManager_ClearBoard 함수를 호출하여 tetrisManager 의 board 를 초기 상태를 설정합니다. (외부 벽과 같은)


25 라인

Block_Make 함수를 처음 호출하여 블럭을 생성하여 tetrisManager->block 에 저장합니다.


26 ~ 27 라인

tetrisManager 의 deletedLineCount 를 0 으로 speedLevel 을 사용자로부터 입력 받은 speedLevel 로 초기화합니다.


30 라인

TetrisManager_CheckValidPosition 함수의 정의부입니다. 매개변수로 tetrisManager 와 direction (방향) 을 전달받습니다. 이 함수는 전달받은 방향으로 block 을 임시로 이동 or 회전시켜보고 그 블럭 상태가 유효한지 아닌지를 반환합니다.


31 라인

tetrisManager->block 과 direction 을 매개변수로 넘기면서 Block_Move 를 호출하여 얻은 block 값을 임시 temp 에 저장합니다. 


33 ~ 40 라인

temp 의 4 개의 상자의 x, y 좌표를 각각 얻어와서 그 좌표에 해당하는 tetrisManager->board 가 EMPTY (빈 곳) 가 아니고, MOVING_BLOCK (움직이는 현재 블럭) 도 아닌 경우에는 그 상태를 반환하고 (유효하지 않다는 의미), 모두 이 두 가지 경우에만 해당되면, EMPTY 를 반환합니다. (유효하다는 의미)


43 라인

TetrisManager_ChangeBoardByDirection 함수의 정의부 입니다. 매개변수들로는 tetrisManager 와 direction (방향) 을 전달받고 있습니다. 이 함수는 방향에 해당하는 처리에 대해서 블럭을 이동 혹은 회전시키고, 그에 따른 테트리스 판의 상태도 변경하는 작업을 합니다.


44 ~ 45 라인

회전시에 벽에 부딪혀 유효하지 않은 상태가 되었을 때도, 한 칸 밀려 나오면서 회전은 가능해야 하기 때문에, 이를 위한 임시 방향과 임시 유효 상태 체크 결과 변수를 선언합니다.


46 라인

처리를 하기 전에 먼저, _TetrisManager_ClearBoard 함수를 호출하여 테트리스 판의 상태들을 정리합니다.


47 라인

TetrisManager_CheckValidPosition 함수를 호출하여 해당 direction 에 해당하는 블럭의 다음 위치가 유효한지를 구하여 checkResult 에 저장합니다.


48 ~ 50 라인

만약 그 다음 위치가 유효하다면, Block_Move 함수를 호출하여 실제로 블럭을 direction 으로 이동 혹은 회전합니다.


52 ~ 70 라인

checkResult 가 유효하지 않은 경우의 처리입니다. 회전을 제외한 왼쪽, 오른쪽, 아래쪽으로의 이동은 움직이면 안되지만, 회전의 경우에는 벽을 만나더라도, 회전을 하면서 한 칸 밀려나와야 합니다. 따라서, checkResult 의 결과를 토대로 TOP_WALL 이면 tempDirection 을 아래로, RIGHT_WALL 이면, tempDirection 을 왼쪽으로, LEFT_WALL 이면 tempDirection 을 오른쪽으로 지정한 뒤, Block_Move 함수에 tempDirection 을 넘기면서 block 을 벽의 반대 방향으로 밀려 나오게 합니다. (회전이 가능할 정도로) 그 다음에 실제로 direction 을 넘기면서 Block_Move 를 호출하여 블럭을 회전시킵니다. 


즉, 쉽게 말하면, 회전의 경우에는, 벽을 만나더라도 회전이 가능해야 하기 때문에, 벽의 반대쪽으로 밀려 나와서, 회전을 해야 한다는 것입니다.


72 ~ 79 라인

checkResult 가 유효하지 않은 경우이지만, 회전이 아닌 경우의 처리입니다. 방향은 오른쪽인데, 오른쪽 벽 혹은 굳어진 블럭에 막혀 있거나, 방향은 왼쪽인데 왼쪽 벽 혹은 굳어진 블럭에 막혀 있는 경우에는, 해당 방향으로 이동은 못하되, 밑으로 일정 시간 지난 후에 자동으로 내려와야 하기 때문에, TetrisManager_Sleep 함수를 호출하여 지연시킨 뒤, Block_Move 함수를 호출하면서 DOWN 방향을 넘겨 블럭을 자동으로 한 칸 내려오게 합니다. (즉, 이동 못하게 되었을 때, 가만히 그 위치에 머물러 있지 않도록 방지하기 위함입니다.)


82 라인

_TetrisManager_ChangeBoardByStatus 함수를 호출하면서, MOVING_BLOCK 을 넘겨서 tetrisManager 의 board 에서 새로 바뀐 블럭의 위치를 재설정합니다.


85 라인

TetrisManager_ChangeBoardByAuto 함수의 정의부입니다. 매개변수로 tetrisManager 를 받아서 자동으로 블럭을 한 칸 내려가게 하는 역할을 합니다.


86 라인

TetrisManager_ChangeBoardByDirection 함수에 DOWN 을 매개변수로 넘겨서 한 칸 밑으로 블럭을 내려가게 합니다.


89 라인

TetrisManager_ProcessDirectDown 함수의 정의부입니다. 매개변수로 tetrisManager 를 받아서 스페이스바를 눌렀을 시 처리 (블럭을 내려갈 수 있을 때까지 한꺼번에 내리기) 를 합니다.


90 ~ 91 라인

TetrisManager_IsReachedToBottom 함수를 호출하여 블럭이 더 이상 밑으로 이동할 수 있는지 체크를 해, 이동 가능하면, 계속해서, TetrisManager_ChangeBoardByDirection 함수를 호출하면서, 매개변수로 DOWN 을 넘겨 밑으로 블럭을 한 칸씩 내립니다. 즉, 밑으로 내릴 수 있을 때까지 계속해서 블럭을 밑으로 내리는 것입니다.


95 라인

TetrisManger_ProcessDeletingLines 함수의 정의부입니다. 매개변수로 tetrisManger 를 받아서, 삭제할 라인을 찾아서 삭제하고 테트리스 판을 갱신하는 역할을 합니다.


96 ~ 97 라인

삭제할 라인의 위치를 저장할 정수 배열과 개수를 선언합니다.


99 라인

_TetrisManager_SearchLineIndexesToDelete 함수를 호출하여, 삭제할 라인의 위치를 찾아서 indexes 배열에 저장하고, count 에는 그 라인의 총 수를 저장합니다.


100 ~ 105 라인

만약, 삭제할 줄 수가 있다면, _TetrisManager_DeleteLines 함수를 호출하여 해당하는 위치의 라인들을 삭제합니다. 그리고, 지운 줄의 총 수가 3 의 배수가 되면, _TetrisManager_UpSpeedLevel 함수를 호출하여 속도 레벨을 1 증가 시킵니다.


108 라인

TetrisManager_IsReachedToBottom 함수의 정의부입니다. 매개변수로 tetrisManager 를 받아서, 현재 이동중인 블럭이 밑으로 이동할 수 있는지 체크하여 그 결과를 참 / 거짓으로 반환하는 역할을 합니다.


110 ~ 117 라인

현재 이동중인 block 의 4 개의 상자의 좌표를 받아와서 그 좌표의 바로 밑이 EMPTY 가 아니고, MOVING_BLOCK 이 아니면 True (밑으로 더 이상 이동할 수 없다는 의미) 를 반환하고, 이것이 아니면 False (밑에 블럭이 닿지 않았음을 의미) 를 반환합니다.


120 라인

TetrisManger_ProcessReachedCase 함수의 정의부입니다. 이 함수에서는 블럭이 밑에 닿았을 때 (아래 벽 혹은 굳어진 블럭에 닿았을 때) 현재 이동중인 블럭을 굳어지게 하고, 새 블럭을 생성하는 등의 처리를 합니다.


121 라인

_TetrisManager_ChangeBoardByStatus 함수를 호춣하며 FIXED_BLOCK 매개변수를 넘겨서 현재 블럭에 해당하는 위치를 테트리스판에서 FIXED_BLOCK 으로 변경합니다.


122 라인

Block_Make 함수를 호출하여 (매개변수로 False 를 넘기는 이유는, 처음 불리는 것이 아닌 2 번째 이후부터 불리는 것이라는 것을 구분해주기 위함입니다.) 새 블럭을 생성합니다. 


123 ~ 128 라인

TetrisManager_IsReachedToBottom 함수를 호출하여 새로 생성한 블럭이 더 이상 밑으로 갈 수 있는지 체크를 하여 갈 수 없으면 END (게임 종료) 를 반환하고, 갈 수 있으면 PLAYING (게임 계속 진행) 을 반환합니다.


131 라인

TetrisManager_Sleep 함수의 정의부입니다. 매개변수로 tetrisManager 를 전달받아서, 속도 레벨에 해당하는 만큼 프로그램을 지연시키는 역할을 합니다.


133 ~ 141 라인

milliSecond 변수에 INITIAL_SPEED 를 넣고, 최소 속도 레벨부터 현재 속도 레벨까지 반복하면서, 최대 속도 레벨 / 2 까지는 milliSecond 에서 SPEED_LEVEL_OFFSET 만큼 빼고, 그 이후에는, SPEED_LEVEL_OFFSET / 5 를 빼면서, 점점 블럭이 내려오는 속도인 milliSecond 를 줄여줍니다.


142 라인

Sleep 함수를 호출하면서 위에서 만든 milliSecond 를 매개변수로 넘겨서 프로그램을 지연시킵니다. 지연 후에 블럭이 자동으로 내려오게 됩니다.

(1 초에 한 번씩 데이터 출력하기 참고)

http://kkikkodev.tistory.com/66


145 라인

TetrisManager_Print 함수의 정의부입니다. 매개변수로 tetrisManager 를 받아서, 테트리스 판을 출력하고, 게임 상태를 출력하는 역할을 합니다.


148 ~ 184 라인

CursorUtil_GotoXY 로 (0,0) 위치로 커서를 이동시킨 후에, tetrisManager->board 배열을 반복하면서, boardType 에 따라 해당하는 문자열을 화면에 출력합니다.

(콘솔 커서 좌표 이동하기 참고)

http://kkikkodev.tistory.com/26


185 ~ 192 라인

테트리스의 속도 레벨과 현재까지 삭제한 총 줄 수를 출력하고, Block_PrintNext 함수를 호출하여 다음 나올 블럭을 화면에 출력한 뒤, CursorUtil_Hide 함수를 호출하여 커서를 숨깁니다.

(콘솔 커서 숨기기 & 두께 조절하기 참고)

http://kkikkodev.tistory.com/27


195 라인

_TetrisManager_ClearBoard 함수의 정의부입니다. 매개변수로 tetrisManger 를 전달받아서 테트리스 판을 초기화하는 역할을 합니다.


198 ~ 201 라인

테트리스판의 왼쪽 벽과 오른쪽 벽을 재설정합니다.


202 ~ 205 라인

테트리스판의 위쪽 벽과 아래쪽 벽을 재설정합니다.


206 ~ 212 라인

테트리스 판의 안쪽에서 굳어진 블럭 빼고 모두 빈 공간으로 재설정합니다.


213 ~ 216 라인

테트리스 판의 4 모서리를 재설정합니다.


219 라인

_TetrisManager_ChangeBoardByStatus 함수의 정의부입니다. 매개변수로는 tetrisManager 와 status (테트리스 판에서 블럭의 위치에 해당하는 좌표를 변경할 상태) 를 받아서, 해당 status 로 블럭의 위치를 테트리스판에서 변경하는 역할을 합니다.


221 ~ 225 라인

block 의 4 좌표를 돌면서 입력받은 status 로 변경해 줍니다.


228 라인

_TetrisManager_UpSpeedLevel 함수의 정의부입니다. 매개변수로 tetrisManager 를 받아서 속도레벨을 1 증가 시키는 역할을 합니다.


229 ~ 231 라인

속도 레벨이 최대 속도 레벨보다 작은 경우에만 1 증가 시킵니다.


234 라인

_TetrisManager_SearchLineIndexesToDelete 함수의 정의부입니다. 매개변수로 tetrisManager 와 indexes (삭제할 라인의 위치들을 담을 배열), count (삭제할 라인의 총 개수) 를 전달받아서, 테트리스 판 중에서 삭제할 라인의 위치를 찾는 역할을 하고 있습니다. 


238 ~ 239 라인

indexes 배열에 memset 함수를 통해 -1 로 모두 초기화합니다. 그리고 count 에 0 을 저장합니다.

(변수 or 배열을 특정 값으로 한번에 초기화하기 참고)

http://kkikkodev.tistory.com/50


240 ~ 251 라인

테트리스 판을 모두 돌면서 가로 한 줄이 모두 FIXED_BLOCK 인 경우를 찾아서 그 위치를 indexes 에 저장하고, 그 때마다 count 를 1 씩 증가합니다.


254 라인

_TetrisManager_DeleteLines 함수의 정의부입니다. 매개변수로 tetrisManager 와 indexes (삭제할 라인의 위치가 담긴 배열), count (삭제할 라인의 총 개수) 를 전달받아서 삭제할 라인을 지우는 역할을 합니다.


259 라인

라인 삭제를 하기 위해서 임시로 삭제된 테트리스판을 저장할 임시 판을 선언합니다.


260 ~ 274 라인

테트리스판을 돌면서 indexes 에 해당하는 줄을 제외한 모든 줄을 임시 판에 저장합니다.


275 ~ 279 라인

다시 임시 판을 기존의 판에 복사합니다.


280 라인

tetrisManager 의 deletedLineCount 를 count 만큼 증가시킵니다.


by kkikkodev 2015. 6. 12. 11:24