c语言 人机交互,五子棋人机交互

程序分两部分:1。核心程序  2。windows图形界面程序

此处只介绍核心程序部分。下面,我们边看边侃。

//========定义文件部分=============================

#define MAX_LENGTH  19  //棋盘格数

#define COMPUTER  1    //计算机棋子

#define PLAYER    2    //玩家棋子

int qp[MAX_LENGTH][MAX_LENGTH];    //定义棋盘

int iswin;    //输赢标记,1=计算机胜,2=玩家胜,0=未分胜负;

#define RandInt(n)  (rand()%n)    //随机数宏

struct LIST

{

int id;

struct LIST *next;

}*PList=NULL,*CList=NULL;   //定义链表,Plist为玩家棋局链表指针,用于阻击,Clist为计算机棋局链表指针,用于攻击

//=========核心程序代码部分=========================

//本函数将数据add添加到链表中,并将数据按从大到小排序

//add低位为棋盘位置,高位代表该位置在当前棋局中的优先级

static int AddList(struct LIST **List,int add)

{

struct LIST *tmp=*List;

struct LIST **temp=List;

int atemp=add>>16;

int id;

struct LIST *newlist=malloc(sizeof(*newlist));

if(!newlist)

return 1;

while(tmp)

{

id=(tmp->id)>>16;

if(id<=atemp)

break;

if(id>atemp)

{

temp=&(tmp->next) ;

tmp=tmp->next;

}

}

newlist->id=add;

newlist->next=tmp;

*temp=newlist;

return 0;

}

//函数获得指定链中最大优先级的值

static int GetMax(struct LIST *List)

{

if(List)

return (List->id>>16);

return 0;

}

//函数获得指定链中的链首数据

static int GetLast(struct LIST **List)

{

if(*List)

{

int ret;

struct LIST *temp;

ret=((*List)->id&0xffff);//取低字节棋盘位置数据

temp=*List;

*List=(*List)->next;

free(temp);

return ret;

}

return 0;

}

#define DestroyList(l)  while(GetLast(&l))  //宏——销毁链表

//函数探测参数tmp指定的棋盘位置的优先级并加入相应的链表中

//凡进入该函数扫描的点,皆为棋盘上的空位置。我们将在此处分析该位置在棋局中的地位。

//tmp=y*MAX_LENGTH+x

static int AddTo_List(int tmp)

{

int temp;

int py,px;

py=tmp/MAX_LENGTH;

px=tmp%MAX_LENGTH;

//探测计算机在此位置的优先级

qp[py][px]=COMPUTER;

temp=scan(px,py,0);//最后一个参数必须为0,否则将进入死循环。

AddList(&CList,(temp<<16)+tmp);

//探测玩家在此位置的优先级

qp[py][px]=PLAYER;

temp=scan(px,py,0);//同上。

AddList(&PList,(temp<<16)+tmp);

qp[py][px]=0;//恢复空子状态。

return 0;

}

//函数对指定的棋盘位置进行格式化全方位扫描,并返回该位置在棋局中的优先级

//进行格式化扫描,可以减少扫描的冗余度,提高扫描效率。这对于大棋盘,如本例的19*19

尤为适用。

//mode控制扫描方式,0=试验性扫描,不将扫描结果加入链表。1=实战性扫描,将扫描结

果加入链表。程序可利用链表中的数据,进行下一步棋的决策。

//px,py在循环中反复使用,我们为其加上const标记,防止不必要的麻烦。

static int scan(const int px,const int py,int mode)

{

register int i;

int play=qp[py][px];//获得该位置棋子

int ret=0;rtemp=0;//返回值

int temp[4];

int base;

base=RandInt(8);//生成随机数,使用不同的起点,使棋局具有一定的随机性

//对该棋子八个方向进行扫描

for(i=0;i<8;i++)

{

int x=px;

int y=py;

int side=0;//边界标记

register j;

switch((base+i)%8)

{

case 0://x–

{

//格式化,首先定位到第一个不与play相同的位置。

//这样,在此方向上,我们便可以只考虑四格棋盘位置,大大减少了不必要的开销。

do

{

x–;

}while(x> =0&&qp[y][x]==play);

//该方向前面没有充足的位置,置标记位为1。这样,我们可以略去无效探测。

if(x+5>MA X_LENGTH)

{

side=1;

}

else

{

x+=2;//沿该方向向前,跳过第一个与play相等的位置,对前方四个位置进行纪录

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);//将棋盘位置合成整型数据保存

x++;

}

}

break;

}

case 1://x–;y–;

{

do

{

x–;

y–;

}while(x> =0&&y>=0&&qp [y][x]==play);

if(x+5>MA X_LENGTH||y+5>MAX_LENGTH)

{

side=1;

}

else

{

x+=2;

y+=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

x++;

y++;

}

}

break;

}

case 2://y–;

{

do

{

y–;

}while(y> =0&&qp[y][x]==play);

if(y+5>MA X_LENGTH)

{

side=1;

}

else

{

y+=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

y++;

}

}

break;

}

case 3://x–;y++;

{

do

{

x–;

y++;

}while(x> =0&&y

if(x+5>MA X_LENGTH||y-5<0)

{

side=1;

}

else

{

x+=2;

y-=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

x++;

y–;

}

}

break;

}

case 4://x++;

{

do

{

x++;

}while(x< MAX_LENGTH&&qp[y][x]==play);

if(x-5<0)

{

side=1;

}

else

{

x-=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

x–;

}

}

break;

}

case 5://x++;y–;

{

do

{

x++;

y–;

}while(x< MAX_LENGTH&&y>=0&&qp [y][x]==play);

if(x-5<0| |y+5>MAX_LENGTH)

{

side=1;

}

else

{

x-=2;

y+=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

x–;

y++;

}

}

break;

}

case 6://x++;y++;

{

do

{

x++;

y++;

}while(x< MAX_LENGTH&&y

if(x-5<0| |y-5<0)

{

side=1;

}

else

{

x-=2;

y-=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

x–;

y–;

}

}

break;

}

case 7://y++;

{

do

{

y++;

}while(y< MAX_LENGTH&&qp[y][x]==play);

if(y-5<0)

{

side=1;

}

else

{

y-=2;

for(j=0;j<4;j++)

{

temp[j]=(MAX_LENGTH*y+x);

y–;

}

}

break;

}

}

if(!side)

{

//该部分是决定优先级的关键部分,本例只使用了简单的优先级决定方案,可以通过修改该部分使程序具有更高的智能。

int t=0;

int k[4]={8,4,2,1};

int kt[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};

//对纪录的棋盘位置进行检测

for(j=0;j<4;j++)

{

int jx=temp[j]%MAX_LENGTH;

int jy=temp[j]/MAX_LENGTH;

int p=qp[jy][jx];

if(p==play)

t+=k[j];

else if(p==0)//可利用位置

{

if(mode)

AddTo_List(temp[j]);//对可利用位置进行探测纪录

}

else//存在阻隔

{

t–;//此处有可能使t=-1,因为t用于数组下标,所以我们必须将其排除。

if(t<0)

t=0;

break;

}

}

if(t==0xf&&mode)//若五子连成一线,返回零

return 0;

if(retrtemp)      {      int t=ret;      ret=rtemp;      rtemp=t;       }       }    }

} return (ret+rtemp);//当前局势}

//初始化棋盘

void initqp(void)

{

register int i;

register int j;

for(i=0;i

for(j=0;j

qp[j]=0;

iswin=0;

srand(time(NULL));//初始化随机生成器

}

//主函数,检测玩家所走位置,返回计算机所走位置

//px,py代表玩家棋子位置。

int five(int px,int py)

{

struct LIST **list;

int tmp;

if(qp[py][px]!=0)//该位置已存在棋子

{

return -1;

}

//对玩家所走棋子进行扫描

qp[py][px]=PLAYER;

if(!scan(px,py,1))

{

//玩家胜

DestroyList(PList);

DestroyList(CList);

iswin=PLAYER;

return 0;

}

if(GetMax(PList)>GetMax(CList))//确定攻击性

list=&PList;//防御

else

list=&CList;//攻击

while(tmp=GetLast(list))//获取最大优先级的棋盘位置

{

px=tmp%MAX_LENGTH;

py=tmp/MAX_LENGTH;

if(qp[py][px]!=0)//该位置不为空则继续循环

{

if(GetMax(PList)>GetMax(CList))//重新确定攻击性

list=&PL ist;

else

list=&CL ist;

continue;

}

break;

}

if(!tmp) //在链表中未找到数据则生成随机数据

{

do

{

px=RandInt(MAX_LENGTH);

py=RandInt(MAX_LENGTH);

}while(qp[py][px]!=0);

}

//计算机走子

qp[py][px]=COMPUTER;

if(!scan(px,py,1))

{

//计算机胜

DestroyList(PList);

DestroyList(CList);

iswin=COMPUTER;

}

return ((py*MAX_LENGTH)+px);//返回走子位置

}

核心程序部分就这么多,图形界面部分只需调用函数initqp()初始化棋盘,然后不断调用函数five(int px,int py)即可。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值