五子棋ai(优化版)

基于博弈树的五子棋ai(优化版)

针对上一个版本做了如下改进

​ 优化了getvalue局面评估函数 时间复杂度为O(n)

​ 优化了getchild扩展函数 时间复杂度为O(n)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define mapsize 225
#define maplen 15
#define dddd 4 
int map[mapsize];
typedef struct child* ch;
struct child{
	int*ls;
	ch next;
};
void print_map(int* data){
	int i,j;
	printf("\t 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 \n");
	printf("\t ———————————————\n");
	for(i=0;i<maplen;i++){
		printf("%d\t|",i); 
		for(j=0;j<maplen;j++){
			switch(data[i*maplen+j]){
				case 0:
					printf("  ");
					break;
				case 1:
					printf("X ");
					break;
				case -1:
					printf("O ");
					break ;
			}
		}
		printf("|"); 
		printf("\n");
	}
	printf("\t ———————————————\n");

}
ch getchild(int* data,int flag){
	ch ret=(ch)malloc(sizeof(struct child));
	ret->ls=(int*)malloc(sizeof(int)*mapsize);
	memset(ret->ls,0,sizeof(int)*mapsize);
	ret->next=NULL;
	int i,j;
	for(i=0;i<maplen;i++){
		for(j=0;j<maplen;j++){
			if(data[i*maplen+j]){
				if(i-1>=0&&j-1>=0) ret->ls[(i-1)*maplen+j-1]=!data[(i-1)*maplen+j-1];
				if(i-1>=0) ret->ls[(i-1)*maplen+j]=!data[(i-1)*maplen+j];
				if(i-1>=0&&j+1<maplen) ret->ls[(i-1)*maplen+j+1]=!data[(i-1)*maplen+j+1];
				if(j-1>=0) ret->ls[i*maplen+j-1]=!data[i*maplen+j-1];
				if(j+1<maplen) ret->ls[i*maplen+j+1]=!data[i*maplen+j+1];
				if(i+1<maplen&&j-1>=0) ret->ls[(i+1)*maplen+j-1]=!data[(i+1)*maplen+j-1];
				if(i+1<maplen) ret->ls[(i+1)*maplen+j]=!data[(i+1)*maplen+j];
				if(i+1<maplen&&j+1<maplen) ret->ls[(i+1)*maplen+j+1]=!data[(i+1)*maplen+j+1];
			}
		}
	}
	ch p=ret;
	for(i=0;i<mapsize;i++){
		if(ret->ls[i]){
			ch tmp=(ch)malloc(sizeof(struct child));
			tmp->ls=(int*)malloc(sizeof(int)*mapsize);
			tmp->next=NULL;
			memcpy(tmp->ls,data,sizeof(int)*mapsize);
			tmp->ls[i]=flag;
			p->next=tmp;
			p=p->next;
		}
	}
	return ret;
}
int getvalue(int *data,int flag){
	int i,j,k;
	int val[5]={0,0,0,0,0};
	for(i=0;i<2*maplen-1;i++){
		int len=0;
		int len1=0;
		for(j=0;j<((i+1)>maplen?(2*maplen-1-i):(i+1));j++){
			int x=(i+1)>maplen?(maplen-1):(i-j);
			int y=(i+1)>maplen?(i+1-maplen):j;
			if(data[x*maplen+y]==flag){
				len1++;
				if(x-1<0||y+1>=maplen||(data[(x-1)*maplen+y+1]!=flag)){
					switch(len1){
						case 2:{
							if(x+2<maplen&&y-2>=0&&x-1>=0&&y+1<maplen&&!data[(x+2)*maplen+y-2]&&!data[(x-1)*maplen+y+1]){
								val[3]++;
							}
							break;
						}
						case 3:{
							if((x+3<maplen&&y-3>=0&&!data[(x+3)*maplen+y-3])&&(x-1>=0&&y+1<maplen&&!data[(x-1)*maplen+y+1])){
								val[0]+=3;
							}
							if((x+3<maplen&&y-3>=0&&!data[(x+3)*maplen+y-3])&&(x+4<maplen&&y-4>=0&&!data[(x+4)*maplen+y-4])){
								val[0]++;
							}
							if((x-2>=0&&y+2<maplen&&!data[(x-2)*maplen+y+2])&&(x-1>=0&&y+1<maplen&&!data[(x-1)*maplen+y+1])){
								val[0]++;
							}
							break;
						}
						case 4:{
							if((x-1>=0&&y+1<maplen&&!data[(x-1)*maplen+y+1])){
								val[1]++;
							}
							if((x+4<maplen&&y-4>=0&&!data[(x+4)*maplen+y-4])){
								val[1]++;
							}
							break;
						}
						case 5:{
							val[2]++;						
							break;
						}
					}
				} 
				
			}else{
				len1=0;
			}
			x=(i+1)>maplen?j:maplen-1-i+j;
			y=(i+1)>maplen?(i+1-maplen+j):j; 
			if(data[x*maplen+y]==flag){
				len++;
				if(x+1>=maplen||y+1>=maplen||data[(x+1)*maplen+y+1]!=flag){
					switch(len){
						case 2:{
							if(x-2>=0&&y-2>=0&&x+1<maplen&&y+1<maplen&&!data[(x-2)*maplen+y-2]&&!data[(x+1)*maplen+y+1]){
								val[3]++;
							}
							break;
						}
						case 3:{
							if((x+1<maplen&&y+1<maplen&&!data[(x+1)*maplen+y+1])&&(x-3>=0&&y-3>=0&&!data[(x-3)*maplen+y-3])){
								val[0]+=3;
							}
							if((x+1<maplen&&y+1<maplen&&!data[(x+1)*maplen+y+1])&&(x+2<maplen&&y+2<maplen&&!data[(x+2)*maplen+y+2])){
								val[0]++;
							}
							if((x-4>=0&&y-4>=0&&!data[(x-4)*maplen+y-4])&&(x-3>=0&&y-3>=0&&!data[(x-3)*maplen+y-3])){
								val[0]++;
							}
							break;
						}
						case 4:{
							if((x+1<maplen&&y+1<maplen&&!data[(x+1)*maplen+y+1])){
								val[1]++;
							}
							if((x-4>=0&&y-4>=0&&!data[(x-4)*maplen+y-4])){
								val[1]++;
							}
							break;
						}
						case 5:{
							val[2]++;
							break;
						}
					}
				} 
				
			}else{
				len=0;
			}
			
		}
	} 
	for(i=0;i<maplen;i++){
		int len=0;
		int len1=0;
		for(j=0;j<maplen;j++){
			if(data[j*maplen+i]==flag){
				len1++;
				if(j+1>=maplen||data[(j+1)*maplen+i]!=flag){
					switch(len1){
						case 2:{
							if(j-2>=0&&j+1<maplen&&!data[(j-2)*maplen+i]&&!data[(j+1)*maplen+i]){
								val[3]++;
							}
							break;
						}
						case 3:{
							if((j+1<maplen&&!data[(j+1)*maplen+i])&&(j-3>=0&&!data[(j-3)*maplen+i])){
								val[0]+=3;
							}
							if((j+1<maplen&&!data[(j+1)*maplen+i])&&(j+2<maplen&&!data[(j+2)*maplen+i])){
								val[0]++;
							}
							if((j-4>=0&&!data[(j-4)*maplen+i])&&(j-3>=0&&!data[(j-3)*maplen+i])){
								val[0]++;
							}
							
							break;
						}
						case 4:{
							if((j+1<maplen&&!data[(j+1)*maplen+i])){
								val[1]++;
							}
							if((j-4>=0&&!data[(j-4)*maplen+i])){
								val[1]++;
							}
							break;
						}
						case 5:{
							val[2]++;	
							break;
						}
					}
				}
				
			}else{
				len1=0;
			}
			
			if(data[i*maplen+j]==flag){
				len++;
				if(j+1>=maplen||data[i*maplen+j+1]!=flag){
					switch(len){
						case 2:{
							if(j-2>=0&&j+1<maplen&&!data[i*maplen+j-2]&&!data[i*maplen+j+1]){
								val[3]++;
							}
							break;
						}
						case 3:{
							if((j+1<maplen&&!data[i*maplen+j+1])&&(j-3>=0&&!data[i*maplen+j-3])){
								val[0]+=3;
							}
							if((j+1<maplen&&!data[i*maplen+j+1])&&(j+2<maplen&&!data[i*maplen+j+2])){
								val[0]++;
							}
							if((j-4>=0&&!data[i*maplen+j-4])&&(j-3>=0&&!data[i*maplen+j-3])){
								val[0]++;
							}
							
							break;
						}
						case 4:{
							if((j+1<maplen&&!data[i*maplen+j+1])){
								val[1]++;
							}
							if((j-4>=0&&!data[i*maplen+j-4])){
								val[1]++;
							}
							break;
						}
						case 5:{
							val[2]++;
							
							break;
						}
					}
				}	
			}else{
				len=0;
			}
		}
	}
	if(flag==1) return (val[2]<<14)+(val[1]<<10)+(val[0]<<5)+(val[3]<<2);
	else return (val[2]<<13)+(val[1]<<9)+(val[0]<<4)+(val[3]<<1);
	
}
int maxmin(int depth,int*data,int flag,int a,int b){
	if(!depth){
		return getvalue(data,1)-getvalue(data,-1);
	}
	if(flag==1){//轮到自己走了,选最大的 
		ch p=getchild(data,flag);
		ch p1=p->next;
		while(p->next){
			int tmp=maxmin(depth-1,p->next->ls,flag*(-1),a,b);		
			if(tmp>a) {
				a=tmp;
				if(a>b) break;
				if(depth==dddd){
					memcpy(data,p->next->ls,sizeof(int)*mapsize);
					printf("电脑埋头苦算中:%d\n",a);
				}			
			}
			free(p->ls);
			free(p);
			p=p1;
			p1=p1->next;	
		}
		while(p->next){
			free(p->ls);
			free(p);
			p=p1;
			p1=p1->next;
		}
		free(p->ls);
			free(p); 
		return a;
	}else{
		ch p=getchild(data,flag);
		ch p1=p->next;
		while(p->next){
			int tmp=maxmin(depth-1,p->next->ls,flag*(-1),a,b);
			if(tmp<b){
				 b=tmp;
				 if(a>b) break;
			}
			free(p->ls);
			free(p);
			p=p1;
			p1=p1->next;
			
		}
		while(p->next){
			free(p->ls);
			free(p);
			p=p1;
			p1=p1->next;
		}
		free(p->ls);
			free(p);
		return b;
	}	
} 
void getnextstep(int*a,int*b,int*map){	
	while(scanf("%d%d",a,b)!=2||*a<0||*a>=maplen||*b<0||*b>=maplen||map[*a*maplen+*b]){
		gets(NULL);
		printf("输入有误!请重新输入位置x,y(从0-%d)\n",maplen-1);			
	}
}
int trans(int x,int y){
	return x*maplen+y;
}
int main(void){
	map[112]=1;
//	map[0]=-1;
//	map[15]=-1;
//	map[30]=-1;
//	map[45]=-1;
//	map[1]=1;
//	map[2]=1;
//	map[3]=1;
//	ch chd=getchild(map,1);
//	while(chd->next){
//		print_map(chd->next->ls);
//		printf("%d",getvalue(chd->next->ls,1)-getvalue(chd->next->ls,-1));
//		chd=chd->next;
//	}

	print_map(map);
	while(1){
		int x,y;
		getnextstep(&x,&y,map);
		map[x*maplen+y]=-1;
		print_map(map);
		if(getvalue(map,-1)>=14000){
			printf("you win!\n");
			break;
		}	
		maxmin(dddd,map,1,-100000,100000);
		print_map(map);
		if(getvalue(map,1)>=14000){
			printf("ai win!\n");
			break;
		}
	}
	return 0;
}