贪吃蛇
本文已被搬运到Github去咯
https://github.com/hsh778205/Greedy-Snake
不完善的地方:电脑走只能死走,没学人工智能
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<windows.h>
#include<stdlib.h>
#include<fstream>
#include<set>
#include<queue>
#include<vector>
#include<ctime>
#include<conio.h>
#define IL inline
#define re register
#define LL long long
using namespace std;
void init();
int lx,ly;
void hide();
void backxy();
void gotoxy0(int,int);
void gotoxy(int,int);
void getxy();
const int A=10,B=11,C=12,D=13,E=14,F=15;
void SetColor(unsigned short,unsigned short);
void SetColor(unsigned short=0x07);
long long step,score;
int speed,size,lenth,way,tme,init_size,start_time,clr=1,have_eaten;
int big_apple_probability,big_apple_save_time=10000,big_apple_time,mode;
long long his_score[10],his_step[10];
bool through_wall,wall_protection,self_protection,full_time,adj_speed;
bool have_big_apple;
int delta[4][2]={
{-1,0},
{0,-1},
{1,0},
{0,1}
};
struct xy{
int x,y;
bool operator==(xy t)
{
return x==t.x&&y==t.y;
}
bool inmap(){
return x<size&&x>=0&&y<size&&y>=0;
}
xy edge(int w){
return {x+delta[w][0],y+delta[w][1]};
}
}apple,big_apple;
bool operator<(xy a,xy b)
{
return a.x*100+a.y<b.x*100+b.y;
}
deque<xy>snake;
set<xy>line;
int map[100][100];
void save();
void setting();
void make_apple();
void move(int);
int judge();
int calc();
void show();
int main()
{
srand(time(0));
hide();
setting();
init();
while(true)
{
show();
if(mode==5)
{
if(_kbhit()){
// char ch=getch();
if(getch()==' '){
int t=clock();
while(getch()!=' ');;
start_time+=clock()-t;
}
}
way=calc();
}
else
{
tme=clock();
while(clock()-tme<=speed)
{
gotoxy0(size+2+5,4);
cout<<(clock()-start_time)/1000<<"s";
if(mode==1) gotoxy0(size+2,15),cout<<"当前苹果价值="<<log2((clock()-start_time)/1000.0)*(1000.0/speed);
if(_kbhit()){
char ch=getch();
if((ch=='a'||ch=='A')&&way!=2){
way=0;break;
}
if((ch=='w'||ch=='W')&&way!=3){
way=1;break;
}
if((ch=='d'||ch=='D')&&way!=0){
way=2;break;
}
if((ch=='s'||ch=='S')&&way!=1){
way=3;break;
}
if(adj_speed)
if(ch=='+'||ch=='='||ch=='.'){
speed=max(0,speed-10);
gotoxy0(size+2,5);
cout<<"移动间隔: \b\b\b\b\b\b\b\b"<<speed<<"ms";
if(mode==1) gotoxy0(size+2,15),cout<<"当前苹果价值= \b\b\b\b\b\b\b\b\b\b\b\b"<<log2((clock()-start_time)/1000.0)*(1000.0/speed);
}
if(adj_speed)
if(ch=='-'||ch==','){
speed+=10;
gotoxy0(size+2,5);
cout<<"移动间隔: \b\b\b\b\b\b\b\b"<<speed<<"ms";
if(mode==1) gotoxy0(size+2,15),cout<<"当前苹果价值= \b\b\b\b\b\b\b\b\b\b\b\b"<<log2((clock()-start_time)/1000.0)*(1000.0/speed);
}
if(ch=='x'||ch=='X') save(),exit(0);
if(ch=='v'||ch=='V') save();
if(ch==' '){//暂停
long ttime=clock();
char c;
do{
c=getch();
if(adj_speed)
if(c=='+'||c=='='||c=='.'){
speed=max(0,speed-10);
gotoxy0(size+2,5);
cout<<"移动间隔: \b\b\b\b\b\b\b\b"<<speed<<"ms";
if(mode==1) gotoxy0(size+2,15),cout<<"当前苹果价值= \b\b\b\b\b\b\b\b\b\b\b\b"<<log2((clock()-start_time)/1000.0)*(1000.0/speed);
}
if(adj_speed)
if(c=='-'||c==','){
speed+=10;
gotoxy0(size+2,5);
cout<<"移动间隔: \b\b\b\b\b\b\b\b"<<speed<<"ms";
if(mode==1) gotoxy0(size+2,15),cout<<"当前苹果价值= \b\b\b\b\b\b\b\b\b\b\b\b"<<log2((clock()-start_time)/1000.0)*(1000.0/speed);
}
if(c=='x') save(),exit(0);
if(c=='v') save();
}while(c!=' ');
tme+=clock()-ttime;
big_apple_time+=clock()-ttime;
}
}
}
}
if(full_time&&clock()-tme<=speed) Sleep(speed-clock()+tme);
if(have_big_apple){
gotoxy0(size+2,14);
cout<<" ";
if(clock()-big_apple_time<big_apple_save_time){
gotoxy0(size+2,14);
cout<<"大苹果剩余时间:"<<big_apple_save_time-clock()+big_apple_time<<"ms";
gotoxy(big_apple.x,big_apple.y);
if(rand()&1) cout<<"♀";
else cout<<"♂";
}
else{
gotoxy(big_apple.x,big_apple.y);
cout<<" ";
have_big_apple=0;
}
}
snake.push_front({snake.front().x+delta[way][0],snake.front().y+delta[way][1]});
if(judge()==1) break;
if(judge()==2){
if(mode==1) score--;
gotoxy0(2,size+2);
cout<<"蛇蛇撞墙了!扣分ing";
cout<<"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ";
gotoxy0(size+2,2);
cout<<"得分: \b\b\b\b\b\b\b\b\b\b\b\b"<<score;
snake.pop_front();
continue;
}
line.insert(snake.front());
gotoxy(snake.front().x,snake.front().y);
SetColor(0x0c);
cout<<"■";
//将第二格的颜色改回来
gotoxy(snake[1].x,snake[1].y);
SetColor();
if(mode==1){
clr++;
clr%=15;
clr++;
if(clr==C||clr==7||clr==0) clr++;
SetColor(0,clr);
}
cout<<"■";
SetColor();
//如果吃到了苹果
if(have_big_apple&&snake.front()==big_apple){
score+=5;
for(int i=0;i<5&&snake.size()>2;i++){
line.erase(snake.back());
gotoxy(snake.back().x,snake.back().y);
snake.pop_back();lenth--;
SetColor();
cout<<" ";
}
big_apple_time=-10000;
show();
}
if(snake.front()==apple){
have_eaten++;
if(have_big_apple) big_apple_time=-10000;
lenth++;
if(snake.size()==(unsigned)size*size){
show();
break;
}
make_apple();
if(mode==1){
score+=log2((clock()-start_time)/1000.0)*(1000.0/speed);
}
else score+=1;
show();
}
else{
line.erase(snake.back());
gotoxy(snake.back().x,snake.back().y);
snake.pop_back();
SetColor();
cout<<" ";
}
gotoxy0(size+2+3,-1);
cout<<" \b\b\b\b\b"<<snake.front().x<<","<<snake.front().y;
gotoxy0(size+2+5+4,-1);
cout<<" \b\b\b\b\b"<<apple.x<<","<<apple.y;
gotoxy0(size+2+3,9);
cout<<++step;
}
show();
save();
cin.get();cin.get();
if(snake.size()>=(unsigned int)size*size){
gotoxy0(size/2-2,size/2);
SetColor(4,7);
cout<<"You have won!!!";
cin.get();
return 0;
}
for(int i=1;i<size;i++)
{
gotoxy0(1,i);
for(int j=1;j*7<size;j++)cout<<"You are dead ";
cout<<"\n";
}
cout<<"\n\n\n\n\n";
cin.get();
main();
return 0;
}
void save()
{
if(his_score[mode]<score)
{
his_score[mode]=score;
his_step[mode]=step;
}
ofstream fout("history.txt",ios::out);
for(int i=0;i<10;i++) fout<<his_score[i]<<" "<<his_step[i]<<endl;
}
void setting()
{
memset(his_step,sizeof(his_score),0);
memset(his_step,sizeof(his_step),0);
step=0;
if(system("@echo off\ndir /a history.txt")==1){
save();
}
ifstream fin("history.txt",ios::in);
if(fin.eof()||fin.peek()==EOF){
save();
}
else{
for(int i=0;i<10;i++) fin>>his_score[i]>>his_step[i];
}
SetColor();
system("cls");
system("mode con cols=80 lines=40");//改变宽高
cout<<"\t序号 名称\t地图\t速度\t大苹果\t其他属性\n";
cout<<"\t【0】作弊模式\t20*20\t5m/s\t15%\t穿墙 吃自己不死亡 可调节速度\n";
cout<<"\t【1】娱乐模式\t25*25\t2m/s\t30%\t撞墙保护 特殊计分方式 彩色!\n";
cout<<"\t【2】经典模式\t20*20\t5m/s\t15%\t穿墙\n";
cout<<"\t【3】普通模式\t15*15\t10m/s\t0%\t无\n";
cout<<"\t【4】快速模式\t20*20\t1m/s\t20%\t穿墙 可调节速度 可手动移动\n";
cout<<"\t【5】电脑模式\n";
cout<<"\t【6】自定义\n";
cout<<"请输入数字选择 或按w(上)/s(下)移动 回车确定\n";
vector<string>sentence;
sentence.push_back("请认真阅读下面的信息!!!!!!!!!!!!!!!!!!!!");
sentence.push_back("请把控制台窗口的字号改成14或以下!!!");
sentence.push_back("请将输入法调成英文模式!!");
sentence.push_back("按空格键暂停游戏");
sentence.push_back("按v键保存(只记录最高) 按x键保存并退出");
sentence.push_back("在可调节速度的模式下,按+加速,按-减速");
sentence.push_back("不仅+可以加快速度,=也可以");
sentence.push_back("其实 ,和.也可以调整速度,但是一定要是英文的符号!");
sentence.push_back("娱乐模式下不会死亡,推荐先玩娱乐模式");
sentence.push_back("娱乐模式下,移速越快,游戏时间越长,加分越多");
sentence.push_back("娱乐模式下,记得先加快一点速度哦");
sentence.push_back("快速模式下,只要你手速够快,蛇想多快有多快");
sentence.push_back("穿墙和撞墙保护不可共存,穿墙优先");
for(unsigned int i=0;i<sentence.size();i++)
{
gotoxy0(16-sentence[i].size()/4,10+i*2);
cout<<sentence[i];
}
int ch=0;
char t;
gotoxy0(1,0);
cout<<"->";
do{
t=getch();
if(t=='s'||t=='S'||t=='W'||t=='w'){
gotoxy0(1,ch);
cout<<" ";
if(t=='s'||t=='S') ch++;
if(t=='w'||t=='W') ch--;
}
if(t>='0'&&t<='6'){
ch=t-'0';
break;
}
ch=(ch+7)%7;
gotoxy0(1,ch);
cout<<"->";
}while(t!='\n'&&t!='\r');
system("cls");
mode=ch;
switch(ch+'0'){
case '0':{
size=20;
speed=200;
big_apple_probability=10;
through_wall=1;
wall_protection=0;
self_protection=1;
adj_speed=1;
full_time=1;
gotoxy0(size+2,6);cout<<"【0】作弊模式";
break;
}
case '1':{
size=25;
speed=500;
through_wall=0;
big_apple_probability=30;
wall_protection=1;
self_protection=1;
adj_speed=1;
full_time=1;
gotoxy0(size+2,6);cout<<"【1】娱乐模式";
break;
}
case '2':{
size=20;
speed=200;
big_apple_probability=20;
wall_protection=0;
self_protection=0;
adj_speed=0;
through_wall=1;
full_time=1;
gotoxy0(size+2,6);cout<<"【2】经典模式";
break;
}
case '3':{
size=15;
speed=100;
big_apple_probability=10;
through_wall=0;
wall_protection=0;
self_protection=0;
adj_speed=0;
full_time=1;
gotoxy0(size+2,6);cout<<"【3】普通模式";
break;
}
case '4':{
size=20;
speed=1000;
big_apple_probability=20;
through_wall=1;
wall_protection=1;
self_protection=0;
adj_speed=1;
full_time=0;
gotoxy0(size+2,6);cout<<"【4】快速模式";
break;
}
case '5':{
system("mode con cols=130 lines=53");//改变宽高
cout<<"输入地图大小(10-50且只能是偶数):";
cin>>size;
size=min(max(size,10),50);
if(size&1){
size--;
cout<<"已自动转化为"<<size;
}
system("cls");
speed=0;
big_apple_probability=0;
wall_protection=0;
self_protection=0;
through_wall=0;
adj_speed=0;
full_time=0;
gotoxy0(size+2,6);cout<<"【5】电脑模式";
break;
}
case '6':{
system("cls");
cout<<"地图大小:";cin>>size;size=max(min(size,50),5);
init_size=2;
cout<<"移动间隔时间(ms):";cin>>speed;speed=max(min(speed,2000),10);
cout<<"大苹果掉落概率(%):";cin>>big_apple_probability;big_apple_probability=max(min(big_apple_probability,100),0);
cout<<"穿墙(1/0):\n";through_wall=getch()-'0';
if(!through_wall) cout<<"撞墙不死亡(1/0):\n",wall_protection=getch()-'0';
cout<<"吃自己不死亡(1/0):\n";self_protection=getch()-'0';
cout<<"允许调整速度(1/0):\n";adj_speed=getch()-'0';
cout<<"允许手动移动(1/0):\n";full_time=!(getch()-'0');
system("cls");
// system("mode con cols=100 lines=45");//改变宽高
gotoxy0(size+2,6);cout<<"【6】自定义模式";
break;
}
}
system("mode con cols=130 lines=53");//改变宽高
}
void init()
{
SetColor();
memset(map,sizeof(map),0);
gotoxy0(-1,-1);
cout<<" x\ny";
for(int i=0;i<size;i++){
gotoxy0(i+1,-1);cout<<i+1;
gotoxy0(-1,i+1);cout<<i+1;
}
for(int i=0;i<=size+1;i++)
{
gotoxy0(i,0);cout<<"═";
gotoxy0(i,size+1);cout<<"═";
gotoxy0(0,i);cout<<"║";
gotoxy0(size+1,i);cout<<"║";
}
gotoxy0(0,0);cout<<"╔";
gotoxy0(0,size+1);cout<<"╚";
gotoxy0(size+1,size+1);cout<<"╝";
gotoxy0(size+1,0);cout<<"╗";
snake.clear();
line.clear();
snake.push_back({size/2-1,size/2-1});
line.insert(snake.back());
gotoxy(size/2-1,size/2-1);SetColor(0x0c);cout<<"■";
SetColor();
show();
while(true){
char ch=getch();
if(ch=='a'||ch=='A'){
way=0;break;
}
if(ch=='w'||ch=='W'){
way=1;break;
}
if(ch=='d'||ch=='D'){
way=2;break;
}
if(ch=='s'||ch=='S'){
way=3;break;
}
}
for(int i=0;i<init_size-1;i++){
snake.push_back(snake.back().edge((way+2)%4));
line.insert(snake.back());
gotoxy(snake.back().x,snake.back().y);cout<<"■";
}
start_time=clock();
make_apple();
lenth=snake.size();
gotoxy0(size+2,-1);
cout<<"蛇头:";
gotoxy0(size+2+6,-1);
cout<<"Apple:";
gotoxy0(size+2,9);
cout<<"step:";
if(mode==5) return;
gotoxy0(size+2,7); cout<<"计分方式:";
if(mode==1) cout<<"小苹果加log2(time)*(1000/speed)分并长长1m";
else cout<<"小苹果加1分并长长1m";
gotoxy0(size+2,8);
cout<<"大苹果加5分并缩短5m";
if(mode==1) gotoxy0(size+2,12),cout<<"碰到墙会持续扣分哦",gotoxy0(size+2,13),cout<<"吃到自己会扣得分的十分之一分(不足5分记作5分)";
gotoxy0(size+2,5);
cout<<"移动间隔: \b\b\b\b\b\b\b\b\b\b"<<speed<<"ms";
}
void hide()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
}
void backxy()
{
COORD pos;
pos.X = lx;
pos.Y = ly;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void gotoxy0(int x,int y)
{
COORD pos;
pos.X =(x<<1)+2;
pos.Y =y+1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void gotoxy(int x, int y)
{
COORD pos;
pos.X =(x<<1)+4;
pos.Y =y+2;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void getxy(){
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
lx=csbi.dwCursorPosition.X,ly=csbi.dwCursorPosition.Y;
}
void SetColor(unsigned short BackGroundColor,unsigned short ForeColor)
{
HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hCon,(ForeColor%16)|(BackGroundColor%16*16));
}
void SetColor(unsigned short x)
{
HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hCon,x);
}
void make_apple()
{
if(have_big_apple){
have_big_apple=0;
gotoxy(big_apple.x,big_apple.y);
cout<<" ";
}
vector<xy>t;
for(int i=0;i<size;i++)
for(int j=0;j<size;j++)
if(line.find({i,j})==line.end()) t.push_back({i,j});
random_shuffle(t.begin(),t.end());
gotoxy(t[0].x,t[0].y);
cout<<"●";
if(snake.size()>10&&rand()%100+1<=big_apple_probability&&t.size()>=2){
gotoxy(t[1].x,t[1].y);
if(rand()&1) cout<<"♀";
else cout<<"♂";
have_big_apple=1;
big_apple=t[1];
big_apple_time=clock();
}
apple=t.front();
}
int judge()
{
if(snake.front().inmap()&&line.find(snake.front())==line.end()) return 0;
if(!snake.front().inmap()&&through_wall){
xy h=snake.front();
h.x=(h.x+size)%size;
h.y=(h.y+size)%size;
snake[0]=h;
return 0;
}
if(!snake.front().inmap()&&wall_protection) return 2;
if(line.find(snake.front())!=line.end()&&self_protection){
if(mode==1){
score-=max((long long)5,score/10);
}
return 0;
}
return 1;
}
/*
*/
void show()
{
gotoxy0(size+2,1);
cout<<"长度: \b\b\b\b\b"<<snake.size();
gotoxy0(size+2+3,9);
cout<<step;
gotoxy0(size+2,4);cout<<"游戏时间:";
gotoxy0(size+2+5,4);
cout<<(clock()-start_time)/1000<<"s";
if(mode==5) return;
gotoxy0(size+2,0);
cout<<"已经吃了"<<have_eaten<<"个";
gotoxy0(size+2,2);
cout<<"得分: \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"<<score;
gotoxy0(size+2,3);
cout<<"方向: \b\b\b\b\b";
if(way==0) cout<<"left";
if(way==1) cout<<"up";
if(way==2) cout<<"right";
if(way==3) cout<<"down";
if(mode==1) gotoxy0(size+2,15),cout<<"当前苹果价值= \b\b\b\b\b\b\b\b\b\b\b\b"<<log2((clock()-start_time)/1000.0)*(1000.0/speed);
}
int calc()
{
xy h=snake.front();
if(snake.size()/size<(size*0.5))
{
if(h.x<apple.x/*go_front*/&&h.y==size-1&&(snake.back().x<h.x||snake.size()<(unsigned int)size-1||snake.back().x>apple.x))
{
if(h.x==size-1){
return 1;
}
if(!(apple.x&1)&&h.x+1==apple.x){
return 1;
}
if((apple.x&1)&&h.x==apple.x){
return 1;
}
return 2;
}
if(h.x>apple.x/*go_back*/&&h.y==1&&(snake.back().x<h.x||snake.size()<(unsigned int)size-1)){
return 1;
}
if(!h.y&&snake.back().x>h.x){
if((apple.x&1)==0&&apple.x==h.x) return 3;
if((apple.x&1)&&apple.x==h.x+1) return 3;
//否则就用普通规则
if(!h.x) return 3;
return 0;
}
}
if(!h.y){
if(!h.x) return 3;
return 0;
}
if(!(h.x&1)){
if(h.y==size-1) return 2;
else return 3;
}
if(h.x&1){
if(h.y==1&&h.x!=size-1) return 2;
//else return 1;
}
return 1;
}
//若要转载,搬运,复制,请不要丢了这行注释!made by 折柳
来源:oschina
链接:https://my.oschina.net/u/4254945/blog/4523017