正文

简单五子棋人机对弈(19×19)一2006-06-29 10:39:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/bakers/16259.html

分享到:

【概述】五子棋是一种大众喜爱的游戏,其规则简单,变化多端,非常富有趣味性何消遣性。这里设计了一个简单的五子棋程序,采用对空格点进行评分排序的算法。 近来随着计算机的快速发展,各种棋类游戏被纷纷请进了电脑,使得那些喜爱下棋,又常常苦于没有对手的棋迷们能随时过足棋瘾。而且这类软件个个水平颇高,大有与人脑分庭抗礼之势。其中战胜过国际象棋世界冠军-卡斯帕罗夫的“深蓝”便是最具说服力的代表;其它像围棋的“手淡”、象棋的“将族”等也以其优秀的人工智能深受棋迷喜爱;而我也做了一个“无比”简单的五子棋算法。  总的来说(我们假定您熟悉五子棋的基本规则),要让电脑知道该在哪一点下子,就要根据盘面的形势,为每一可能落子的点计算其重要程度,也就是当这子落下后会形成什么棋型(如:“冲四”、“活三”等),然后通览全盘选出最重要的一点,这便是最基本的算法。 主程序模块包括:数据结构,评分规则,胜负判断,搜索最优空格的算法过程。 【关键字】人工智能,博弈树,五子棋,无禁手,评分,搜索,C,随机。 【环境】XP/TC3.0 【算法及解析】(无禁手) 一.   数据结构: 本程序中只使用了一个19×19的二元结构数组如下定义: Typedef  Struct {     int     player;             int     value[8][5];             long int  score;        }map[19][19]; 其中map[i][j]保存i行j列棋子信息,player为下棋方,value数组记录八个方向的连续5个棋子的信息,为以后评分服务。Score为空格评分。 以及数据结构可以满足初级人机对弈程序的功用。 对比其他程序结构: 王小春五子棋源码:该程序采用链表节点结构,保存下子信息,该结构主要为悔棋提供方便(虽该源码为开发悔棋功能)  Typedef struct Step   {    int m;    int n;    char side;   }; 为链表clist节点,m,n表示两个坐标值,side表示下子方相对于我的程序中的player. 另外该程序还使用一个二维数组map[][],来保存棋盘信息。 二.预定义单元 #define blank   0 #define black   1 #define white   2 #define NUM_HIGH 19 #define NUM_LINE 19 #define man 1 #define bot 2 其中blank表示空白点,black该点放黑子(即man),white该点放白子(即robot) NUM_HIGH,NUM_LINE分别定义棋盘的高度与宽度。 Turn 为轮流下子方。 三.评分机制判断是否能成活四或者是双死四或者是死四活三,如果是机器方的话给予10,000,000; 判断是否已成冲四,如果是机器方的话给予6,000,000; 判断是否成死3活3,如果是机器方的话给予1,500,000;; 判断是否已成双活2,如果是机器方的话给予100,00;  判断是否能成活2,如果是机器方的话给予70,000; 判断是否能成死2,如果是机器方的话给予30,000。 四.函数定义及其功能。 1.Void init()    初始化棋盘bgi图形与棋盘棋型。    将棋盘标记map[][].player都置为blank(空白),各点8方向的连续五个棋子信息也初始为0,各点评分数也置为0。  void init() {     int i, j, m, n;     int gdriver=DETECT,gmode;     initgraph(&gdriver,&gmode,"..\\bgi");     for( i = 0; i < 19; i++)         for( j = 0; j < 19; j++)         {             map[i][j].player = blank;             for( m = 0; m < 8; m++)                 for( n = 0; n < 4; n++)                     map[i][j].value[m][n] = blank;             map[i][j].score = blank;         } } 2.Void paint() 画棋盘函数,本五子棋程序使用的是标准围棋棋盘,规格19×19,每格25大小(象素),并且规定man棋子颜色为黑,robot为白色,黑棋优先。最后初始化光标(开始位置)位置。 void paint() {     int i, j;     clearviewport();     setbkcolor(BLUE);//设置背景色     setcolor(WHITE);//设置作图色     for(i = 20; i <= 470; i+= 25)         line( 20, i, 470, i);     for(j = 20; j <= 470; j+= 25)         line( j, 20, j, 470); outtextxy( 525, 160, "Man");     setcolor(DARKGRAY);     setfillstyle( SOLID_FILL, DARKGRAY);     pieslice( 545, 185, 0, 360, 10);     setcolor(WHITE);     outtextxy( 520, 210, "Robot");     setcolor(WHITE);     setfillstyle( SOLID_FILL, WHITE);     pieslice( 545, 235, 0, 360, 10);     moverel( 245, 245);//开始游戏时 man 下棋的位置 } 3.void main()   主函数控制。初始化图形及棋型,规定黑子优先,画棋盘,开始下子。   (略) 4.Void human() Man下棋函数,其中添加了防棋子覆盖控制。 void human(void) {     char ch=1;     int size, x, y;     void *buf;     while( ch != 32 )      {         ch = getch();         putimage( getx()-10, gety()-10, buf, COPY_PUT);         if( ch == 27)   //ESC退出             exit(1);         if( ch == 'w' || ch == 'W') //移动控制单元             moverel( 0, -25);         else if( ch == 's' || ch == 'S')             moverel( 0, 25);         else if( ch == 'a' || ch == 'A')             moverel( -25, 0);         else if( ch == 'd' || ch == 'D')             moverel( 25, 0);         if( getx() < 20)    //防止man下棋越界             moverel( 25, 0);         if( getx() > 470)             moverel( -25, 0);         if( gety() < 20)             moverel( 0, 25);         if( gety() > 470)             moverel( 0, -25);         size = imagesize( getx()-10, gety()-10, getx()+10, gety()+10);         buf = malloc(size);         getimage( getx()-10, gety()-10, getx()+10, gety()+10, buf);         if( man == black)         {             setcolor(DARKGRAY);             setfillstyle(SOLID_FILL, DARKGRAY);         }         else         {             setcolor(WHITE);             setfillstyle(SOLID_FILL, WHITE);         }         pieslice( getx(), gety(), 0, 360, 10);  //光标显示 x = ( getx() - 20) / 25;  //计算 man 下棋的棋盘位置 y = ( gety() - 20) / 25; if( ch == 32 && map[y][x].player != 0 ) //防止 man 棋子覆盖     ch = 1;     }     map[y][x].player = man;     mark( x, y); } 5.Void mark(int,int) 标记棋子,robot标记为白棋,man标记为黑棋。 在程序结束添加了判断下子方是否胜出(结束)判断函数,check(int,int). void mark( int x, int y)  //标记棋子 {     int i, j,m,n;     m=x;     n=y;     if( turn == man)     {         setcolor(DARKGRAY);         setfillstyle(SOLID_FILL, DARKGRAY);     }     else     {         setcolor(WHITE);         setfillstyle(SOLID_FILL, WHITE);     }     pieslice( (x * 25 + 20), (y * 25 + 20), 0, 360, 10);  //棋盘前端显示     setcolor(RED);     if( turn == bot)         for( x = 0; x < 19;x++)                 //bot下完子后,对评分机制初始化             for(y = 0; y < 19; y++)                 if( map[x][y].player == blank)                 {                     for( i = 0; i < 8; i++)                         for( j = 0; j < 5; j++)                             map[x][y].value[i][j] = blank;                     map[x][y].score = blank;                 }     check(n,m); } 6.void check(int,int) 判断程序是否结束函数(一方胜利),共判断了四个方向:水平方向,竖直方向,左斜线方向,右斜线方向。如果发现存在超过或等于5各连续棋子,则判断一方胜利,调用win(int)函数,显示结果,程序结束。 程序结尾,添加交换下子部分。 void check(int m,int n) {     int WinTag=map[m][n].player;     int i=m,j=n,level=1;     //outtextxy((m * 25 + 20), (n * 25 + 20),".");     if(WinTag==man) outtextxy((n* 25 + 17), (m * 25 + 17),"M");     else outtextxy((n * 25 + 17), (m * 25 + 17),"R");     //水平位置判断 while(map[i-1][j].player==WinTag&&i>=1) {         level++;  i--; } i=m; while(map[i+1][j].player==WinTag&&i<(NUM_LINE-1)) {         level++;  i++; } if(level>=5)win(WinTag); level=1; //竖直方向判断 i=m;     j=n; while(map[i][j-1].player==WinTag&&j>=1) {         level++;  j--; } j=n; while(map[i][j+1].player==WinTag&&j<(NUM_HIGH-1)) {         level++;  j++; } if(level>=5)win(WinTag); level=1; //左斜线判断 i=m;    j=n; while(map[i-1][j-1].player==WinTag&&i>=1&&j>=1) {         level++; i--;j--; } i=m;       j=n; while(map[i+1][j+1].player==WinTag&&i<(NUM_LINE-1)&&j<(NUM_HIGH-1)) {         level++;  i++; j++; } if(level>=5)win(WinTag); level=1; //右斜线判断 i=m;        j=n; while(map[i+1][j-1].player==WinTag&&i<NUM_LINE&&j>=1) {         level++;   i++; j--; } i=m;       j=n; while(map[i-1][j+1].player==WinTag&&i>=1&&j<(NUM_HIGH-1)) {         level++; i--; j++; } if(level>=5)win(WinTag);    //交换下棋顺序     if( turn == man)     {         turn = bot;   robot();     }     else     {         turn = man;   human();     } 7.Void win(int) void win( int winner) {     char ch;     setbkcolor(LIGHTGRAY);     setcolor(YELLOW);     //ch = getch();     while( ch != 27)     {         if(winner==man)outtextxy( 240, 210, "You are the winner !");         else outtextxy( 240, 210, "You are lost !");         outtextxy( 245, 250, "Press ESC to Exit!");         printf("%d",winner);         ch = getch();     }     closegraph();     exit(1); }  } 下一页

阅读(7569) | 评论(4)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册