#include <iostream>
#include <list>//使用双向链表
#include <cstdio>
#include <cstring>
#include <Windows.h>//使用windows API函数(1.本代码使用函数来更改dos窗口标题,使美观2.使用COORD)
#include <string>
#include <ctime>//随机化种子,达到随机生成食物的目的
#include <conio.h>
#include <fstream>
#include <vector>//不定长数组用来储存从文件中读取的成绩
#include <algorithm>//用sort
#include <sstream>//用stringstream
#include <cstdlib>
using namespace std;
list<COORD> snake;//双链表储存蛇身
list<COORD> ai_snake;//双链表储存ai蛇身
string game_map[25];//储存地图
int direction_before;//因为有了上面的映射,所以可以用int来表示蛇的运动方向。上一步的运动方向
int direction_now;//新的运动方向
int ai_direction_before;//ai蛇的运动方向信息
int chse;//游戏模式选择
int score;//得分
bool die;//判断游戏是否结束
bool ai_die;//ai蛇的生死
int speed = 500;//控制速度
vector<int> sc;//不定长数组用来储存从文件中读取的成绩
COORD food;
void Init();//更改dos窗口标题,初始化地图,初始化蛇身,蛇运动方向, 随机化种子
void Generate_food();//随机生成食物
void Press_key();//监听键盘并处理从键盘上读取的字符
void Move_snake();//移动蛇,并检测是否合理
void Move_ai_snake();//自动移动ai蛇,并检测是否合理
void Draw_map();//输出地图,蛇,食物,操作提示
void File_action();//成绩读入文件并计算名次
void Init_ai();//初始化ai蛇
int main()
{
cout << "Press 1(solo) or 2(vs ai) to choose mod:" << endl;
cin >> chse;
if (chse == 1)//单人游戏
{
Init();
Draw_map();
COORD coord; coord.X = 5; coord.Y = 10;//下标为[10][5]的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//移动光标位置
cout << "Press any key to start" << endl;//在指定位置输出提示语
//按下任意键,游戏开始
char c = _getch();//利用阻塞函数,当按下任意键,程序才继续向下运行,游戏才开始
Generate_food();//生成第一个食物
while (!die)
{
Press_key();//监听键盘并处理从键盘上读取的字符
Move_snake();//移动蛇,并检测是否合理
system("cls");//清屏
Draw_map();//重新画
if (speed < 0)
speed = 0;
Sleep(speed);//控制速度
}
File_action();
}
else//人机
{
Init();//初始化地图,dos窗口标题和玩家控制的蛇
Init_ai();//初始化ai蛇
Draw_map();
COORD coord; coord.X = 5; coord.Y = 10;//下标为[10][5]的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//移动光标位置
cout << "Press any key to start" << endl;//在指定位置输出提示语
//按下任意键,游戏开始
char c = _getch();//利用阻塞函数,当按下任意键,程序才继续向下运行,游戏才开始
Generate_food();//生成第一个食物
while (!die && !ai_die)
{
Press_key();//监听键盘并处理从键盘上读取的字符
Move_ai_snake();//移动ai蛇,并检测是否合理
Move_snake();//移动蛇,并检测是否合理
system("cls");//清屏
Draw_map();//重新画
if (speed < 0)
speed = 0;
Sleep(speed);//控制速度
}
}
system("pause");
return 0;
}
void Init()
{
SetConsoleTitleW(L"程序设计——team1——贪吃蛇");//更改dos窗口标题
//上下边界
game_map[0] = "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$";//三十个字符
game_map[19] = "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$";//三十个字符
//左右边界
for (int i = 1; i < 19; i++)
game_map[i] = "$ $";//三十个字符
//初始化蛇身,长度为两节
snake.push_back({ 10, 15 });
snake.push_back({ 10, 16 });
//默认一个蛇的初始运动方向
direction_before = 1;//默认朝上运动
srand((unsigned int)time(NULL));
}
void Generate_food()
{
do
{
food.Y = rand() % 20;
food.X = rand() % 30;
} while (game_map[food.Y][food.X] != ' ');//当食物生成在地图边界或者蛇身上时重新生成
game_map[food.Y][food.X] = '*';//生成食物
}
void Press_key()
{
while (_kbhit())
{
char temp = _getch();
if (temp == ' ')//暂停的功能实现
{
Sleep(2000);
}
switch (temp)
{
case 'o':
case 'O': speed -= 200; break;
case 'p':
case 'P': speed += 200; break;
case 'w':
case 'W': direction_now = 1; break;
case 's':
case 'S': direction_now = 2; break;
case 'a':
case 'A': direction_now = 3; break;
case 'd':
case 'D': direction_now = 4; break;
default: direction_now = 0;//其他情况的输入
}
//处理变向
if (direction_now)//当合法输入时
{
if (direction_before + direction_now != 3 && direction_before + direction_now != 7)//当之前的运动方向和之后的运动方向夹角不是180度时(即可以合理变向)
direction_before = direction_now;//变向
}
}
}
void Move_snake()
{
COORD temp;//储存新的蛇头坐标
switch (direction_before)//获取新的蛇头坐标
{
case 1: temp.X = snake.front().X, temp.Y = snake.front().Y - 1; break;
case 2: temp.X = snake.front().X, temp.Y = snake.front().Y + 1; break;
case 3: temp.X = snake.front().X - 1, temp.Y = snake.front().Y; break;
case 4: temp.X = snake.front().X + 1, temp.Y = snake.front().Y; break;
}
if (game_map[temp.Y][temp.X] == '$' || game_map[temp.Y][temp.X] == '+' || game_map[temp.Y][temp.X] == '%')//碰到墙壁或者自身或者ai蛇蛇身
{
COORD coord; coord.X = 5; coord.Y = 10;//下标为[10][5]的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//移动光标位置
if (chse == 1)//根据模式不同输出不同的信息
cout << "Game over." << endl;//在指定位置输出提示语
else
cout << "AI snake is winner." << endl;
die = true;
Sleep(1000);//函数在此停止1000ms,方便用户反应知道结果
}
else if (game_map[temp.Y][temp.X] == '*')//吃到食物
{
game_map[snake.front().Y][snake.front().X] = '+';//原蛇头变成蛇身
snake.push_front(temp);//新蛇头入链表
game_map[snake.front().Y][snake.front().X] = '=';//在地图上绘出新蛇头
score += 10;//加分
Generate_food();//生成新的食物
}
else//如果只是向前移动一步的话,加入新蛇头,去掉蛇尾即可
{
game_map[snake.front().Y][snake.front().X] = '+';//原蛇头变蛇身
snake.push_front(temp);//加入新蛇头
game_map[snake.front().Y][snake.front().X] = '=';//画出新蛇头
game_map[snake.back().Y][snake.back().X] = ' ';//尾部变为空白
snake.pop_back();//去尾巴
}
}
void Draw_map()
{
for (int i = 0; i < 20; i++)
cout << game_map[i] << endl;
cout << endl;
if(chse == 1)//单人模式中才记录分数
cout << "Score:" << score << endl;
cout << "操作方式:" << endl;
cout << "w(W)上 s(S)下 a(A)左 d(D)右" << endl;
cout << "o(O)实现游戏加速,p(P)实现游戏减速" << endl;
cout << "按空格键暂停2秒" << endl;
}
void File_action()
{
ofstream fout("record.txt", ios::out | ios::app);
fout << score << ' ';//成绩读入文件中
fout.close();
ifstream fin("record.txt"); //待读取文件的目录
string line;
while (getline(fin, line))
{
stringstream ss(line);//定义输入流并且传值进去
if (!ss.eof())
{
int temp;
while (ss >> temp)//提取int
sc.push_back(temp);//加入到vector数组中
}
}
sort(sc.begin(), sc.end());//通过迭代器来利用sort排序
COORD coord; coord.X = 5; coord.Y = 10;//下标为[10][5]的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//移动光标位置
//求排名
int rank = 1;
for (auto x : sc)
if (x > score) rank++;
cout << "你的排名是:" << rank;
fin.close();
}
void Init_ai()
{
//初始化蛇身,长度为两节
ai_snake.push_back({ 10, 10 });
ai_snake.push_back({ 10, 11 });
//默认一个蛇的初始运动方向
ai_direction_before = 1;//默认朝上运动
}
void Move_ai_snake()
{
//实现ai蛇的转向,向靠近食物的方向运动
if (ai_direction_before == 1)//ai蛇运动朝上
{
if (ai_snake.front().Y <= food.Y)//食物在蛇头此行或者下面某行
{
if (ai_snake.front().X >= food.X)
ai_direction_before = 3;
else if (ai_snake.front().X < food.X)
ai_direction_before = 4;
}
}
else if (ai_direction_before == 2)//ai蛇运动朝下
{
if (ai_snake.front().Y >= food.Y)//食物在蛇头此行或者上面某行
{
if (ai_snake.front().X >= food.X)
ai_direction_before = 3;
else if (ai_snake.front().X < food.X)
ai_direction_before = 4;
}
}
else if (ai_direction_before == 3)//ai蛇运动朝左
{
if (ai_snake.front().X <= food.X)//食物在蛇头此列或者右边某列
{
if (ai_snake.front().Y >= food.Y)
ai_direction_before = 1;
else if (ai_snake.front().Y < food.Y)
ai_direction_before = 2;
}
}
else//ais蛇运动朝右
{
if (ai_snake.front().X >= food.X)//食物在蛇头此列或者左边某列
{
if (ai_snake.front().Y >= food.Y)
ai_direction_before = 1;
else if (ai_snake.front().Y < food.Y)
ai_direction_before = 2;
}
}
//移动并判断合理性
COORD temp;//储存新的蛇头坐标
switch (ai_direction_before)//获取新的蛇头坐标
{
case 1: temp.X = ai_snake.front().X, temp.Y = ai_snake.front().Y - 1; break;
case 2: temp.X = ai_snake.front().X, temp.Y = ai_snake.front().Y + 1; break;
case 3: temp.X = ai_snake.front().X - 1, temp.Y = ai_snake.front().Y; break;
case 4: temp.X = ai_snake.front().X + 1, temp.Y = ai_snake.front().Y; break;
}
if (game_map[temp.Y][temp.X] == '$' || game_map[temp.Y][temp.X] == '%' || game_map[temp.Y][temp.X] == '+')//碰到墙壁或者自身或者玩家蛇身体
{
COORD coord; coord.X = 5; coord.Y = 10;//下标为[10][5]的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//移动光标位置
cout << "You is winner" << endl;
ai_die = true;
Sleep(1000);//函数在此停止1000ms,方便用户反应知道结果
}
else if (game_map[temp.Y][temp.X] == '=')//蛇头碰到蛇头
{
COORD coord; coord.X = 5; coord.Y = 10;//下标为[10][5]的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//移动光标位置
cout << "No winner." << endl;//在指定位置输出提示语
ai_die = true;
Sleep(1000);//函数在此停止1000ms,方便用户反应知道结果
}
else if (game_map[temp.Y][temp.X] == '*')//吃到食物
{
game_map[ai_snake.front().Y][ai_snake.front().X] = '%';//原蛇头变成蛇身
ai_snake.push_front(temp);//新蛇头入链表
game_map[ai_snake.front().Y][ai_snake.front().X] = '#';//在地图上绘出新蛇头
Generate_food();//生成新的食物
}
else//如果只是向前移动一步的话,加入新蛇头,去掉蛇尾即可
{
game_map[ai_snake.front().Y][ai_snake.front().X] = '%';//原蛇头变蛇身
ai_snake.push_front(temp);//加入新蛇头
game_map[ai_snake.front().Y][ai_snake.front().X] = '#';//画出新蛇头
game_map[ai_snake.back().Y][ai_snake.back().X] = ' ';//尾部变为空白
ai_snake.pop_back();//去尾巴
}
}