¡¡/********************************/
¡¡¡¡/* Desc: ¶íÂÞ˹·½¿éÓÎÏ· */
¡¡¡¡/* By: hoodlum1980 */
¡¡¡¡/* Email: jinfd@126.com */
¡¡¡¡/* Date: 2008.03.12 22£º30 */
¡¡¡¡/********************************/
¡¡¡¡#include <stdio.h>
¡¡¡¡#include <bios.h>
¡¡¡¡#include <dos.h>
¡¡¡¡#include <graphics.h>
¡¡¡¡#include <string.h>
¡¡¡¡#include <stdlib.h>
¡¡¡¡#define true 1
¡¡¡¡#define false 0
¡¡¡¡#define BoardWidth 12
¡¡¡¡#define BoardHeight 23
¡¡¡¡#define _INNER_HELPER /*inner helper method */
¡¡¡¡/*Scan Codes Define*/
¡¡¡¡enum KEYCODES
¡¡¡¡{
¡¡¡¡K_ESC =0x011b,
¡¡¡¡K_UP =0x4800, /* upward arrow */
¡¡¡¡K_LEFT =0x4b00,
¡¡¡¡K_DOWN =0x5000,
¡¡¡¡K_RIGHT =0x4d00,
¡¡¡¡K_SPACE =0x3920,
¡¡¡¡K_P =0x1970
¡¡¡¡};
¡¡¡¡/* the data structure of the block */
¡¡¡¡typedef struct tagBlock
¡¡¡¡{
¡¡¡¡char c[4][4]; /* cell fill info array, 0-empty, 1-filled */
¡¡¡¡int x; /* block position cx [ 0,BoardWidht -1] */
¡¡¡¡int y; /* block position cy [-4,BoardHeight-1] */
¡¡¡¡char color; /* block color */
¡¡¡¡char size; /* block max size in width or height */
¡¡¡¡char name; /* block name (the block's shape) */
¡¡¡¡} Block;
¡¡¡¡/* game's global info */
¡¡¡¡int FrameTime= 1300;
¡¡¡¡int CellSize= 18;
¡¡¡¡int BoardLeft= 30;
¡¡¡¡int BoardTop= 30;
¡¡¡¡/* next block grid */
¡¡¡¡int NBBoardLeft= 300;
¡¡¡¡int NBBoardTop= 30;
¡¡¡¡int NBCellSize= 10;
¡¡¡¡/* score board position */
¡¡¡¡int ScoreBoardLeft= 300;
¡¡¡¡int ScoreBoardTop=100;
¡¡¡¡int ScoreBoardWidth=200;
¡¡¡¡int ScoreBoardHeight=35;
¡¡¡¡int ScoreColor=LIGHTCYAN;
¡¡¡¡/* infor text postion */
¡¡¡¡int InfoLeft=300;
¡¡¡¡int InfoTop=200;
¡¡¡¡int InfoColor=YELLOW;
¡¡¡¡int BorderColor=DARKGRAY;
¡¡¡¡int BkGndColor=BLACK;
¡¡¡¡int GameRunning=true;
¡¡¡¡int TopLine=BoardHeight-1; /* top empty line */
¡¡¡¡int TotalScore=100;
¡¡¡¡char info_score[20];
¡¡¡¡char info_help[255];
¡¡¡¡char info_common[255];
¡¡¡¡/* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */
¡¡¡¡unsigned char Board[BoardWidth][BoardHeight][2];
¡¡¡¡char BufferCells[4][4]; /* used to judge if can rotate block */
¡¡¡¡Block curBlock; /* current moving block */
¡¡¡¡Block nextBlock; /* next Block to appear */
¡¡¡¡/* function list */
¡¡¡¡int GetKeyCode();
¡¡¡¡int CanMove(int dx,int dy);
¡¡¡¡int CanRotate();
¡¡¡¡int RotateBlock(Block *block);
¡¡¡¡int MoveBlock(Block *block,int dx,int dy);
¡¡¡¡void DrawBlock(Block *block,int,int,int);
¡¡¡¡void EraseBlock(Block *block,int,int,int);
¡¡¡¡void DisplayScore();
¡¡¡¡void DisplayInfo(char* text);
¡¡¡¡void GenerateBlock(Block *block);
¡¡¡¡void NextBlock();
¡¡¡¡void InitGame();
¡¡¡¡int PauseGame();
¡¡¡¡void QuitGame();
¡¡¡¡/*Get Key Code */
¡¡¡¡int GetKeyCode()
¡¡¡¡{
¡¡¡¡int key=0;
¡¡¡¡if(bioskey(1))
¡¡¡¡{
¡¡¡¡key=bioskey(0);
¡¡¡¡}
¡¡¡¡return key;
¡¡¡¡}
¡¡¡¡/* display text! */
¡¡¡¡void DisplayInfo(char *text)
¡¡¡¡{
¡¡¡¡setcolor(BkGndColor);
¡¡¡¡outtextxy(InfoLeft,InfoTop,info_common);
¡¡¡¡strcpy(info_common,text);
¡¡¡¡setcolor(InfoColor);
¡¡¡¡outtextxy(InfoLeft,InfoTop,info_common);
¡¡¡¡}
¡¡¡¡/* create a new block by key number,
¡¡¡¡* the block anchor to the top-left corner of 4*4 cells
¡¡¡¡*/
¡¡¡¡void _INNER_HELPER GenerateBlock(Block *block)
¡¡¡¡{
¡¡¡¡int key=(random(13)*random(17)+random(1000)+random(3000))%7;
¡¡¡¡block->size=3;/* because most blocks' size=3 */
¡¡¡¡memset(block->c,0,16);
¡¡¡¡switch(key)
¡¡¡¡{
¡¡¡¡case 0:
¡¡¡¡block->name='T';
¡¡¡¡block->color=RED;
¡¡¡¡block->c[1][0]=1;
¡¡¡¡block->c[1][1]=1, block->c[2][1]=1;
¡¡¡¡block->c[1][2]=1;
¡¡¡¡break;
¡¡¡¡case 1:
¡¡¡¡block->name='L';
¡¡¡¡block->color=YELLOW;
¡¡¡¡block->c[1][0]=1;
¡¡¡¡block->c[1][1]=1;
¡¡¡¡block->c[1][2]=1, block->c[2][2]=1;
¡¡¡¡break;
¡¡¡¡case 2:
¡¡¡¡block->name='J';
¡¡¡¡block->color=LIGHTGRAY;
¡¡¡¡block->c[1][0]=1;
¡¡¡¡block->c[1][1]=1;
¡¡¡¡block->c[1][2]=1, block->c[0][2]=1;
¡¡¡¡break;
¡¡¡¡case 3:
¡¡¡¡block->name='z';
¡¡¡¡block->color=CYAN;
¡¡¡¡block->c[0][0]=1, block->c[1][0]=1;
¡¡¡¡block->c[1][1]=1, block->c[2][1]=1;
¡¡¡¡break;
¡¡¡¡case 4:
¡¡¡¡block->name='5';
¡¡¡¡block->color=LIGHTBLUE;
¡¡¡¡block->c[1][0]=1, block->c[2][0]=1;
¡¡¡¡block->c[0][1]=1, block->c[1][1]=1;
¡¡¡¡break;
¡¡¡¡case 5:
¡¡¡¡block->name='o';
¡¡¡¡block->color=BLUE;
¡¡¡¡block->size=2;
¡¡¡¡block->c[0][0]=1, block->c[1][0]=1;
¡¡¡¡block->c[0][1]=1, block->c[1][1]=1;
¡¡¡¡break;
¡¡¡¡case 6:
¡¡¡¡block->name='I';
¡¡¡¡block->color=GREEN;
¡¡¡¡block->size=4;
¡¡¡¡block->c[1][0]=1;
¡¡¡¡block->c[1][1]=1;
¡¡¡¡block->c[1][2]=1;
¡¡¡¡block->c[1][3]=1;
¡¡¡¡break;
¡¡¡¡}
¡¡¡¡}
¡¡¡¡/* get next block! */
¡¡¡¡void NextBlock()
¡¡¡¡{
¡¡¡¡/* copy the nextBlock to curBlock */
¡¡¡¡curBlock.size=nextBlock.size;
¡¡¡¡curBlock.color=nextBlock.color;
¡¡¡¡curBlock.x=(BoardWidth-4)/2;
¡¡¡¡curBlock.y=-curBlock.size;
¡¡¡¡memcpy(curBlock.c,nextBlock.c,16);
¡¡¡¡/* generate nextBlock and show it */
¡¡¡¡EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);
¡¡¡¡GenerateBlock(&nextBlock);
¡¡¡¡nextBlock.x=1,nextBlock.y=0;
¡¡¡¡DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);
¡¡¡¡}
¡¡¡¡/* rotate the block, update the block struct data */
¡¡¡¡int _INNER_HELPER RotateCells(char c[4][4],char blockSize)
¡¡¡¡{
¡¡¡¡char temp,i,j;
¡¡¡¡switch(blockSize)
¡¡¡¡{
¡¡¡¡case 3:
¡¡¡¡temp=c[0][0];
¡¡¡¡c[0][0]=c[2][0], c[2][0]=c[2][2], c[2][2]=c[0][2], c[0][2]=temp;
¡¡¡¡temp=c[0][1];
¡¡¡¡c[0][1]=c[1][0], c[1][0]=c[2][1], c[2][1]=c[1][2], c[1][2]=temp;
¡¡¡¡break;
¡¡¡¡case 4: /* only 'I' block arived here! */
¡¡¡¡c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3];
¡¡¡¡c[0][1]=1-c[0][1], c[2][1]=1-c[2][1], c[3][1]=1-c[3][1];
¡¡¡¡break;
¡¡¡¡}
¡¡¡¡}
¡¡¡¡/* judge if the block can move toward the direction */
¡¡¡¡int CanMove(int dx,int dy)
¡¡¡¡{
¡¡¡¡int i,j,tempX,tempY;
¡¡¡¡for(i=0;i<curBlock.size;i++)
¡¡¡¡{
¡¡¡¡for(j=0;j<curBlock.size;j++)
¡¡¡¡{
¡¡¡¡if(curBlock.c[i][j])
¡¡¡¡{
¡¡¡¡/* cannot move leftward or rightward */
¡¡¡¡tempX = curBlock.x + i + dx;
¡¡¡¡if(tempX<0 || tempX>(BoardWidth-1)) return false; /* make sure x is valid! */
¡¡¡¡/* cannot move downward */
¡¡¡¡tempY = curBlock.y + j + dy;
¡¡¡¡if(tempY>(BoardHeight-1)) return false; /* y is only checked lower bound, maybe negative!!!! */
¡¡¡¡/* the cell already filled, we must check Y's upper bound before check cell ! */
¡¡¡¡if(tempY>=0 &&Board[tempX][tempY][0]) return false;
¡¡¡¡}
¡¡¡¡}
¡¡¡¡}
¡¡¡¡return true;
¡¡¡¡}
¡¡¡¡/* judge if the block can rotate */
¡¡¡¡int CanRotate()
¡¡¡¡{
¡¡¡¡int i,j,tempX,tempY;
¡¡¡¡/* update buffer */
¡¡¡¡memcpy(BufferCells, curBlock.c, 16);
¡¡¡¡RotateCells(BufferCells,curBlock.size);
¡¡¡¡for(i=0;i<curBlock.size;i++)
¡¡¡¡{
¡¡¡¡for(j=0;j<curBlock.size;j++)
¡¡¡¡{
¡¡¡¡if(BufferCells[i][j])
¡¡¡¡{
¡¡¡¡tempX=curBlock.x+i;
¡¡¡¡tempY=curBlock.y+j;
¡¡¡¡if(tempX<0 || tempX>(BoardWidth-1))
¡¡¡¡return false;
¡¡¡¡if(tempY>(BoardHeight-1))
¡¡¡¡return false;
¡¡¡¡if(tempY>=0 &&Board[tempX][tempY][0])
¡¡¡¡return false;
¡¡¡¡}
¡¡¡¡}
¡¡¡¡}
¡¡¡¡return true;
¡¡¡¡}
¡¡¡¡/* draw the block */
¡¡¡¡void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize)
¡¡¡¡{
¡¡¡¡int i,j;
¡¡¡¡setfillstyle(SOLID_FILL,block->color);
¡¡¡¡for(i=0;i<block->size;i++)
¡¡¡¡{
¡¡¡¡for(j=0;j<block->size;j++)
¡¡¡¡{
¡¡¡¡if(block->c[i][j] &&(block->y+j)>=0)
¡¡¡¡{
¡¡¡¡floodfill(
¡¡¡¡bdLeft+cellSize*(i+block->x)+cellSize/2,
¡¡¡¡bdTop+cellSize*(j+block->y)+cellSize/2,
¡¡¡¡BorderColor);
¡¡¡¡}
¡¡¡¡}
¡¡¡¡}
¡¡¡¡}
¡¡¡¡/* Rotate the bloc