半年前毛都不懂的时候,写了个暴力的贪吃蛇ai,900多行,一堆if,else,现在算是懂了点毛吧,加了个bfs,瞬间优越了很多,在10*10下试验也比老的ai快,真是知识就是力量啊...
#include<cstdio>
#include<iostream>
#include<cstring>
#include <conio.h>
#include<windows.h>
using namespace std;
const int N=10+2;
const int MAX=N*N+100;
struct snk{
int x,y;
int length;
snk *next,*pre;
}; snk *head,*tail;
struct food{
int x,y;
}fd;
void InitGame();void PaintGame();
bool MoveSnk(int);void SetNewfd();
void NofdMove(int,int);void GetfdMove(int,int);
char brush[6]={' ','-','\6','*','^'};
int g[N+10][N+10];
int vis[MAX],que[4][MAX],findfood,first,last[4],num;
int fa[MAX],depth[MAX],dir[4]={-1,-N,1,N},vis_dir[4];
int glb_least,least_p,fd_depth,tail_pos;
int snkque[MAX],snk_dep[MAX],snk_vis[MAX];
void comp(int &a,int b){
if(b<a) least_p=first,a=b;
}
int cango(int pos,int fun){
int x=pos/N, y=pos%N;
if(g[x][y]==0) return 1;
if(fun==0){
if(x==tail->x&&y==tail->y) tail_pos=pos;
return 0;
}
if(g[x][y]>1){
snk *p1=head,*p2=tail;
while(1){
if(p1->x==x&&p1->y==y) {comp(glb_least,p1->length);break;}
if(p2->x==x&&p2->y==y) {comp(glb_least,p2->length);break;}
p1=p1->pre; p2=p2->next;
}
}
return 0;
}
void clear(int que[],int vis[],int last){
for(int i=0;i<last;i++) vis[que[i]]=0;
}
int canfd(int pos){
int x=pos/N, y=pos%N;
if(g[x][y]==0) return 0;
if(g[x][y]>1){
snk *p1=head,*p2=tail;
while(1){
if(p1->x==x&&p1->y==y) return p1->length;
if(p2->x==x&&p2->y==y) return p2->length;
p1=p1->pre; p2=p2->next;
}
}
return MAX;
}
int snkbfs(int pfd,int t){
int l=t,r=t,b;
snkque[r++]=pfd; snk_dep[l]=1; snk_vis[pfd]=1;
while(l<r){
if(snk_dep[l]>head->length){
for(int i=0;i<r;i++) snk_vis[snkque[i]]=0;
return 1;
}
int pos=snkque[l],newp;
for(int i=0;i<4;i++){
newp=pos+dir[i];
if(!snk_vis[newp]){
if(!(b=canfd(newp)))
snkque[r]=newp,snk_dep[r++]=snk_dep[l]+1,snk_vis[newp]=1;
else
if(snk_dep[l]>=b){
for(int i=0;i<r;i++) snk_vis[snkque[i]]=0;
return 1;
}
}
}
l++;
}
for(int i=0;i<r;i++) snk_vis[snkque[i]]=0;
return 0;
}
int bfs(int que[MAX],int last){
first=0; for(int i=0;i<last;i++) vis[que[i]]=1,depth[i]=1;
int pfd=fd.x*N+fd.y; glb_least=MAX;
while(first<last){
int pos=que[first],newp;
if(pfd==pos){
findfood=1;
if(depth[first]>=head->length){
clear(que,vis,last); fd_depth=depth[first];
while(depth[first]>1) first=fa[first];
return que[first];
}
int t=first,i=0;
while(depth[t]>1) t=fa[t],snk_vis[que[t]]=1,snkque[i++]=que[t];
if(snkbfs(pfd,i)){
clear(que,vis,last); fd_depth=depth[first];
while(depth[first]>1) first=fa[first];
return que[first];
}
findfood=0;
}
for(int i=0;i<4;i++){
newp=pos+dir[i];
if(!vis[newp]&&cango(newp,1))
que[last]=newp,depth[last]=depth[first]+1,fa[last++]=first,vis[newp]=1;
}
first++;
}
findfood=0; clear(que,vis,last); first=least_p;
while(depth[first]>1) first=fa[first]; int j=first;
for(int i=0;depth[i]==1&&i<last;i++) if(i!=first) j=i;
return que[j];
}
int AiDir(){
int pos,ph=head->x*N+head->y; num=-1; tail_pos=0;
for(int i=0;i<4;i++) last[i]=0,vis_dir[i]=-1;
for(int i=0;i<4;i++){
pos=ph+dir[i];
if(!cango(pos,0)) continue;
if(vis_dir[i]<0) vis_dir[i]=++num;
int j=(i+1)%4;
int p2=pos+dir[j]; pos=ph+dir[j];
if(cango(pos,0)&&cango(p2,0)){
if(vis_dir[j]<0) vis_dir[j]=num;
else{
if(vis_dir[i-1]==vis_dir[i]) vis_dir[i-1]=vis_dir[j];
vis_dir[i]=vis_dir[j];
}
}
}
if(num==-1) return tail_pos?tail_pos:ph+dir[0];
num=-1; int tag;
for(int i=0;i<4;i++){
if((tag=vis_dir[i])<0) continue;
if(tag>num) num=tag;
que[tag][last[tag]++]=ph+dir[i];
}
findfood=0; int least=MAX,newp,p,d=MAX,fdp,everfind=0;
for(int i=0;i<=num;i++){
findfood=0;
newp=bfs(que[i],last[i]);
if(findfood&&fd_depth<d) d=fd_depth,fdp=newp,everfind=1;
else if(glb_least<least) least=glb_least,p=newp;
}
if(everfind) return fdp;
if(tail_pos){
snk *p1=tail->next; int tp=p1->x*N+p1->y,pfd=fd.x*N+fd.y;
if( abs(tp-p)==N||abs(tp-p)==1 ){
if(pfd!=p||head->length==(N-2)*(N-2)-1) return p;
}
if(least>1) return tail_pos;
}
return p;
}
int main(){
while(1){ getchar(); Sleep(1000);
int run=1; int p;
InitGame();
while(1){
if(head->length==(N-2)*(N-2)) getchar();
p=AiDir();
if( MoveSnk(p) ){
cout<<"die";
break;
}
PaintGame();
run++;
}
}
return 0;
}
bool MoveSnk(int pos){
int x=pos/N,y=pos%N;
if(g[x][y]>0&&!(x==tail->x&&y==tail->y)) return 1;
g[head->x][head->y]=3; //当前头位置图案改为身体图案
g[tail->x][tail->y]=0;
if(x==fd.x && y==fd.y){
GetfdMove(x,y);
g[x][y]=2;
SetNewfd();
}
else
NofdMove(x,y);
g[head->x][head->y]=2;
g[tail->x][tail->y]=4;
return 0;
}
void GetfdMove(int x,int y){
snk* new_head=new snk;
new_head->x=x;
new_head->y=y;
new_head->length=head->length+1;
new_head->next=NULL;
new_head->pre=head;
head->next=new_head;
head=new_head;
}
void SetNewfd(){
int x,y;
while(1){
//srand((unsigned)time(NULL));
x=rand()%(N-2)+1;
y=rand()%(N-2)+1; //产生随机食物的函数
if(g[x][y]==0) break;
}
fd.x=x; fd.y=y;
}
void NofdMove(int x,int y){
snk *p1=tail, *p2;
while(p1->next != NULL){
p2=p1->next;
p1->x=p2->x;
p1->y=p2->y;
p1=p2;
}
p1->x=x; p1->y=y;
}
void InitGame(){
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
if(i==0 || j==0 || i==N-1 || j==N-1)
g[i][j]=1;
snk *p1,*p2;
for(int i=5;i>0;i--){
p1=new snk;
p1->x=5;
p1->y=i;
p1->length=i;
g[5][i]=3;
if(i==5){
head=p1;
head->next=NULL;
}
else{
p1->next=p2;
p2->pre=p1;
}
p2=p1;
}
tail=p1; tail->pre=NULL;
g[5][5]=2; g[5][1]=4;
fd.x=N-4; fd.y=N-4;
PaintGame();
}
void PaintGame(){
system("cls");
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(!g[i][j]&&i==fd.x&&j==fd.y) putchar('@');
else putchar(brush[g[i][j]]);
putchar(' ');
}
putchar('\n');
}
}