文档库 最新最全的文档下载
当前位置:文档库 › C语言扫雷

C语言扫雷

#include
#include
#include
#include
#include /*load getch*/
#include
typedef long ttime;

void count_ij_by_k(int k,int *i,int *j);
int count_k_by_ij(int i,int j);
void count_mines_around(); /*数周围雷的个数*/
void count_xy_by_ij(int i,int j,int *x,int *y); /*计算当前光标所在位置的坐标*/
void count_mines_around_in(int pk,int i,int j); /**/
void dig_mine(int i,int j);/*挖完雷块之后要标记*/
void dig_mine_1(int i,int j);/*挖完雷块之后要标记*/
void dig_mine_2(int i,int j);/*挖完雷块之后要标记*/
void dig_mine_3(int i,int j);/*挖完雷块之后要标记*/
void disp_all_mines();
void disp_all_number();
void disp_gameover(int n);
void disp_number(int i,int j);/*要么0,-1,1~8就这三种情况,只显示1~8的情况*/
void draw_box(int x1,int y1,int x2,int y2,int type); /* draw a box */
void draw_head_bar(int x0,int y0);
void draw_mine(int i,int j); /* 画出雷的图样 */
void draw_flag(int i,int j);
void draw_mine_region(); /* draw mine region */
void init_system(); /* initialize system */
void setmines();
void sweepmines(); /* sweep mine */
void digui(int i,int j);
void disp_time(ttime t);
void disp_leftover_minenum();
int is_over();
void draw_cursor(int i,int j);

#define WIDTH 20 /*小雷方块边长WIDTH=20*/
#define MINE -1 /*有雷的地方置为-1*/

#define ESC 283
#define UP 18432
#define DOWN 20480
#define LEFT 19200
#define RIGHT 19712
#define TAB 3849
#define SPACE 14624
#define m 12909
#define M 12877

int m_maxx,m_maxy;
int row=10,col=20; /*雷区的大小*/
int mx0,my0; /*雷区左上角坐标*/
int *mymine;
int ok=10*20; /*一维数组*/
int minenumber=40; /*有30个雷块*/
int digged=0;
int marked=0;

/***************************************************************
** function : dig_mine
** description: dig mine
** parameters : i: row
** j: col
***************************************************************/

main()
{
init_system(); /* 初始化图形系统 */
draw_mine_region(); /*画雷区布局图*/

setmines(); /*安雷*/
count_mines_around(); /*数周围的雷*/
/* disp_all_number(); */
sweepmines(); /*清雷*/
getch();
free(mymine);
closegraph(); /* close system */
getch();
}

void init_system() /* initialize system */
{
int gdriver=DETECT,gmode;
initgraph(&gdriver,&gmode,""); /*初始化图形系统*/

m_maxx=getmaxx();
m_maxy=getmaxy();
mymine=(int *)malloc(ok);
mx0=(m_maxx-col*(WIDTH+1)+1)/2;
my0=(m_maxy-row*(WIDTH+1)+1)/2;
}

void count_mines_around() /*数周围雷的个数*/
{
int k,i,j;
for(k=0;k{
if(mymine[k]==MINE) /*此块如果是雷,就跳过,

判断下一个块*/
continue;
count_ij_by_k(k,&i,&j);

count_mines_around_in(k,i-1,j-1); /*周围8块*/
count_mines_around_in(k,i-1,j);
count_mines_around_in(k,i-1,j+1);
count_mines_around_in(k,i,j-1);
count_mines_around_in(k,i,j+1);
count_mines_around_in(k,i+1,j-1);
count_mines_around_in(k,i+1,j);
count_mines_around_in(k,i+1,j+1);
}
}

void count_mines_around_in(int pk,int i,int j) /**/
{
int k;
if(i>=1&&i<=row&&j>=1&&j<=col)
{
k=count_k_by_ij(i,j);
if(mymine[k]==MINE)
mymine[pk]++; /*因为不是雷块,说明是0,而不是-1*/
}
}


void draw_mine_region() /* draw mine region */
{
int i,j,x,y;
draw_head_bar(mx0,my0);
y=my0;
for(i=1; i<=row; i++)
{
x=mx0;
for(j=1; j<=col; j++)
{
draw_box(x,y,x+WIDTH,y+WIDTH,1); /* draw a box */
x+=WIDTH+1;
}
y+=WIDTH+1;
}
}


void draw_box(int x1,int y1,int x2,int y2,int type) /* draw a box */
{
setcolor(WHITE);
rectangle(x1,y1,x2,y2);
setfillstyle(SOLID_FILL,LIGHTGRAY);
floodfill((x1+x2)/2,(y1+y2)/2,WHITE);

if (type==1) setcolor(WHITE);
else setcolor(DARKGRAY);

line(x1,y1,x2,y1); /* 1是凸出来,0是凹进去 */
line(x1,y1,x1,y2);
line(x1+1,y1+1,x2-1,y1+1);
line(x1+1,y1+1,x1+1,y2-1);

if (type==1) setcolor(DARKGRAY);
else setcolor(WHITE);

line(x1,y2,x2,y2);
line(x2,y1,x2,y2);
line(x1+1,y2-1,x2-1,y2-1);
line(x2-1,y1+1,x2-1,y2-1);
}


void draw_head_bar(int x0,int y0)
{
int mwidth,mhight;

mwidth=col*(WIDTH+1)-1;
mhight=row*(WIDTH+1)-1;

draw_box(x0-4,y0-32,x0+mwidth+2,y0+mhight+2,1);
draw_box(x0-2,y0-32,x0+mwidth+2,y0-2,1);
draw_box(mx0+10,my0-30,mx0+74,my0-4,0); /*左上角的框*/
draw_box(x0+mwidth-60,y0-30,x0+mwidth-10,y0-4,0);/*右上角的框*/
}

void setmines()
{
int i,k;
int mcount=0; /*计算当前雷数*/

for(i=0;imymine[i]=0;

randomize(); /*初始化随机数发生器*/
while(mcount{
k=random(ok);

if(0==mymine[k]) /*防止产生相同的随机数的影响*/
{
mymine[k]=MINE;
mcount++;
}
}
}

void sweepmines() /* sweep mine */
{
int key=0; /*/键盘的每个键都有自己的标识码(TC16位,低8位是ASC码,高8位为扫描码)*/
int i,j,x,y;
ttime mt,mtl=0;
int mflag=0;

disp_leftover_minenum();
i=1; /*初始时,默认在第一个方块上*/
j=1;
draw_cursor(i,j); /* 此句只为第一个光标服务 */

mt=time(NULL);

while(key!=ESC)
{
if((mt!=time(NULL)) && mflag!=0)
{
mt=time(NULL);
mtl++;
disp_time(mtl);
}

key=bioskey(1); /*当cmd是1,bioskey()查询是否按下一个键,若按下一个键则返回非零值,并且不删除此按键的缓冲,否则返回0。*/
if(key==0)

continue;



key=bioskey(0); /*接收上面按键的缓冲,并且删除此缓冲*/
mflag=1; /*flag用来标记是否有按键按下*/
draw_cursor(i,j); /*这是第二个画光标,目的进行异或运算,使其恢复原样*/

switch(key)
{
case UP:
if(i==1) i=1;
else i=i-1;
break;
case DOWN:
if(i==row) i=row;
else i=i+1;
break;
case LEFT:
if(j==1) j=1;
else j=j-1;
break;
case RIGHT:
if(j==col) j=col;
else j+=1;
break;
case SPACE:
dig_mine(i,j);
key=is_over();
break;
case m:
case M:
draw_flag(i,j);
key=is_over();
break;
}
draw_cursor(i,j);
}
}

void draw_cursor(int i,int j)
{
int x,y;

count_xy_by_ij(i,j,&x,&y);

setcolor(LIGHTGRAY);
setlinestyle(DOTTED_LINE,0,1);
setwritemode(1);
rectangle(x+4,y+6,x+WIDTH-4,y+WIDTH-4);
setlinestyle(SOLID_LINE,0,1);
setwritemode(0);
}

int is_over()
{
if((digged==ok-minenumber) && (marked==minenumber))
{
disp_gameover(1);
getch();
return (ESC);
}
else return (0);
}

void disp_leftover_minenum()
{
char str[5]={0};

draw_box(mx0+10,my0-30,mx0+74,my0-4,0);

sprintf(str,"%4d",minenumber-marked);
setcolor(RED);
settextstyle(DEFAULT_FONT,0,2);
outtextxy(mx0+10,my0-25,str);
}

void disp_time(ttime t)
{
char str[5];
int mwidth;

if(t>999) /* because max is 1000ms */
{
return;
}
mwidth=col*(WIDTH+1)-1;
draw_box(mx0+mwidth-60,my0-30,mx0+mwidth-10,my0-4,0);
sprintf(str,"%-3ld",t);
setcolor(RED);
settextstyle(DEFAULT_FONT,0,2);
outtextxy(mx0+mwidth-55,my0-25,str);
}

void dig_mine(int i,int j)/*挖完雷块之后要标记*/
{
int k;
int x,y;

k=count_k_by_ij(i,j);
if(mymine[k]==MINE) /*直接space挖到雷*/
{
dig_mine_1(i,j);
mymine[k]-=20;
}
if(mymine[k]>0 && mymine[k]<9)/* space的是没挖过的块 */
{
dig_mine_2(i,j);
mymine[k]+=20; /* 有的已经挖完之后,要把它标记,标明它已被挖,加个20就是如此 */
}
if(mymine[k]==0)/*它本身不是雷,它周围8块也都不是雷*/
{
dig_mine_3(i,j);
}
}

void dig_mine_2(int i,int j)
{
int x,y;

count_xy_by_ij(i,j,&x,&y);
draw_box(x,y,x+WIDTH,y+WIDTH,0); /* 让块凹下去 */
disp_number(i,j); /* 显示当前 块 周围雷的个数 */

digged++;
}

void dig_mine_1(int i,int j)
{
int x,y;

disp_all_mines();
count_xy_by_ij(i,j,&x,&y);
setcolor(RED);
setlinestyle(SOLID_LINE,0,3); /* 先显示所有雷的图样,再在当前块上画 红X */
line(x+2,y+2,x+WIDTH-2,y+WIDTH-2);
line(x+WIDTH-2,y+2,x+2,y+WIDTH-2);
setlinestyle(SOLID_LINE,0,1);
disp_gameover(0);
exit(0);
}

void dig_mine_3(int i,int j)
{
int k;
int x,y;

k=count_k_by

_ij(i,j);

if(mymine[k]<0 || mymine[k]>8) /* 说明是雷块或者是0~8的已经挖出的数字 */
return;

if(mymine[k]>0 && mymine[k]<9) /*如果还没被挖,那就先挖,再标记*/
{
disp_number(i,j);
mymine[k]+=20;
digged++;
return;
}
if(mymine[k]==0)
{
count_xy_by_ij(i,j,&x,&y);
draw_box(x,y,x+WIDTH,y+WIDTH,0);
mymine[k]+=20; /*防止递归被弹回来*/
digged++;

digui(i-1,j-1); /*周围8块*/
digui(i-1,j);
digui(i-1,j+1);
digui(i,j-1);
digui(i,j+1);
digui(i+1,j-1);
digui(i+1,j);
digui(i+1,j+1);
}
}

void digui(int i,int j)
{
if(i>=1&&i<=row&&j>=1&&j<=col)
dig_mine_3(i,j);
}

void draw_flag(int i,int j)
{
int x,y,k;
count_xy_by_ij(i,j,&x,&y);
k=count_k_by_ij(i,j);

if(mymine[k]>=MINE&&mymine[k]<=8) /* -1~~8,draw flag */
{
mymine[k]+=100; /* take a mark from others */
setcolor(RED);
setwritemode(0);/* the mode of cover */
rectangle(x+4,y+4,x+WIDTH*3/4,y+WIDTH/2);
setfillstyle(SOLID_FILL,RED);
floodfill(x+WIDTH/2,y+WIDTH/4,RED);
setcolor(BLACK);
setlinestyle(SOLID_LINE,0,2);
line(x+4,y+4,x+4,y+WIDTH-4);

marked++;
disp_leftover_minenum();
}
else if(mymine[k]>=90) /* 不加else ,而只有if让我蛋碎一地 ,因为执行上面的if之后,加了100,自然符合下面的if条件 */
{
mymine[k]-=100;/*恢复数组原来值*/
disp_leftover_minenum();
draw_box(x,y,x+WIDTH,y+WIDTH,1);/* 使此方块恢复原样,所以是 1 */

marked--;
disp_leftover_minenum();
}
}

void draw_mine(int i,int j) /* 画出雷的图样 */
{
int x,y;

count_xy_by_ij(i,j,&x,&y);

draw_box(x,y,x+WIDTH,y+WIDTH,1);
setcolor(BLACK);
circle(x+WIDTH/2,y+WIDTH/2,WIDTH/3);
setfillstyle(SOLID_FILL,BLACK);
floodfill(x+WIDTH/2,y+WIDTH/2,BLACK);
}


int count_k_by_ij(int i,int j) /*当二维数组用一维数组存储时,互相的下标关系*/
{
return((i-1)*col+j-1);
}

void count_ij_by_k(int k,int *i,int *j) /*当二维数组用一维数组存储时,互相的下标关系*/
{
*i=k/col+1;
*j=k%col+1;
}

void count_xy_by_ij(int i,int j,int *x,int *y) /*计算当前光标所在位置的坐标*/
{
*x=mx0+(j-1)*(WIDTH+1);
*y=my0+(i-1)*(WIDTH+1);
}

void disp_gameover(int n)
{
int x,y;
char str[]="GAME OVER!!";
char arr[]="YOU WIN!";

setcolor(RED);
settextstyle(DEFAULT_FONT,HORIZ_DIR,4);
x=mx0+(col*(WIDTH+1)-1-textwidth(str))/2;
y=my0+(row*(WIDTH+1)-1-textheight(str))/2;
if(n==0)
{
outtextxy(x,y,str);
}
else
{
outtextxy(x,y,arr);
}
getch();
exit(0);
}

void disp_all_number()
{
int i,j;

for(i=1; i<=row; i++)
{
for(j=1; j<=col; j++)
{
disp_number(i,j);
}
}
}
void disp_number(int i,int j)/*要么0,-1,1~8就这三种情况,只显示1~8的情况*/
{
int k,x,y;
char str[2];

k=count

_k_by_ij(i,j);
count_xy_by_ij(i,j,&x,&y);

if(mymine[k]==MINE) /*-1不显示*/
return;

/* draw_box(x,y,x+WIDTH,y+WIDTH,0);*/ /* 作用未知 */

if(mymine[k]==0) /* 周围没雷,本身也不是雷 */
return;

settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
sprintf(str,"%d",mymine[k]);
x=x+(WIDTH-textwidth(str))/2;
y=y+(WIDTH-textheight(str))/2;
switch(mymine[k])
{
case 1:
setcolor(BLUE);
break;
case 2:
setcolor(GREEN);
break;
case 3:
setcolor(RED);
break;
case 4:
setcolor(CYAN);
break;
case 5:
setcolor(YELLOW);
break;
case 6:
setcolor(LIGHTCYAN);
break;
case 7:
setcolor(BROWN);
break;
case 8:
setcolor(MAGENTA);
break;
}
outtextxy(x,y,str);
}

void disp_all_mines()
{
int k,i,j;
for(k=0; k{
if(MINE==mymine[k])
{
count_ij_by_k(k,&i,&j);
draw_mine(i,j);
}
}
}

相关文档
相关文档 最新文档