/* Name: blockInfo.h ver 1.0
* Content: 각종 블록 정보
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#ifndef __BLOCK_INFO_H_
#define __BLOCK_INFO_H_
#define NUM_OF_BLOCK_MODEL 7
char blockModel[][4][4] =
{
/* 첫 번째 블록
■
■■■ */
{
{0, 0, 0, 0},
{1, 0, 0, 0},
{1, 1, 1, 0},
{0, 0, 0, 0} },
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{0, 0, 0, 0} },
{
{0, 0, 0, 0},
{1, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 0, 0} },
{
{0, 0, 0, 0},
{1, 1, 0, 0},
{1, 0, 0, 0},
{1, 0, 0, 0} },
/* 두 번째 블록
■
■■■ */
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{1, 1, 1, 0},
{0, 0, 0, 0} },
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 0} },
{
{0, 0, 0, 0},
{0, 1, 1, 1},
{0, 1, 0, 0},
{0, 0, 0, 0} },
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0} },
/* 세 번째 블록
■
■■■ */
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 1, 0},
{0, 0, 0, 0} },
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 0, 0},
{0, 1, 0, 0} },
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{1, 1, 1, 0},
{0, 1, 0, 0} },
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 1, 0, 0} },
/* 네 번째 블록
■■■■ */
{
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 0, 0} },
{
{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} },
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{1, 1, 1, 1},
{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, 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, 0},
{0, 0, 0, 0} },
/* 여섯 번째 블록
■■
■■ */
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{1, 1, 0, 0},
{0, 0, 0, 0} },
{
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 0, 0} },
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{1, 1, 0, 0},
{0, 0, 0, 0} },
{
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 0, 0} },
/* 일곱 번째 블록
■■
■■ */
{
{0, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0} },
{
{0, 1, 0, 0},
{1, 1, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 0} },
{
{0, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 0, 0} },
{
{0, 1, 0, 0},
{1, 1, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 0} },
};
#endif
/* end of file */
/* Name: blockStageControl.c ver 1.2
* Content: 블록, 게임화면 컨트롤 함수들의 정의
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#include <time.h>
#include "common.h"
#include "point.h"
#include "blockInfo.h"
#include "keyCurControl.h"
#define GBOARD_WIDTH 10
#define GBOARD_HEIGHT 20
#define GBOARD_ORIGIN_X 4
#define GBOARD_ORIGIN_Y 2
static int gameBoardInfo[GBOARD_HEIGHT+1][GBOARD_WIDTH+2]={0,};
static int currentBlockModel;
static int curPosX, curPosY;
static int rotateSte;
/* 함 수: void InitNewBlockPos(int x, int y)
* 기 능: 블록의 첫 위치 지정
* 반 환: void
*
*/
void InitNewBlockPos(int x, int y)
{
if(x<0 || y<0)
return;
curPosX=x;
curPosY=y;
SetCurrentCursorPos(x, y);
}
/* 함 수: void ChooseBlock(void)
* 기 능: 출력할 블록을 무작위 선택
* 반 환: void
*
*/
void ChooseBlock(void)
{
srand((unsigned int)time(NULL));
currentBlockModel = (rand() % NUM_OF_BLOCK_MODEL) * 4;
}
/* 함 수: int GetCurrentBlockIdx(void)
* 기 능: 현재 출력해야 하는 블록의 index 정보 반환
* 반 환: int
*
*/
int GetCurrentBlockIdx(void)
{
return currentBlockModel + rotateSte;
}
/* 함 수: void ShowBlock(char blockInfo[][4])
* 기 능: 전달된 인자를 참조하여 블록 출력
* 반 환: void
*
*/
void ShowBlock(char blockInfo[][4])
{
int y, x;
point curPos=GetCurrentCursorPos();
for(y=0; y<4; y++)
{
for(x=0; x<4; x++)
{
SetCurrentCursorPos(curPos.x+x*2, curPos.y+y);
if(blockInfo[y][x] == 1)
printf("■");
}
}
SetCurrentCursorPos(curPos.x, curPos.y);
}
/* 함 수: void DeleteBlock(char blockInfo[][4])
* 기 능: 현재 위치에 출력된 블록 삭제
* 반 환: void
*
*/
void DeleteBlock(char blockInfo[][4])
{
int y, x;
point curPos=GetCurrentCursorPos();
for(y=0; y<4; y++)
{
for(x=0; x<4; x++)
{
SetCurrentCursorPos(curPos.x+x*2, curPos.y+y);
if(blockInfo[y][x] == 1)
printf(" ");
}
}
SetCurrentCursorPos(curPos.x, curPos.y);
}
/* 함 수: int DetectCollision(int posX, int posY, char blockModel[][4])
* 기 능: 블록의 이동 및 회전 가능 여부 판단
* 반 환: 이동 및 회전 가능시 1 반환
*
*/
int DetectCollision(int posX, int posY, char blockModel[][4])
{
int x, y;
/* gameBoardInfo 배열의 좌표로 변경 */
int arrX= (posX-GBOARD_ORIGIN_X)/2;
int arrY= posY-GBOARD_ORIGIN_Y;
/* 충돌 검사 */
for(x=0; x<4; x++)
{
for(y=0; y<4; y++)
{
/* Short Circuit eva1uation에 의해 배열 일부만 검사 */
if(blockModel[y][x]==1 && gameBoardInfo[arrY+y][arrX+x]==1)
return 0;
}
}
return 1;
}
/* 함 수: int BlockDown(void)
* 기 능: 모니터에 그려진 블록을 아래로 한 칸 내림
* 반 환: 성공 시 1, 실패 시 0
*
*/
int BlockDown(void)
{
if(!DetectCollision(curPosX, curPosY+1, blockModel[GetCurrentBlockIdx()]))
return 0;
DeleteBlock(blockModel[GetCurrentBlockIdx()]);
curPosY+=1;
SetCurrentCursorPos(curPosX, curPosY);
ShowBlock(blockModel[GetCurrentBlockIdx()]);
return 1;
}
/* 함 수: void ShiftLeft(void)
* 기 능: 블록을 왼쪽으로 한 칸 이동
* 반 환: void
*
*/
void ShiftLeft(void)
{
if(!DetectCollision(curPosX-2, curPosY, blockModel[GetCurrentBlockIdx()]))
return;
DeleteBlock(blockModel[GetCurrentBlockIdx()]);
curPosX-=2;
SetCurrentCursorPos(curPosX, curPosY);
ShowBlock(blockModel[GetCurrentBlockIdx()]);
}
/* 함 수: void ShiftRight(void)
* 기 능: 블록을 오른쪽으로 한 칸 이동
* 반 환: void
*
*/
void ShiftRight(void)
{
if(!DetectCollision(curPosX+2, curPosY, blockModel[GetCurrentBlockIdx()]))
return;
DeleteBlock(blockModel[GetCurrentBlockIdx()]);
curPosX+=2;
SetCurrentCursorPos(curPosX, curPosY);
ShowBlock(blockModel[GetCurrentBlockIdx()]);
}
/* 함 수: void RotateBlock(void)
* 기 능: 블록을 90도 회전
* 반 환: void
*
*/
void RotateBlock(void)
{
int nextRotSte;
int beforeRotSte=rotateSte; // 복원을 위한 정보
DeleteBlock(blockModel[GetCurrentBlockIdx()]);
nextRotSte=rotateSte+1;
nextRotSte%=4;
rotateSte=nextRotSte;
if(!DetectCollision(curPosX, curPosY, blockModel[GetCurrentBlockIdx()]))
{
rotateSte=beforeRotSte;
return;
}
SetCurrentCursorPos(curPosX, curPosY);
ShowBlock(blockModel[GetCurrentBlockIdx()]);
}
/* 함 수: void DrawGameBoard(void)
* 기 능: 게임 판의 경계 면을 그린다.
* 반 환: void
*
*/
void DrawGameBoard(void)
{
int x, y;
/* 시각적인 부분 처리 */
for(y=0; y<=GBOARD_HEIGHT; y++)
{
SetCurrentCursorPos(GBOARD_ORIGIN_X, GBOARD_ORIGIN_Y+y);
if(y==GBOARD_HEIGHT)
printf("┗");
else
printf("┃");
}
for(y=0; y<=GBOARD_HEIGHT; y++)
{
SetCurrentCursorPos(GBOARD_ORIGIN_X+(GBOARD_WIDTH+1)*2, GBOARD_ORIGIN_Y+y);
if(y==GBOARD_HEIGHT)
printf("┛");
else
printf("┃");
}
for(x=1; x<GBOARD_WIDTH+1; x++)
{
SetCurrentCursorPos(GBOARD_ORIGIN_X+x*2, GBOARD_ORIGIN_Y+GBOARD_HEIGHT);
printf("━");
}
SetCurrentCursorPos(0, 0);
/* 데이터 부분 처리 */
for(y=0; y<GBOARD_HEIGHT; y++)
{
gameBoardInfo[y][0]=1;
gameBoardInfo[y][GBOARD_WIDTH+1]=1;
}
for(x=0; x<GBOARD_WIDTH+2; x++)
{
gameBoardInfo[GBOARD_HEIGHT][x]=1;
}
}
/* 함 수: void AddCurrentBlockInfoToBoard(void)
* 기 능: 배열에 현재 블록의 정보를 추가한다.
* 반 환: void
*
*/
void AddCurrentBlockInfoToBoard(void)
{
int x, y;
int arrCurX;
int arrCurY;
for(y=0; y<4; y++)
{
for(x=0; x<4; x++)
{
/* 커서 위치 정보를 배열 index 정보로 변경 */
arrCurX=(curPosX-GBOARD_ORIGIN_X)/2;
arrCurY=curPosY-GBOARD_ORIGIN_Y;
if(blockModel[GetCurrentBlockIdx()][y][x]==1)
gameBoardInfo[arrCurY+y][arrCurX+x]=1;
}
}
}
/* 함 수: int IsGameOver(void)
* 기 능: 게임이 종료되었는지 확인하는 함수
* 반 환: 게임 종료 시 1 반환
*
*/
int IsGameOver(void)
{
if(!DetectCollision(curPosX, curPosY, blockModel[GetCurrentBlockIdx()]))
return 1;
else
return 0;
}
/* end of file */
/* Name: blockStageControl.h ver 1.2
* Content: 블록, 게임화면 컨트롤 함수들의 선언
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#ifndef __BLOCK_STAGE_H_
#define __BLOCK_STAGE_H_
void InitNewBlockPos(int x, int y);
void ChooseBlock(void);
int GetCurrentBlockIdx(void);
void ShowBlock(char blockInfo[][4]);
void DeleteBlock(char blockInfo[][4]);
int BlockDown(void);
void ShiftLeft(void);
void ShiftRight(void);
void RotateBlock(void);
void AddCurrentBlockInfoToBoard(void);
void DrawGameBoard(void);
int IsGameOver(void);
#endif
/* Name: common.h ver 1.0
* Content: 공통 ANSI 표준 헤더.
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#ifndef __COMMOM_H__
#define __COMMON_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
/* end of file */
/* Name: keyCurControl.c ver 1.1
* Content: 커서, 키보드 컨트롤 함수들의 정의
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#include <conio.h>
#include <windows.h>
#include "point.h"
#include "blockStageControl.h"
#define KEY_SENSITIVE 100
#define SYS_DELAY 20
#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
static int keyDelayRate; // 값이 클수록 속도 증가
/* 함 수: void RemoveCursor(void)
* 기 능: 깜빡 거리는 커서의 제거
* 반 환: void
*
*/
void RemoveCursor(void)
{
CONSOLE_CURSOR_INFO curInfo;
GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&curInfo);
curInfo.bVisible=0;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&curInfo);
}
/* 함 수: point GetCurrentCursorPos(void)
* 기 능: 현재 커서 위치 정보를 담은 구조체 변수 반환
* 반 환: point
*
*/
point GetCurrentCursorPos(void)
{
point curPoint;
CONSOLE_SCREEN_BUFFER_INFO curInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &curInfo);
curPoint.x=curInfo.dwCursorPosition.X;
curPoint.y=curInfo.dwCursorPosition.Y;
return curPoint;
}
/* 함 수: void SetCurrentCursorPos(int x, int y)
* 기 능: 커서 위치를 설정
* 반 환: void
*
*/
void SetCurrentCursorPos(int x, int y)
{
COORD pos={x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
/* 함 수: void ProcessKeyInput(void)
* 기 능: 키 입력 처리
* 반 환: void
*
*/
void ProcessKeyInput(void)
{
int i;
int key;
for(i=0; i<KEY_SENSITIVE; i++)
{
if(_kbhit() != 0)
{
key = _getch();
switch(key)
{
case LEFT:
ShiftLeft();
break;
case RIGHT:
ShiftRight();
break;
case UP:
RotateBlock();
}
}
if(i % keyDelayRate == 0)
Sleep(SYS_DELAY);
}
}
/* 함 수: void InitKeyDelayRate(int rate)
* 기 능: 속도 조절, 값이 클수록 속도 증가
* 반 환: void
*
*/
void InitKeyDelayRate(int rate)
{
if(rate<1)
return;
keyDelayRate=rate;
}
/* end of file */
/* Name: keyCurControl.h ver 1.1
* Content: 커서, 키보드 컨트롤 함수들의 정의
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#ifndef __KEY_CURSOR_H_
#define __KEY_CURSOR_H_
#include "point.h"
void RemoveCursor(void);
point GetCurrentCursorPos(void);
void SetCurrentCursorPos(int x, int y);
void ProcessKeyInput(void);
void InitKeyDelayRate(int rate);
#endif
/* end of file */
/* Name: point.h ver 1.0
* Content: 커서 위치 정보 표현을 위한 구조체
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#ifndef __POINT_H_
#define __POINT_H_
typedef struct __point
{
int x;
int y;
} point;
#endif
/* Name: tetrisMain.c ver 1.2
* Content: main 함수의 정의
* Implementation: YSW
*
* Last modified 2008/01/01
*/
#include <Windows.h>
#include "common.h"
#include "keyCurControl.h"
#include "blockStageControl.h"
#define START_CURPOS_X (5*2)
#define START_CURPOS_Y (0)
int main(void)
{
/* 게임 속도 설정 */
InitKeyDelayRate(10);
/* 커서 깜빡임 제거 */
RemoveCursor();
/* 게임 보드 그리기 */
DrawGameBoard();
/* 반복적으로 새로운 블록의 등장 */
while(1)
{
/* 새 블록의 등장위치 설정 */
InitNewBlockPos(START_CURPOS_X, START_CURPOS_Y);
/* 블록 선택 */
ChooseBlock();
/* 게임 종료 확인 */
if(IsGameOver())
break;
/* 내리는 작업 시작 */
while(1)
{
/* 블록을 아래로 한 칸 이동 */
if(BlockDown()==0) // 블록 이동 실패 시
{
AddCurrentBlockInfoToBoard();
break;
}
/* 게이머 키 입력 처리 */
ProcessKeyInput();
}
}
SetCurrentCursorPos(10, 10);
puts("GAME OVER ^^");
return 0;
}
/* end of file */