www.pudn.com > snake.rar > snake.C


/*---------------------------------------------------------------------------------------------------------------------- 
 * 对snakemap矩阵元素含义的定义: 
 *       0: 空 
 *      -1: 障碍 
 *      -2: 食物 
 *    正数: 有可能是蛇节点(程序正常就是蛇节点) 
 * 
 *    对于正数 
 *    个位=1/2/3/4 = 上/下/左/右 
 *    十位=1/0 = 曾经吃过食物还没加长度的/最近没在这个位置吃过食物 
 * 
 *    不在定义之外的正数应该不会出现吧 
 * 
 ---------------------------------------------------------------------------------------------------------------------*/ 
 
#include  
#include  
#include  
#include  
#include  
 
/*  几个键盘的ASCII码值             */ 
/*  上下左右键盘游戏                */ 
/*  可以改成其他的ASCII值来更换热键 */ 
#define UP             0x48 
#define DOWN           0x50 
#define LEFT           0x4b 
#define RIGHT          0x4d 
 
 
 
 
 
/*-定义游戏格子矩阵,可以配置修改游戏矩阵-*/ 
#define height 9 
#define width  16 
int snakemap[height][width]= 
{ 
/*----------0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 
 */ 
/* 0 */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
/* 1 */   { 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
/* 2 */   { 0, 0, 0, 0, 0, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, 
/* 3 */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
/* 4 */   { 0, 0, 0, 0, 0, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, 
/* 5 */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
/* 6 */   { 0, 0, 0, 0, 0, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, 
/* 7 */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
/* 8 */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
}; 
 
#define map_left     160                      /*界面左边界的x像素   */ 
#define map_top      125                      /*界面左边界的y像素   */ 
#define blcok_size   15                       /*一个蛇身格子的边长  */ 
#define margin_size1  1                       /*格子之间留得空隙长度*/ 
#define margin_size2  1                       /*格子之间留得空隙长度*/ 
 
#define snakecolor    LIGHTBLUE               /*蛇体颜色 */ 
#define headcolor     GREEN                   /*蛇头颜色 */ 
#define barriercolor  BROWN                   /*障碍颜色 */ 
#define bgcolor       WHITE                   /*背景颜色 */ 
#define foodcolor     MAGENTA                 /*食物颜色 */ 
#define margin_color1 GREEN                   /*间隔1颜色*/ 
#define margin_color2 bgcolor                 /*间隔2颜色*/ 
 
/*定义贪吃蛇控制结构*/ 
struct snakecotrol 
{ 
	int head_i; /*蛇头*/ 
	int head_j; 
	int tail_i; /*蛇尾*/ 
	int tail_j; 
}snakecotrol; 
 
/* 当前移动方向 : 默认最开始往右边           */ 
/* 移动方向信心将会记录在矩阵元素中          */ 
/* 1/2/3/4 = 上/下/左/右                     */ 
int derection=4; 
 
/* 记录当前map中空白格的数量,即0的数量       */ 
/* 游戏结束,和随机产生食物将要用到这个       */ 
/* spacenum的初始值在mian函数开始设置        */ 
int spacenum; 
 
/* 延迟功能的设计:                           */ 
/* if(上次触发时间 - 此刻) > 基本等待 * 倍数 */ 
/*     触发并且记录此刻时间                  */ 
/*   else                                    */ 
/*      不触发                               */ 
 
#define persec 30                                          /*基本等待时间,单位百分之一秒                              */ 
int mulpersec = 1;                                         /*等待时间的倍数                                           */ 
int history_sec = 0;                                       /*上次触发的秒值                                           */ 
int history_persec = 0;                                    /*上次触发的百分之一秒值                                   */ 
 
int trigger();                                             /*触发函数,返回1触发,返回0不触发                           */ 
void show(int i,int j,int color,int bargin1, int bargin2); /*打印一个格子,坐标i,坐标j,颜色,间隔色                     */ 
int anlyse(int i,int j);                                   /*分析元素的类型                                           */ 
void clear(int i,int j);                                   /*清理一个格子的显示                                       */ 
void getnextpos(int *i,int *j,int d);                      /*根据蛇的位置,和当时移动方向,取得下一个位置               */ 
int  mov();                                                /*做一次移动,mov成功返回1,继续游戏,mov失败返回-1,游戏结束  */ 
int genfood();                                             /*产生食物,如果没有空白位置来产生食物,则游戏结束           */ 
 
void main() 
{ 
    int gameoversign = 0; 
    int derectionback = derection;                         /*不能对任意一次按键就更新全局变量derection,所以设置备份    */ 
    int i,j; 
    char keyboard_hit; 
 
    /*初始化显示器图形模式: 640 X 480  */ 
    int driver=VGA,mode=VGAHI; 
    registerbgidriver(EGAVGA_driver); 
    initgraph(&driver,&mode,"c:\\tc"); 
    setbkcolor(bgcolor); 
 
    /*初始化随机数种子用于生成随机食物 */ 
    srand((unsigned)time(NULL)); 
 
    /*游戏地图初始化,并初始化空白格数量*/ 
	spacenum = 0; 
    for (j = 0; j < width; j++){ 
        for (i = 0; i < height; i++){ 
            if (snakemap[i][j] == 0){/*空白*/ 
                spacenum++; 
                show(i, j, bgcolor,margin_color1,margin_color2); 
            }else if(snakemap[i][j] == -1){/*障碍*/ 
                show(i, j, barriercolor,margin_color1,margin_color2); 
            }else if (snakemap[i][j] == -2){/*食物*/ 
                show(i, j, foodcolor,margin_color1,margin_color2); 
            }else{ 
                show(i, j, snakecolor,margin_color1,margin_color2);/*蛇*/ 
            } 
        } 
    } 
 
    /*初始化贪吃蛇控制结构*/ 
    /*蛇头(1,1),蛇尾(0,1)*/ 
    snakecotrol.head_i = 1; 
    snakecotrol.head_j = 1; 
    snakecotrol.tail_i = 1; 
    snakecotrol.tail_j = 0; 
 
	/*最开始的两节蛇,位置要与上面的数组一致*/ 
    show(snakecotrol.head_i,snakecotrol.head_j,snakecolor,margin_color1,margin_color2); 
    show(snakecotrol.tail_i,snakecotrol.tail_j,snakecolor,margin_color1,margin_color2); 
 
    /*产生食物*/ 
    genfood(); 
 
    /*游戏循环*/ 
    while (gameoversign == 0){ 
        /*如果有合法按键则接受键盘字符*/ 
        if (kbhit()!=0){ 
            keyboard_hit = getch(); 
            switch(keyboard_hit) 
            { 
                /*设置derectionback,的目的是为了多次接受输入,最后再更新全局量*/ 
                case UP:    {if (derection != 2) derectionback = 1;break;} 
                case DOWN:  {if (derection != 1) derectionback = 2;break;} 
                case LEFT:  {if (derection != 4) derectionback = 3;break;} 
                case RIGHT: {if (derection != 3) derectionback = 4;break;} 
            }; 
        } 
 
        /*如果到了触发时间就mov()*/ 
        if (trigger() == 1){ 
            /*更新移动方向*/ 
            derection = derectionback; 
	    /*移动*/ 
            if (mov() == -1){ 
                gameoversign = 1; 
            } 
        } 
    } 
	/*关闭图形模式*/ 
	closegraph(); 
} 
 
int genfood() 
{ 
    int i = 0,j = 0; 
    int v; 
    if (spacenum == 0){ 
        return -1;/*游戏结束*/ 
    } 
 
    v =  rand() % spacenum + 1; 
 
    while(v > 0){ 
        if(snakemap[i][j] == 0){ 
            if (--v == 0) 
                break; 
        } 
 
        if(j < width - 1){ 
			j++; 
		}else{ 
			j=0; i++; 
		} 
	} 
 
        if (v != 0 || i < 0 || i >= height || j < 0 || j >= width){ 
            printf("genfood() error: i = %d, j = %d, v = %d", i, j, v); 
            getch(); 
        } 
 
        /*产生食物*/ 
        spacenum--; 
        snakemap[i][j] = -2; 
        show(i, j, foodcolor, margin_color1,margin_color2); 
        return 1; 
} 
 
int mov() 
{ 
    int i = snakecotrol.head_i, j = snakecotrol.head_j; 
    int r; 
 
    /*处理蛇尾*/ 
    i = snakecotrol.tail_i, j = snakecotrol.tail_j; 
    if (snakemap[i][j]/10 > 0){ 
        /*加长*/ 
        snakemap[i][j] -= 10; 
    }else{ 
        /*不用加长*/ 
        clear(i,j); 
        getnextpos(&i,&j,snakemap[i][j]%10); 
        snakemap[snakecotrol.tail_i][snakecotrol.tail_j] = 0; 
        snakecotrol.tail_i = i; 
        snakecotrol.tail_j = j; 
    } 
 
    /*处理蛇头*/ 
    i = snakecotrol.head_i; 
    j = snakecotrol.head_j; 
    show(i,j,snakecolor,margin_color1,margin_color2); 
    getnextpos(&i,&j,derection); 
    r = anlyse(i,j); 
    if (r != 0 && r != -2){ 
        return -1;/*移动到的地方非空非食物则撞了,游戏结束*/ 
    } 
 
    snakemap[snakecotrol.head_i][snakecotrol.head_j] /= 10; 
    snakemap[snakecotrol.head_i][snakecotrol.head_j] *= 10; 
    snakemap[snakecotrol.head_i][snakecotrol.head_j] += derection; 
    show(i,j,headcolor,margin_color1,margin_color2); 
    snakecotrol.head_i = i; 
    snakecotrol.head_j = j; 
 
    if (r == -2){ 
        snakemap[snakecotrol.head_i][snakecotrol.head_j] = 0; 
        snakemap[snakecotrol.head_i][snakecotrol.head_j] += 10; 
        if(genfood() == -1){ 
            return -1; 
        } 
    } 
 
    return 1; 
} 
void getnextpos(int *i, int *j, int d) 
{ 
    /*根据方向移动*/ 
    switch(d) 
    { 
        case 1:{(*i)--;}break; 
        case 2:{(*i)++;}break; 
        case 3:{(*j)--;}break; 
        case 4:{(*j)++;}break; 
    } 
    /*处理越边界情况*/ 
    if (*i<0) 
        *i = height-1; 
    else if(*i>= height) 
        *i = 0; 
    else if(*j<0) 
        *j = width-1; 
    else if(*j>= width) 
        *j = 0; 
} 
 
int anlyse(int i, int j) 
{ 
    int x; 
    x = snakemap[i][j]; 
 
    if (x == 0){ 
        return 0;/*空*/ 
    }else if(x == -1){ 
        return -1;/*障碍*/ 
    }else if (x == -2){ 
        return -2;/*食物*/ 
    }else if(x > 0 && x < 9 && (x%10) >= 1 && (x%10) <= 4){ 
        return 1;/*蛇身*/ 
    }else if((x/10) > 0 && (x%10) >= 1 && (x%10) <= 4){ 
        return 2;/*蛇身,因在此处吃过食物,待加长*/ 
    }else{ 
        printf("anlyse ERROR elem : %d",x); 
        getch(); 
        return 100; 
    } 
} 
 
void clear(int i,int j) 
{ 
    show(i,j,bgcolor,margin_color1,margin_color2); 
} 
 
void show(int i,int j,int color,int bargin1, int bargin2) 
{ 
    int x1,x2,x3,x4; 
    int s_left,s_top; 
    x1 = blcok_size; 
    x2 = margin_size1; 
    x3 = margin_size2; 
    x4 = x1 + x2 + x2 + x3 + x3; 
 
    s_left = map_left + j * x4; 
    s_top = map_top + i * x4; 
 
    /* 打印间隔1 */ 
    setfillstyle(SOLID_FILL,bargin1); 
    bar(s_left, s_top, s_left+x4, s_top+x2); 
    bar(s_left, s_top + x4 - x2, s_left + x4, s_top + x4); 
    bar(s_left, s_top, s_left+x2, s_top+x4); 
    bar(s_left+x4-x2,s_top,s_left+x4,s_top+x4); 
 
    /* 打印间隔2 */ 
    s_left = s_left + x2; 
    s_top = s_top + x2; 
    x4 -= x2*2; 
    setfillstyle(SOLID_FILL,bargin2); 
    bar(s_left, s_top, s_left+x4, s_top+x3); 
    bar(s_left, s_top + x4 - x3, s_left + x4, s_top + x4); 
    bar(s_left, s_top, s_left+x3, s_top+x4); 
    bar(s_left+x4-x3,s_top,s_left+x4,s_top+x4); 
 
    /* 打印方块 */ 
    s_left = s_left + x3; 
    s_top = s_top + x3; 
    x4 -= x3*2; 
    setfillstyle(SOLID_FILL,color); 
    bar(s_left,s_top,s_left+x4,s_top+x4); 
} 
 
int trigger() 
{ 
    int d; 
    struct time now; 
    gettime(&now); 
    d = (now.ti_sec + 60 - history_sec) % 60; 
    d = (d * 100 + now.ti_hund - history_persec); 
    if (d > persec * mulpersec){ 
        history_sec = now.ti_sec; 
        history_persec = now.ti_hund; 
        return 1;/*触发*/ 
    }else{ 
        return 0;/*不触发*/ 
    } 
}