/*亲测DEVC++编译器完美执行*/
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>#include<time.h>
#include<conio.h>
#include<stdio.h>
void readini(FILE **fphead, int *score, char *argv[]) //创建或打开一个和运行文件对应的ini文件,读取最高纪录
{
char filename[200], *pfilename;
int flag = -1, i;
strcpy(filename, argv[0]);
for (i = 0; filename[i] != ' '; i++)
{
if ('.' == filename[i])flag = 1;
}
if (1 == flag)
{
filename[i - 1] = 'i';
filename[i - 2] = 'n';
filename[i - 3] = 'i';
}
else
{
filename[i] = '.';
filename[i + 1] = 'i';
filename[i + 2] = 'n';
filename[i + 3] = 'i';
filename[i + 4] = ' ';
}
for (; filename[i] != '\'&&i >= 0; i--)pfilename = &filename[i];
if ((*fphead = fopen(pfilename, "rb+")) == NULL)
{
if ((*fphead = fopen(pfilename, "wb+")) == NULL)
{
printf("无法创建或打开"%s"文件 ", pfilename);
system("pause");
exit(0);
}
}
else
{
fread(score, sizeof(int), 1, *fphead);
}
}
void writeini(FILE **fphead, int *score, char *argv[]) //打开一个和运行文件对应的ini文件,写入最高纪录
{
char filename[200], *pfilename;
int flag = -1, i;
strcpy(filename, argv[0]);
for (i = 0; filename[i] != ' '; i++)
{
if ('.' == filename[i])flag = 1;
}
if (1 == flag)
{
filename[i - 1] = 'i';
filename[i - 2] = 'n';
filename[i - 3] = 'i';
}
else
{
filename[i] = '.';
filename[i + 1] = 'i';
filename[i + 2] = 'n';
filename[i + 3] = 'i';
filename[i + 4] = ' ';
}
for (; filename[i] != '\'&&i >= 0; i--)pfilename = &filename[i];
if ((*fphead = fopen(pfilename, "wb+")) == NULL)
{
printf("无法写入"%s"文件,磁盘写保护! ", pfilename);
system("pause");
exit(0);
}
else
{
rewind(*fphead);
fwrite(score, sizeof(int), 1, *fphead);
fclose(*fphead);
}
}
void gotoxy(int x, int y)//光标定位,光标定位函数SetConsoleCursorPosition是左上角位置是0,0然后向左向下延伸
{
COORD pos;
pos.X = 2 * y;
pos.Y = x;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void color(int a)//颜色函数
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}
void Refresh(int q[][22], int grade, int gamespeed, int length, int score) // 输出贪吃蛇棋盘
{
int i, j;
for (i = 0; i<22; i++)
{
for (j = 0; j<22; j++)
{
if (q[i][j] == 0)//输出棋盘空白
{
gotoxy(i, j);
color(11);
printf("■");
}
if (q[i][j] == 1 || q[i][j] == 2)//输出棋盘墙壁
{
gotoxy(i, j);
color(11);
printf("□");
}
if (q[i][j] == 3)//输出蛇头
{
gotoxy(i, j);
color(14);
printf("★");
}
if (q[i][j] == 4)//输出蛇身
{
gotoxy(i, j);
color(12);
printf("◆");
}
if (q[i][j] == 5)//输出果子
{
gotoxy(i, j);
color(12);
printf("●");
}
}
if (i == 0) printf(" ***********************");
if (i == 1) printf(" 等级为:%d", grade);//显示等级
if (i == 3) printf(" 自动前进时间");
if (i == 4) printf(" 间隔为:%dms", gamespeed);//显示时间
if (i == 6) printf(" 历史最高分为:%d分", score);
if (i == 7) printf(" 你现在得分为:%d分", (length + (grade - 1) * 8) * 10);
if (i == 8) printf(" **********************");
if (i == 9) printf(" 游戏说明:");
if (i == 10) printf(" (1)用小键盘方向键控制");
if (i == 11) printf(" 蛇头运动方向;");
if (i == 12) printf(" (2)蛇每吃一个果子蛇身");
if (i == 13) printf(" 增加一节;");
if (i == 14) printf(" (3)蛇咬到自己或碰到墙");
if (i == 15) printf(" 壁游戏结束。");
if (i == 18) printf(" **********************");
}
}
int main(int argc, char *argv[])
{
int score;
FILE *fpini;//*fpini 信息文件
int grade = 1, length = 4; //设置初始等级和蛇的初始长度
int first = 0;
readini(&fpini, &score, argv);//读取ini文件的最高纪录
while (1)
{
int tcsZuobiao[2][500]; //蛇的坐标数组
int tcsQipan[22][22]; // 贪吃蛇棋盘是一个二维数组(如22*22,包括墙壁)
int i, j, directiontemp;
int x1, y1; // 随机出果子
int head = 3, tail = 0;//标示蛇头和蛇尾的数组偏移量
int timeover = 1, otherkey = 1;//初始化超时时间和按键判断参数
char direction = 77; // 设置初始情况下,向右运动
int x, y;//保存蛇头坐标到x,y变量
long start, starttemp;
int grade = 1, length = 4; //设置初始等级和蛇的初始长度
int first = 0;
int gamespeed = 500; //设置初始前进时间间隔
if (score<0)//最高成绩小于零设置为零,初建文件会是负数
score = 0;
for (i = 1; i <= 20; i++)
for (j = 1; j <= 20; j++)
tcsQipan[i][j] = 0; //贪吃蛇棋盘相应坐标标上中间空白部分的标志0
for (i = 0; i <= 21; i++)
tcsQipan[0][i] = tcsQipan[21][i] = 1; //贪吃蛇棋盘相应坐标标上上下墙壁的标志1
for (i = 1; i <= 20; i++)
tcsQipan[i][0] = tcsQipan[i][21] = 2; //贪吃蛇棋盘相应坐标标上左右墙壁的标志2
if (first == 0)
{
for (i = 0; i<4; i++)
{
tcsZuobiao[0][i] = 1;//蛇身和蛇头的x坐标
tcsZuobiao[1][i] = i + 1;//蛇身和蛇头的y坐标
}
first = 1;
for (i = 1; i <= 3; i++)
tcsQipan[1][i] = 4; //蛇身
tcsQipan[1][4] = 3; //蛇头
}
srand(time(0));//设置随机种子
do
{
x1 = rand() % 20 + 1;
y1 = rand() % 20 + 1;
} while (tcsQipan[x1][y1] != 0);//如果不是在空白处重新出果子
tcsQipan[x1][y1] = 5;//贪吃蛇棋盘相应坐标标上果子的标志5
color(12);
printf(" 贪吃蛇游戏即将开始 ! ");//准备开始
for (i = 3; i >= 0; i--)
{
start = clock();
while (clock() - start <= 1000);
system("cls");
if (i>0)
printf(" 进入倒计时:%d ", i); //倒计时显示
else
Refresh(tcsQipan, grade, gamespeed, length, score); //初始棋盘显示
}
x = tcsZuobiao[0][head];
y = tcsZuobiao[1][head];//保存蛇头坐标到x,y变量
while (1)//运行一局游戏
{
start = clock();
while ((timeover = ((starttemp = clock()) - start <= gamespeed)) && !kbhit());//如果有键按下或时间超过自动前进时间间隔则终止循环
if (direction == 72 || direction == 80 || direction == 75 || direction == 77)
directiontemp = direction;//保留上一次方向按键
//starttemp=gamespeed+start-starttemp;//保留停留时间
if (timeover)
{
if ((direction = getch()) == -32)
direction = getch();
}
if (!(direction == 72 || direction == 80 || direction == 75 || direction == 77))
{
otherkey = 0;// 按键非方向键,otherkey设置为0
}
else
{
otherkey = 1;// 按键为方向键,otherkey设置为1
}
if (direction == 72 && directiontemp == 80)//忽略反方向按键
{
direction = 32;
otherkey = 0;
//start = clock();
//while(clock()-start<=starttemp);
}
else if (direction == 80 && directiontemp == 72)
{
direction = 32;//设置按键为非方向键
otherkey = 0;// 按键为非方向键,otherkey设置为0
// start = clock();
//while(clock()-start<=starttemp);//补偿等待时间
}
else if (direction == 75 && directiontemp == 77)
{
direction = 32;
otherkey = 0;
//start = clock();
//while(clock()-start<=starttemp);
}
else if (direction == 77 && directiontemp == 75)
{
direction = 32;
otherkey = 0;
//start = clock();
//while(clock()-start<=starttemp);
}
switch (direction)//判断方向键
{
case 72: x = tcsZuobiao[0][head] - 1; y = tcsZuobiao[1][head]; break; // 向上
case 80: x = tcsZuobiao[0][head] + 1; y = tcsZuobiao[1][head]; break; // 向下
case 75: x = tcsZuobiao[0][head]; y = tcsZuobiao[1][head] - 1; break; // 向左
case 77: x = tcsZuobiao[0][head]; y = tcsZuobiao[1][head] + 1; break; // 向右
default: break;
}
if (x == 0 || x == 21 || y == 0 || y == 21) // 蛇头碰到墙壁,结束本局游戏
{
gotoxy(22, 12);
printf(" 游戏已结束! ");
if (score >= (length + (grade - 1) * 8) * 10)//判断是否破记录
{
gotoxy(10, 7);
color(12);
printf("闯关失败 加油耶! ");
fclose(fpini);//关闭ini文件
}
else
{
gotoxy(10, 7);
color(12);
printf("恭喜您打破记录 ");
score = (length + (grade - 1) * 8) * 10;
writeini(&fpini, &score, argv);//写入ini文件的最高纪录
}
gotoxy(23, 12);
printf("按回车键重新开始,按ESC退出游戏 ");//显示的提示
break;//退出该局游戏
}
if (tcsQipan[x][y] != 0 && !(x == x1&&y == y1) && tcsQipan[x][y] != 3) // 蛇头碰到蛇身,结束本局游戏
{
gotoxy(22, 12);
printf(" 游戏已结束! ");
if (score >= (length + (grade - 1) * 8) * 10)//判断是否破记录
{
gotoxy(10, 7);
color(12);
printf("闯关失败 加油耶! ");
fclose(fpini);//关闭ini文件
}
else
{
gotoxy(10, 7);
color(12);
printf("恭喜您打破记录 ");
score = (length + (grade - 1) * 8) * 10;
writeini(&fpini, &score, argv);//写入ini文件的最高纪录
}
gotoxy(23, 12);
printf("按回车键重新开始,按ESC退出游戏 ");//显示的提示
break;//退出该局游戏
}
/*
游戏运行时的核心算法开始
*/
if (x == x1 && y == y1) // 吃果子,长度加1
{
length++;
if (length >= 8)//长度大于等于8重新计算长度,等级加1
{
length -= 8;//重新计算长度
grade++;//等级加1
if (gamespeed>50)//控制最快速度为50
gamespeed = 550 - grade * 50; // 改变自动前进时间间隔
}
tcsQipan[x][y] = 3;//贪吃蛇棋盘相应坐标现在蛇头标志改为蛇头标志3
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]] = 4;//贪吃蛇棋盘相应坐标原来蛇头标志改为蛇身标志4
head = (head + 1) % 400;//防止数组越界
tcsZuobiao[0][head] = x;//蛇头的x坐标
tcsZuobiao[1][head] = y;//蛇头的y坐标
do//随机出果子
{
x1 = rand() % 20 + 1;
y1 = rand() % 20 + 1;
} while (tcsQipan[x1][y1] != 0);//如果不是在空白处重新出果子
tcsQipan[x1][y1] = 5;//贪吃蛇棋盘相应坐标标上果子的标志5
gotoxy(22, 12);
printf(" 游戏进行中! ");
Refresh(tcsQipan, grade, gamespeed, length, score);
}
else // 不吃果子
{
if (otherkey)
{
tcsQipan[tcsZuobiao[0][tail]][tcsZuobiao[1][tail]] = 0;
tail = (tail + 1) % 400;//防止数组越界
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]] = 4;
head = (head + 1) % 400;//防止数组越界
tcsZuobiao[0][head] = x;//蛇头的x坐标
tcsZuobiao[1][head] = y;//蛇头的y坐标
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]] = 3;
gotoxy(22, 12);
printf(" 游戏进行中! ");
Refresh(tcsQipan, grade, gamespeed, length, score);
}
else
{
gotoxy(22, 12);
printf(" 游戏暂停中! ");
}
}
/*
游戏运行时的核心算法结束
*/
}
while (1)
{
while (!kbhit());
if ((direction = getch()) == 13)//按回车键开始下一局
break;
if (direction == 27)//按ESC退出游戏
exit(0);
}
system("cls");//清除屏幕重新开始
}
return 0;
}