admin 管理员组

文章数量: 887021


2024年2月26日发(作者:电脑如何下载matlab软件下载)

连连看游戏C语言源代码

#include

#include

#include

#include

#include

#define true 1

#define false 0

/* ---------------------全局变量------------------------------------ */

int BkGndColor=BLACK;

int BorderColor=LIGHTGRAY;

int LineColor=LIGHTBLUE;/* 消除一对方块时时候的连线颜色 */

/* Pb - ProgressBar */

int PbColor=LIGHTGREEN;

int PbY=4;

int PbHeight=4;

int PbValue; /* 进度条百分比,初始值为100.*/

long StartTime; /* 开始时间的秒数,只统计分钟,秒 */

long TotalTime; /* 游戏总共的最大秒数!,*/

/* BoardDatas: a small-size board */

/* Board[x][y][0] - 0:empty, 1:filled */

/* Board[x][y][1] - cell's key; */

unsigned char Board[10][10][2];

int CellSize=30;

int BoardX=20;

int BoardY=60;

int BoardWidth=10;

int BoardHeight=10;

int CellColor=WHITE;

int SelColor=BLUE; /* selCell's border rect color */

int CurColor=RED; /* curCell's border rect color */

int EraColor=CYAN; /* 用于擦除cell的颜色!*/

int PairsCount; /* how much pairs we have put on board */

/* 用于存储逻辑坐标(索引) */

typedef struct _tagCELL

{

char x;

char y;

} CELL;

CELL selCell,curCell;/*缓存前一个被选中的位置以及当前所处位置!*/

/*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,

K_RETURN =0x1c0d, /* Enter */

};

/* ---------------------函数列表------------------------------------ */

void InitGame(char *bgiPath);

void PlayGame();

void QuitGame();

void InitProgressBar();

void UpdateProgressBar(int percent);

void DrawCell(int key,int x,int y,int color);

void EraseCell(int x,int y);

void DrawBorderRect(CELL *c,int color);

void DrawGameOver(char* info);

int GetKeyCode();

int FindPath(CELL *c1,CELL *c2);

/*绘制消除方块时候的连接路径!,用指定颜色!*/

void DrawPath(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int color);

/* ----------------------函数实现----------------------------------- */

/* ----------------------[ 核心算法 ]---------------------------------

* 先进行水平方向判断,找出两点所在的水平直线活动范围,

* 算出这两条线段在垂直方向的共同区域,

* 遍历该区域判断能否在两线段间架起公垂线,能则两点连接上;

* 接着进行垂直方向判断,类同。无论两点在不在一条直线上,

* 都能使用该算法,因为两点同线只是两点作为矩形对角点的特例而已。

*/

/* 找到两个CELL之间的路径,成功返回true */

int FindPath(CELL *c1,CELL *c2)

{

int i,j,path,min1,max1,min2,max2,left,right,top,bottom;

/*---------------(0)判断是否点中相同块! ------------*/

if(Board[c1->x][c1->y][1] != Board[c2->x][c2->y][1])

return false;

/*---------------(1)查找水平方向公共区域!-----------*/

min1=max1=c1->x;

min2=max2=c2->x;

while(min1-1>=0 && Board[min1-1][c1->y][0]==0) min1--;

while(min2-1>=0 && Board[min2-1][c2->y][0]==0) min2--;

left=max(min1,min2); /* 左边界 */

while(max1+1y][0]==0) max1++;

while(max2+1y][0]==0) max2++;

right=min(max1,max2); /* 右边界 */

/* 检查两条水平线之间是否有公垂线连通!*/

/* 可以在边缘连通 */

if(left==0)

{

/* 左边缘连通 */

DrawPath(c1->x,c1->y, -1,c1->y, -1,c2->y, c2->x,c2->y, LineColor);

delay(6000);

DrawPath(c1->x,c1->y, -1,c1->y, -1,c2->y, c2->x,c2->y, BkGndColor);/*插除线条!*/

return true;

}

if(right==(BoardWidth-1))

{

DrawPath(c1->x,c1->y, BoardWidth,c1->y, BoardWidth,c2->y, c2->x,c2->y,

LineColor);

delay(6000);

DrawPath(c1->x,c1->y, BoardWidth,c1->y, BoardWidth,c2->y, c2->x,c2->y,

BkGndColor);/*插除线条!*/

return true;

}

for(i=left;i<=right;i++)

{

path=0;/*统计垂直的公垂线长度!*/

for(j=min(c1->y,c2->y)+1;jy,c2->y);j++)

{

path+=Board[i][j][0];

if(path>0) break;

}

if(path==0)

{

DrawPath(c1->x,c1->y, i,c1->y, i,c2->y, c2->x,c2->y, LineColor);

delay(6000);

DrawPath(c1->x,c1->y, i,c1->y, i,c2->y, c2->x,c2->y, BkGndColor);/*插除线条!*/

return true;

}

}

/*---------------(2)查找垂直方向公共区域!-----------*/

min1=max1=c1->y;

min2=max2=c2->y;

while(min1-1>=0 && Board[c1->x][min1-1][0]==0) min1--;

while(min2-1>=0 && Board[c2->x][min2-1][0]==0) min2--;

top=max(min1,min2);

while(max1+1x][max1+1][0]==0) max1++;

while(max2+1x][max2+1][0]==0) max2++;

bottom=min(max1,max2);

/* 检查两条垂直线之间是否有公垂线连通!*/

/* 可以在边缘连通 */

if(top==0)

{

/* 同在顶端消除 */

DrawPath(c1->x,c1->y, c1->x,-1, c2->x,-1, c2->x,c2->y, LineColor);

delay(6000);

DrawPath(c1->x,c1->y, c1->x,-1, c2->x,-1, c2->x,c2->y, BkGndColor);/*插除线条!*/

return true;

}

if(bottom==(BoardHeight-1))

{

DrawPath(c1->x,c1->y, c1->x,BoardHeight, c2->x,BoardHeight, c2->x,c2->y,

LineColor);

delay(6000);

DrawPath(c1->x,c1->y, c1->x,BoardHeight, c2->x,BoardHeight, c2->x,c2->y,

BkGndColor);/*插除线条!*/

return true;

}

for(j=top;j<=bottom;j++)

{

path=0;/*统计水平的公垂线长度!*/

for(i=min(c1->x,c2->x)+1; ix,c2->x); i++)

{

path+=Board[i][j][0];

if(path>0) break;

}

if(path==0)

{

/* 水平公垂线 */

DrawPath(c1->x,c1->y, c1->x,j, c2->x,j, c2->x,c2->y, LineColor);

delay(6000);

DrawPath(c1->x,c1->y, c1->x,j, c2->x,j, c2->x,c2->y, BkGndColor);/*插除线条!*/

return true;

}

}

/* 到达这里说明没有任何通路 */

return false;

}

/*Get Key Code */

int GetKeyCode()

{

int key=0;

if(bioskey(1))

{

key=bioskey(0);

}

return key;

}

/*绘制消除方块时候的连接路径!,用指定颜色!,坐标是CELL逻辑坐标!*/

void DrawPath(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int color)

{

setcolor(color);

moveto(BoardX+CellSize/2+CellSize*x1,BoardY+CellSize/2+CellSize*y1);

lineto(BoardX+CellSize/2+CellSize*x2,BoardY+CellSize/2+CellSize*y2);

lineto(BoardX+CellSize/2+CellSize*x3,BoardY+CellSize/2+CellSize*y3);

lineto(BoardX+CellSize/2+CellSize*x4,BoardY+CellSize/2+CellSize*y4);

}

/* congratulations info,the user has success finish the game ! */

void DrawGameOver(char* info)

{

/*计算棋盘的中心点*/

int cx=BoardX+CellSize*BoardWidth/2;

int cy=BoardY+CellSize*BoardHeight/2;

struct textsettingstype textInfos;

/*获取此前的文字信息*/

gettextsettings(&textInfos);

setcolor(DARKGRAY);

setfillstyle(SOLID_FILL,BLUE);

/* 文字居中 */

rectangle(cx-102,cy-22,cx+102,cy+22);

floodfill(cx,cy,DARKGRAY);

rectangle(cx-100,cy-20,cx+100,cy+20);

settextjustify(CENTER_TEXT,CENTER_TEXT);

setcolor(LIGHTBLUE);

outtextxy(cx,cy,info);

/*restore orignal text settings */

settextjustify(, );

}

/* draw a focus rect on the cell with the color */

/* 用制定颜色绘制一个选中的外边框 */

void DrawBorderRect(CELL *c,int color)

{

setcolor(color);

rectangle(BoardX+(c->x)*CellSize+1, BoardY+(c->y)*CellSize+1,

BoardX+(c->x+1)*CellSize-2, BoardY+(c->y+1)*CellSize-2);

rectangle(BoardX+(c->x)*CellSize, BoardY+(c->y)*CellSize,

BoardX+(c->x+1)*CellSize-1, BoardY+(c->y+1)*CellSize-1);

}

/* 在x,y处用指定颜色绘制键为key的 CELL,key在2,3,4,5,6,7,8,9,10,11之间随机 */

void DrawCell(int key,int x,int y,int color)

{

setcolor(color);

rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3,

BoardY+(y+1)*CellSize-3);

setfillstyle(key, color);

floodfill(BoardX+x*CellSize+3, BoardY+y*CellSize+3,color);

}

/* 擦除CELL */

void EraseCell(int x,int y)

{

setcolor(EraColor);

rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3,

BoardY+(y+1)*CellSize-3);

setfillstyle(SOLID_FILL, BkGndColor);

floodfill(BoardX+x*CellSize+3, BoardY+y*CellSize+3,EraColor);

setcolor(BkGndColor);

rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3,

BoardY+(y+1)*CellSize-3);

}

/* 初始化进度条 */

void InitProgressBar()

{

int width=CellSize*BoardWidth;

/* progress bar border rect */

setcolor(BorderColor);

rectangle(BoardX-2,PbY-2,BoardX+width+2,PbY+PbHeight+2);

/* draw a value = 100% progress bar */

setcolor(PbColor);

rectangle(BoardX,PbY,BoardX+width,PbY+PbHeight);

setfillstyle(SOLID_FILL,PbColor);

floodfill(BoardX+1,PbY+1,PbColor);

}

/* 更新进度条,设置为某个百分比 */

void UpdateProgressBar(int percent)

{

int p=percent;

int width;

if(percent<0) p=0;

else if(percent>100) p=100;

width=BoardWidth*percent/100*CellSize;

setfillstyle(SOLID_FILL,BkGndColor);

floodfill(BoardX+1,PbY+1,BorderColor);

if(width<2) return;/* too small value? */

setcolor(PbColor);

rectangle(BoardX,PbY,BoardX+width,PbY+PbHeight);

setfillstyle(SOLID_FILL,PbColor);

floodfill(BoardX+1,PbY+1,PbColor);

}

/* 初始化程序 */

void InitGame(char *bgiPath)

{

int gdriver=DETECT,gmode,i,x,y,key;

struct time sysTime;

/*清空棋盘数据!*/

memset(Board,0,sizeof(Board[0][0][0]*BoardWidth*BoardHeight*2));

/* set new seed! */

gettime(&sysTime);

srand(_hour*3600+_min*60+_sec);

/* enter graphics mode */

initgraph(&gdriver,&gmode,bgiPath);

PairsCount=BoardWidth*BoardHeight/4;

for(i=0; i

{

key=random(10)+2;

/* fill first cell of pair */

do

{

x=random(BoardWidth);

y=random(BoardHeight);

}

while(Board[x][y][0]!=0);

DrawCell(key,x,y,CellColor);

Board[x][y][0]=1;

Board[x][y][1]=key;

/* fill second cell of pair */

do

{

x=random(BoardWidth);

y=random(BoardHeight);

}

while(Board[x][y][0]!=0);

DrawCell(key,x,y,CellColor);

Board[x][y][0]=1;

Board[x][y][1]=key;

}

setcolor(YELLOW);

outtextxy(BoardX,BoardY+BoardHeight*CellSize+30,"Press ESC to Exit!");

outtextxy(BoardX,BoardY+BoardHeight*CellSize+42,"ArrowKeys to move,

Confirm.");

Enter to

outtextxy(BoardX,BoardY+BoardHeight*CellSize+54,"--by Hoodlum1980");

PbValue=100;

TotalTime=3*60; /* Total minutes. */

gettime(&sysTime);

StartTime=_min*60+_sec;

}

/* 游戏进行 */

void PlayGame()

{

int key,percent;

long curTime;

struct time sysTime;

curCell.x = curCell.y = 0;/*当前所处位置!*/

selCell.x = selCell.y = -1;/*为-1表示当前未选中*/

DrawBorderRect(&curCell, CurColor);

/*用一个循环检测按键!*/

while(key!=K_ESC)

{

/* wait until a key pressed */

while(!(key=GetKeyCode()))

{

gettime(&sysTime);

curTime=_min*60+_sec;

percent=(int)((1-(curTime-StartTime)*1.0/TotalTime)*100);

if(percent<=1)

{

DrawGameOver("YOU HAVE LOSE!");

return;

}

else if(percent!=PbValue)

{

UpdateProgressBar(percent);

PbValue=percent;/* update cache PbValue */

}

delay(1000);

}

/* 这时用户按下了某个键 */

/*需要恢复的是此前选中的cell!*/

if(curCell.x==selCell.x && curCell.y==selCell.y)

DrawBorderRect(&curCell, SelColor); /*恢复选中cell的focus痕迹 */

else

DrawBorderRect(&curCell, BkGndColor); /*擦除此前的focus痕迹 */

switch(key)

{

case K_LEFT:

curCell.x--;

if(curCell.x < 0) curCell.x += BoardWidth;

break;

case K_RIGHT:

curCell.x++;

if(curCell.x >= BoardWidth) curCell.x -= BoardWidth;

break;

case K_UP:

curCell.y--;

if(curCell.y < 0) curCell.y += BoardHeight;

break;

case K_DOWN:

curCell.y++;

if(curCell.y >= BoardHeight) curCell.y -= BoardHeight;

break;

/* 对回车键 */

case K_RETURN:

/* 如果此处没有任何cell,不处理! */

if(Board[curCell.x][curCell.y][0]==0)

break;

/* 与此前选中的位置重合,则不处理 */

if(curCell.x==selCell.x && curCell.y==selCell.y)

break;

/*如果此前没有任何选中,则设置改点为选中位置*/

if(selCell.x<0 || selCell.y<0)

{

selCell.x=curCell.x;

selCell.y=curCell.y;

DrawBorderRect(&selCell,SelColor);

continue;

}

/*如果此前已有选中,则判断是否可以消除!*/

if(FindPath(&selCell,&curCell))

{

/* 消除这两个cell!*/

EraseCell(selCell.x,selCell.y);

EraseCell(curCell.x,curCell.y);

/* 清除棋盘数据 */

Board[selCell.x][selCell.y][0]=0;

Board[selCell.x][selCell.y][1]=0;

Board[curCell.x][curCell.y][0]=0;

Board[curCell.x][curCell.y][1]=0;

/* 清除selCell */

DrawBorderRect(&selCell,BkGndColor);

selCell.x=selCell.y=-1;

/* decrease the pairs count */

PairsCount--;

if(PairsCount==0)

{

DrawGameOver("CONGRATULATIONS!");

return;

}

}

else

{

/* 不能消除这两个cell!*/

/* erase the selCell's focus rect!*/

DrawBorderRect(&selCell,BkGndColor);

selCell.x=selCell.y=-1;

}

break;

case K_ESC:

DrawGameOver("GAME OVER!");

break;

default:

break;

}

/*绘制当前focus位置*/

DrawBorderRect(&curCell, CurColor);

}

}

/* 退出程序 */

void QuitGame()

{

closegraph();

}

/* Entry Point */

int main(int argc,char *argv[])

{

InitGame("");

InitProgressBar();

PlayGame();

getch();

QuitGame();

return 0;

getch();

}


本文标签: 选中 判断 方向 水平 颜色