贪吃蛇ai

半年前毛都不懂的时候,写了个暴力的贪吃蛇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');
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值