[code]
//
// 설명 읽지말고 분석하란다 OTL
//
#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;
};
//
// 원래는...
// {{0,0},{1,0},{2,0},{-1,0}} 이렇게 해야된다..
//
// -1,0, 1.0, 0,0, 2,0
//
// ㅡ 모양의 블럭이 완성된다.
// 이후 것은
// 0,1,
// 0,0,
// 0,-1,
// 0,-2
// 식으로 회전 한다. 일명 제일 좋아하는 짝대기...
//
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 };
char *arTile[]={". ","■","□"};
int board[BW+2][BH+2];
int nx,ny;
int brick,rot;
void main()
{
int nFrame, nStay;
int x,y;
setcursortype(NOCURSOR);
randomize();
clrscr();
// □ 으로 테두리 변수에 대입하기
for (x=0;x<BW+2;x++) {
for (y=0;y<BH+2;y++) {
board[x][y] = (y==0 || y==BH+1 || x==0 || x==BW+1) ? WALL:EMPTY;
}
}
DrawScreen();
nFrame=20;
for (;1;) {
brick=random(sizeof(Shape)/sizeof(Shape[0])); // 896 / 128 = 7가지의 종류!!
nx=BW/2; // 5
ny=3; // 3
rot=0;
PrintBrick(TRUE);
if (GetAround(nx,ny,brick,rot) != EMPTY) break;
nStay=nFrame;
//
// for (;2;) 루프의 끝에서 0.05초씩 시간을 지연시키고 있으므로 이 루프는 초당 20번 반복된다.
// 벽돌 하나가 내려오는 주기인 nFrame이 20으로 초기화되어 있고 nStay가 이 값을 역카운트하면서
// 0이 될 때 벽돌을 한칸 내린다. 그래서 벽돌은 정확하게 1초에 한 번 한칸 아래로 이동할 것이다.
// 이렇게 할 바에야 아예 delay(1000)을 주고 1초에 한 번씩 벽돌을 이동시킬 수도 있지만 그렇게
// 할 경우 키 입력도 1초에 한 번밖에 못 받으므로 반응성이 떨어진다. 그래서 시간을 1/20초로
// 분할하고 벽돌은 20프레임에 한 번씩 움직이되 키는 매 프레임마다 입력받을 수 있도록 했다
//
for (;2;) {
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()
{
int x,y;
// 변수의 내용을 직접 뿌려주기 puts
for (x=0;x<BW+2;x++) {
for (y=0;y<BH+2;y++) {
gotoxy(BX+x*2,BY+y);
puts(arTile[board[x][y]]);
}
}
gotoxy(50,3);puts("ShTetris Ver 1.0");
gotoxy(50,5);puts("좌우:이동, 위:회전, 아래:내림");
gotoxy(50,6);puts("공백:전부 내림");
// gotoxy(50,8);
//printf("%d, %d",sizeof(Shape),sizeof(Shape[0]));
}
//
// 게임판만 그린다. 즉 외부벽과 문자열들은 빼고 쌓여 있는 벽돌만 그린다
//
void DrawBoard()
{
int x,y;
for (x=1;x<BW+1;x++) {
for (y=1;y<BH+1;y++) {
gotoxy(BX+x*2,BY+y);
puts(arTile[board[x][y]]);
}
}
}
//
// 키 입력을 처리하는데 main 함수의 부담을 덜어주기 위해 별도의 함수로 분리해 놓았다. 이동중인 벽돌이 바닥에 닿으면 TRUE를 리턴한다
//
BOOL ProcessKey()
{
int ch,trot;
if (kbhit()) {
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,trot) == 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;
}
//
// 벽돌을 출력하거나 삭제하는데 이동중인 벽돌을 대상으로 하므로 전역 변수 brick, rot, nx, ny값을 참조한다
//
void PrintBrick(BOOL Show) // 불쑈 ㅡ.ㅡ;;;; 미친소가 생각나따!
{
int i;
//
// 하나의 블럭을 완성시킨다... 4번 for를 돌리므로서의 완성(배열정보가 4개므로..)
//
for (i=0;i<4;i++) {
//
// 0: 5+(0+5)*2, 1+0+3 = 15 4
// 1: 5+(1+5)*2, 1+0+3 = 17 4
// 2: 5+(2+5)*2, 1+0+3 = 19 4
// 3: 5+(-1+5)*2, 1+0+3 = 13 4
//
// [벽돌 종류], [회전번호], [일련번호]
gotoxy(BX+(Shape[brick][0][i].x+nx)*2,BY+Shape[brick][rot][i].y+ny);
puts(arTile[Show ? BRICK:EMPTY]);
}
}
//
// x:5, y:3, b:random, r:0
// 벽돌 주변에 무엇이 있는지 검사하여 벽돌의 이동 및 회전 가능성을 조사한다.
// 이동중인 벽돌의 주변을 조사하는 것이 아니므로 인수로 전달된 위치의 벽돌 모양을 참조한다.
//
// □ □ □ □ □ □ □ □ □ □ □ □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ □ □ □ □ □ □ □ □ □ □ □
//
int GetAround(int x,int y,int b,int r)
{
int i,k=EMPTY;
for (i=0;i<4;i++) {
// EMPTY보다는 BRICK을, BRICK보다는 WALL을 더 큰 값으로 평가한다
// board[5+0][3+0]
// board[5+1][3+0]
// board[5+2][3+0]
// board[5+-1][3+0]
k=max(k,board[x+Shape[r][i].x][y+Shape[r][i].y]);
}
return k;
}
//
// 벽돌을 한칸 아래로 이동시킨다. 만약 바닥에 닿았다면 TestFull 함수를 호출한 후 TRUE를 리턴한다.
//
BOOL MoveDown()
{
if (GetAround(nx,ny+1,brick,rot) != EMPTY) {
TestFull();
return TRUE;
}
PrintBrick(FALSE);
ny++;
PrintBrick(TRUE);
return FALSE;
}
//
// 수평으로 다 채워진 줄을 찾아 삭제한다
//
void TestFull()
{
int i,x,y,ty;
for (i=0;i<4;i++) {
board[nx+Shape[brick][rot][i].x][ny+Shape[brick][rot][i].y]=BRICK;
}
for (y=1;y<BH+1;y++) {
// 한줄 전체가 BRICK이면
for (x=1;x<BW+1;x++) {
if (board[x][y] != BRICK) break;
}
if (x == BW+1) {
for (ty=y;ty>1;ty--) {
for (x=1;x<BW+1;x++) {
board[x][ty]=board[x][ty-1];
}
}
DrawBoard();
delay(200);
}
}
}
[/code]
//
// 설명 읽지말고 분석하란다 OTL
//
#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;
};
//
// 원래는...
// {{0,0},{1,0},{2,0},{-1,0}} 이렇게 해야된다..
//
// -1,0, 1.0, 0,0, 2,0
//
// ㅡ 모양의 블럭이 완성된다.
// 이후 것은
// 0,1,
// 0,0,
// 0,-1,
// 0,-2
// 식으로 회전 한다. 일명 제일 좋아하는 짝대기...
//
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 };
char *arTile[]={". ","■","□"};
int board[BW+2][BH+2];
int nx,ny;
int brick,rot;
void main()
{
int nFrame, nStay;
int x,y;
setcursortype(NOCURSOR);
randomize();
clrscr();
// □ 으로 테두리 변수에 대입하기
for (x=0;x<BW+2;x++) {
for (y=0;y<BH+2;y++) {
board[x][y] = (y==0 || y==BH+1 || x==0 || x==BW+1) ? WALL:EMPTY;
}
}
DrawScreen();
nFrame=20;
for (;1;) {
brick=random(sizeof(Shape)/sizeof(Shape[0])); // 896 / 128 = 7가지의 종류!!
nx=BW/2; // 5
ny=3; // 3
rot=0;
PrintBrick(TRUE);
if (GetAround(nx,ny,brick,rot) != EMPTY) break;
nStay=nFrame;
//
// for (;2;) 루프의 끝에서 0.05초씩 시간을 지연시키고 있으므로 이 루프는 초당 20번 반복된다.
// 벽돌 하나가 내려오는 주기인 nFrame이 20으로 초기화되어 있고 nStay가 이 값을 역카운트하면서
// 0이 될 때 벽돌을 한칸 내린다. 그래서 벽돌은 정확하게 1초에 한 번 한칸 아래로 이동할 것이다.
// 이렇게 할 바에야 아예 delay(1000)을 주고 1초에 한 번씩 벽돌을 이동시킬 수도 있지만 그렇게
// 할 경우 키 입력도 1초에 한 번밖에 못 받으므로 반응성이 떨어진다. 그래서 시간을 1/20초로
// 분할하고 벽돌은 20프레임에 한 번씩 움직이되 키는 매 프레임마다 입력받을 수 있도록 했다
//
for (;2;) {
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()
{
int x,y;
// 변수의 내용을 직접 뿌려주기 puts
for (x=0;x<BW+2;x++) {
for (y=0;y<BH+2;y++) {
gotoxy(BX+x*2,BY+y);
puts(arTile[board[x][y]]);
}
}
gotoxy(50,3);puts("ShTetris Ver 1.0");
gotoxy(50,5);puts("좌우:이동, 위:회전, 아래:내림");
gotoxy(50,6);puts("공백:전부 내림");
// gotoxy(50,8);
//printf("%d, %d",sizeof(Shape),sizeof(Shape[0]));
}
//
// 게임판만 그린다. 즉 외부벽과 문자열들은 빼고 쌓여 있는 벽돌만 그린다
//
void DrawBoard()
{
int x,y;
for (x=1;x<BW+1;x++) {
for (y=1;y<BH+1;y++) {
gotoxy(BX+x*2,BY+y);
puts(arTile[board[x][y]]);
}
}
}
//
// 키 입력을 처리하는데 main 함수의 부담을 덜어주기 위해 별도의 함수로 분리해 놓았다. 이동중인 벽돌이 바닥에 닿으면 TRUE를 리턴한다
//
BOOL ProcessKey()
{
int ch,trot;
if (kbhit()) {
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,trot) == 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;
}
//
// 벽돌을 출력하거나 삭제하는데 이동중인 벽돌을 대상으로 하므로 전역 변수 brick, rot, nx, ny값을 참조한다
//
void PrintBrick(BOOL Show) // 불쑈 ㅡ.ㅡ;;;; 미친소가 생각나따!
{
int i;
//
// 하나의 블럭을 완성시킨다... 4번 for를 돌리므로서의 완성(배열정보가 4개므로..)
//
for (i=0;i<4;i++) {
//
// 0: 5+(0+5)*2, 1+0+3 = 15 4
// 1: 5+(1+5)*2, 1+0+3 = 17 4
// 2: 5+(2+5)*2, 1+0+3 = 19 4
// 3: 5+(-1+5)*2, 1+0+3 = 13 4
//
// [벽돌 종류], [회전번호], [일련번호]
gotoxy(BX+(Shape[brick][0][i].x+nx)*2,BY+Shape[brick][rot][i].y+ny);
puts(arTile[Show ? BRICK:EMPTY]);
}
}
//
// x:5, y:3, b:random, r:0
// 벽돌 주변에 무엇이 있는지 검사하여 벽돌의 이동 및 회전 가능성을 조사한다.
// 이동중인 벽돌의 주변을 조사하는 것이 아니므로 인수로 전달된 위치의 벽돌 모양을 참조한다.
//
// □ □ □ □ □ □ □ □ □ □ □ □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ . . . . . . . . . . □
// □ □ □ □ □ □ □ □ □ □ □ □
//
int GetAround(int x,int y,int b,int r)
{
int i,k=EMPTY;
for (i=0;i<4;i++) {
// EMPTY보다는 BRICK을, BRICK보다는 WALL을 더 큰 값으로 평가한다
// board[5+0][3+0]
// board[5+1][3+0]
// board[5+2][3+0]
// board[5+-1][3+0]
k=max(k,board[x+Shape[r][i].x][y+Shape[r][i].y]);
}
return k;
}
//
// 벽돌을 한칸 아래로 이동시킨다. 만약 바닥에 닿았다면 TestFull 함수를 호출한 후 TRUE를 리턴한다.
//
BOOL MoveDown()
{
if (GetAround(nx,ny+1,brick,rot) != EMPTY) {
TestFull();
return TRUE;
}
PrintBrick(FALSE);
ny++;
PrintBrick(TRUE);
return FALSE;
}
//
// 수평으로 다 채워진 줄을 찾아 삭제한다
//
void TestFull()
{
int i,x,y,ty;
for (i=0;i<4;i++) {
board[nx+Shape[brick][rot][i].x][ny+Shape[brick][rot][i].y]=BRICK;
}
for (y=1;y<BH+1;y++) {
// 한줄 전체가 BRICK이면
for (x=1;x<BW+1;x++) {
if (board[x][y] != BRICK) break;
}
if (x == BW+1) {
for (ty=y;ty>1;ty--) {
for (x=1;x<BW+1;x++) {
board[x][ty]=board[x][ty-1];
}
}
DrawBoard();
delay(200);
}
}
}
[/code]
'Native > C' 카테고리의 다른 글
함수 포인터 상에서의 캐스트 연산자 (0) | 2013.10.02 |
---|---|
Function pointer(함수포인터) (0) | 2013.10.02 |
turbo.h (0) | 2013.10.02 |
Matrix Logo (0) | 2013.10.02 |
공용체 Union (0) | 2013.10.02 |