五子棋AI智能算法设计和测试方法

五子棋AI智能算法设计和测试方法
先前发了几篇五子棋游戏程序设计的博文,设计了游戏程序,也设计了AI智能奕棋的算法,运行程序检测算法的可行性,完成人机模式游戏功能的设置。这还不够,还要提高算法的实战水平,即算力和应用水平。

对于人机对战的电脑智能应子算法,参阅很多五子棋书籍棋谱和五子棋竞赛的对抗棋谱。我感到白棋的后手防御算法很难取胜,棋界有黑棋高手先手必胜一说。算法么想了很多,既然是人工智能下棋就得按人的思路来算计。棋书阐述有许多思路和棋局解说。如活四冲四,嵌五,活三嵌四,活二嵌二。这些是高级棋手的总结。我就按此思路用加权计权方法来表现此类各种情况。
我对算法的思路是:黑棋的进攻点就是白棋的防守点,反之,白棋的进攻点就是黑棋的防守点。我采用一次遍历棋盘各点位的方法,凡有黑子和白子就判断其四周的空白点,即可下子位,评估棋势加权计分。棋势就是单子、活二嵌二、活三嵌三嵌四、活四冲四嵌五。各个棋势的交点就叠加计分,高分点就是双方博弈的必争点。算法的要点是:独子成二是起点,连二到连三是重点,关键的要点是三连子到四连五连。这这三点就分出权重的棋势。活三02220两边的点位是,先手是绝杀点,后手是防守逢三必堵。眠三122200棋势,空位下子成冲四,这是抢先手来改势扩势来进攻。若抓到冲四加活三叠加进攻点,权分叠加计权,就能绝杀对方。我的算法思路就这样。算法想白棋后手取胜,就在白棋的棋势上加小分,这样利于白棋在同等情况下能争得先手,反战进攻取胜。想法很简单,写算法也不难,而对于棋势的加权分的估量较难。

图例:

14aa83c1d8ec474faa91a967192d3860.png

 

人机模式例:人执黑,AI 执白,无禁手则黑棋可胜,有禁手就AI胜。

419ead73b494490fa9fdb09eb0d309e6.png

816b8c0437ab4400be14a16a8848a638.png 

 

五子棋博弈要算杀,算杀就是计算必杀之局。必杀局有双活三,双冲四,冲四加活三,嵌五加活三,嵌五加冲四,这些必杀局就是必胜法宝。此算法的要点就是如何加权必杀局棋势的加权分。文后附源码中的testAIq( ),算法至要可见一斑,自己体会一下。
算杀的最高境界是做杀,预判算出必杀点提前几子做出必杀局。此谓奕道高手中的高手,乃高高手也。此种算法也就是编程界的高手,是谓大咖也。我望之有些高仰,自感境界还没到。叠加计权计分有趋向于此类。还要努力,锲而不舍,持之以恒。

另外在设计上加了算法的测试方法。用来检测和改进算法。
测试算法的方法:
一是:程序运行时在黑白落子周边的空位(即可下子位)显示加权计算的分值,查看加权计分情况。最高分点位画出黄色标记点,即AI选取的下子位。
在双人模式时可以直观的看到AI加权计算的分值,以及选取下子位的过程。
在人机模式时由人下黑子检测白棋的防守和进攻情况 。依据此优化和改进算法。

二是:设置自动演示功能autotest(),不需手动模拟对奕过程,连续点击演示按钮逐步显示黑白双方由机器选位下子过程。这就是对战演示功能。
增加26个开局定式对战演示。用以观察加权计分的设置情况,以此来测试和改进算法。也可以每步根据AI计权黄点黑白双方落子位来下子,这样可慢慢地观察加权计分情况。当然在演示功能时可介入手动操作下子,这是方法的灵活应用。

73e2a8c417b54cba895b10eb42508ab3.png

 

五子棋程序设置双人对奕,人机模式,对战演示三种模式。设置悔棋,记录功能,有禁手设置。另有复盘功能设置。

 AI智能奕棋的算法testAIq( ),主要是检测算法,测试算法的可行性。程序设置的对战演示就是为了测试算法,此为研究五子棋算法提供一些参考。
此算法加权偏重于白棋,主要是研究如何对付”黑先必胜”。研究白棋抢先手,拦堵黑棋,反转取胜。

测试了好几个局的例子,白棋的攻防还是可以的。然而如
(例11 例12 例13例15 例16等),
黑棋还是蛮厉害的,如白棋挡不住,就还是黑棋胜。

10fe470b40144ab6b35af189d1f7cabc.png

9bff560cba2e4c22b2b4aeed28f4aab0.png 

c6bfa896d85e48ab89af038894ca6b01.png 

a538e7408df64d958ee7d6af49a71623.png 

c5a6afd1331f483192ccdc2e6a6ee3bc.png 

 

例4花月局,例7金星局,例8松月局
白棋防守封堵都很漂亮,抢先手反攻取胜,可供参考研究。

7187d639cdd748dc9265d33762980f60.png

b6ebdd87637c4b6b8856064190927ed5.png 

f9edd01af8dc42608cc26e9a9b1a6230.png 

 

例24斜月局,黑棋进攻力度不够,黑21手F8和23手J12失误而失先手,白棋反败为胜。

f32b9a6733b84062a0d89a8f32719c18.png

469a407602c14b3bb8a008b29e608f56.png 

 

我测试了26定式局和人机对战的好多局,本文仅例出了一部分。感兴趣的朋友可自己来玩下。此游戏程序可成为喜欢五子棋游戏的练手程序。下面源码可在安卓手机上编译为桌面游戏。

42ac0eca53f448f994e0e4aef3a4b1cf.png

6ff1fb1afa9842bead30cfb1468042c4.png 

 

下面是五子棋游戏程序设计的源码:
//****************************************
//*  五子棋  Gobang  AI   v.3.0.1  (测试版)
//*  人机对战  双人对奕  对战演示           
//*  编制人:张纯叔    micelu@126.com
//*   myspringc  v2.7   编译      安卓手机上编程       
//****************************************
Canvas cs;    //画布
string sBarDes[10];    //按钮
int nBarId[10];
string sMenu[50];       //菜单
int nMenu[50];
float src[4];  //ClearDraw (cls) clear screen
string s1,s2,s3,s4,s5,s6,s7,s8 ;     //显示
string s,ss,ss1,ss2,ss3,ss4,ss9 ;
 int dx,dy;        //draw X, Y
FileInput filebox;   //file Input box加底图
int size[2];    //load picture size
string fname;  //filename
int i,j,t ;           //t = times
int a,b ;           //tab for print
int pn[250];     // pn  0=" " , 1=black , 2=white
int n;                // 225 棋子编码号pn(250)容错
int px,py;        // piece x,y
int context;    //canvasProc 触控
int obj;
int id;
int event;
int dn,dn1 ;        //下子计数
 int isDo;      //游戏操作控制 1=可下子,0=不可下
int B,W,k;   //detect win Black White
string cordp,cordp1;   //record pn & G9
int cord;        //record switch
int mode;      //0=人人,1=人机
int wn;        //演示
 int sn,  kn ;   //sn AI计权位号 1 to 225
int dwn[120];    //记录,下子60回合120子为和棋
 int col,row ;
 int gn ;    //game round number
 int fudat[200];      //复盘数据
int fusum;    //复盘记录总数
int sd;         //复盘
 int jqn[225];      //计权数
int jqf,jqfn ;        //计权分,优选点位码
int js[225];         //禁手设置
int jsset ;    //0=on 有禁手,1=off 无禁手
double smode ;   // 开局模式 26式
int num ;   // 开局式号
//**********

main(){
setDisplay(1);
  cs.SetBackground(200,200,200);
  cs.Active();
   sBarDes[0]="开始游戏";
   nBarId[0]=100;
   sBarDes[1]="选择模式";
   nBarId[1]=101;
   sBarDes[2]="黑棋下子";
   nBarId[2]=102;
   sBarDes[3]="白棋下子";
   nBarId[3]=103;
   sBarDes[4]="退出程序";
   nBarId[4]=104;
   sBarDes[5]="记录v";
   nBarId[5]=105;
   setToolBarHeight(6);
   setButtonTextSize(13);
   setToolBarBackgroundColor(255,250,250,250);
   setButtonColor(255,220,220,220);
   setButtonTextColor(255,0,0,150);
   setToolBar(100,myToolBarProc,sBarDes,nBarId,6);

   sMenu[0]="选择开局定式 ( 26种定式 )";
   nMenu[0]=200;
   sMenu[1]="选择游戏模式 ( 双人 , 人机 )";
   nMenu[1]=201;
   sMenu[2]="悔棋";
   nMenu[2]=202;
   sMenu[3]="复盘";
   nMenu[3]=203;
   sMenu[4]="禁手设置 ( on )";
   nMenu[4]=204;
   sMenu[5]="查看记录";
   nMenu[5]=205;
   sMenu[6]="显示棋板";
   nMenu[6]=206;
   sMenu[7]="退出";
   nMenu[7]=207;
   setMenu(200,myMenuProc,sMenu,nMenu,8);
   setTitle("五子棋 (AI智能版) V.3.0.1   ");
//*************************
  cs.SetProc (context, mycanvasProc); //触控设置
      mode=0 ;  
      s7="游戏模式:双人对奕"; 
      wn=0 ;   //测试演示
      gn=0;    //round number
      gamestart ();    //游戏初始界面
//draw title ****
        ss3="五子棋 (AI智能版)";
   cs.SetTextSize (60);
   cs.SetTextStyle (1);
     cs.SetFillMode (1);//0不填色,1填色
     cs.SetColor(255,160,60,40);
         cs.DrawText (ss3,95,505);
     cs.SetColor(255,0,250,0);
         cs.DrawText (ss3,90,500);
     cs.SetFillMode (0);//0不填色,1填色
    cs.SetColor(255,250,250,0);
         cs.DrawText (ss3,91,501);
     cs.SetFillMode (1);//0不填色,1填色
     cs.SetTextSize (36);
     cs.SetColor(255,150,50,250);
          cs.DrawText ("(测试版)",255,555);
    cs.Update();  
while (){}
 }//main ()

mycanvasProc (int context,int obj,int id,int event,float x,float y){          
      if (isDo==0) return ;   //结束标志   
    kn=kn+1;     //延时,  减少闪屏
    if ((kn-kn/2*2)==0){ kn=0; }else{  return;  }  
       board ();   //redraw board
  //** get chess pieces position X , Y 
   if (x>40&&x<610&&y>40&&y<610){
      px=(int)(x/40)*40;    //棋盘区棋位取整数
      py=(int)(y/40)*40;
           dx=px/40; 
           dy=py/40;
   cs.SetFillMode (0);//0不填色,1填色
   cs.SetColor (255,250,0,0);  //chess flag选子标记
   cs.DrawRect (px-20,py-20,px+20,py+20);  
             }    
   //复盘和悔棋按钮
    if (x>40&&x<180&&y>900&&y<960){
         replay () ;    }    //复盘
    if (x>210&&x<350&&y>900&&y<960){
         undo () ;      }   //悔棋
    if (x>380&&x<520&&y>900&&y<960){
         if (mode==0) autotest () ;  }    //算法测试
 
   cs.SetTextStyle (0);
   cs.SetFillMode (1);//0不填色,1填色
   cs.SetColor (255,240,240,240);  //clear n
   cs.DrawRect (520,760,605,800);
      n=(dy-1)*15+dx;  //提示选定棋子pn number      
       row=15-(n/15) ;
       col=(n-(n/15*15)) ;
       if (col==0){ col=15 ;    row=row+1 ;   }
       swapabc () ;   //col n to ABC return ss
       s=ss+" "+intToString (row) ;
       s5="选定落子位 >>   "+s;
   if (x<40||x>610||y<40||y>610) s5="  ";  //棋盘位越界
    cs.SetColor(255,0,0,150);
     cs.SetTextSize (30);
   cs.DrawText (s5,328,790); //提示选定棋子
   cs.Update ();
}//mycanvasProc 

autotest (){
  //用于检测AI智能下子算法 testAIq ()
  //黑白棋用同一个算法下子很难区分算法的优劣,
  //要设计二种算法分别以黑棋VS白棋才能显示出
  //算法的优劣。下面代码只可检测算法的可行性。
      s7="游戏模式:对战演示"; 
  if (isDo==0||dn>75) {
          ss9="( 演示 ) ";   print ss9; 
          cs.DrawText (ss9,655,(dn+2)*16);        
          isDo=0 ;  return ;    }  //结束标志,测试75子   
   if (mode==1) return ; //双人模式可演示
   if (dn==0) {   //设定首子黑先天元位
         n=113;  wn=0 ;  black_do () ;   }
  //注:对战演示模式可按选定的开局定式演示
 
      wn=wn+1 ;
         testAIq () ;    //智能计权取得下子点位
      if (wn>1) wn=0 ;    //轮流下子
      if (wn==1) white_do () ;  //白棋下子
      if (wn==0) black_do () ;  //黑棋下子         
         detect () ;     //判胜负
 }//autotest ()


//AI智能下子算法求解方案:
//(一) 四连情况,黑棋下子,黑冲四嵌五,白必应子,若白无活四 022220 冲四 122220 022221 和嵌五 22022 22202 20222 则必应,有则先着取胜  

//* (二) 三连情况,黑棋下子,黑成活三嵌四,若白无活三 02220 嵌四 2022 2202 则必应, 有则先着下子成活四     

//(三) 二连情况,黑棋下子,
 //有活二01100嵌三01010,010010基本都是这样, 二连应子:抢先手原则,白棋先找自己的活二嵌三 ,先下子成活三嵌四      

//(四) 开局应首子,定标黑子 pn113,白应首子, 大多棋谱是 应上(直指) pn98,上右(斜指) pn99,暂定此应起首三子:按棋谱开局法

//*黑白双方博弈,加权计分,黑攻方进攻点就是白守方防守点。叠加加权计分,乃此算法要点。计分累加标记此点,取最高分作为进攻点和防守点。
//下面的 testAIq () 是测试算法。   

testAIq (){
 //人机对战AI选子,加权计算
   for (i=1;i<=225;i++) {
         jqn[i]=0 ;    }      //scan init
   //遍历加权
  for (i=1;i<=15;i++){    //遍历scan B & W 子
  for (j=1;j<=15;j++){    
           k=(i-1)*15+j ;    //pn(n) number
  //独子 左右上下 二对角 八方
      if (pn[k]==2){
        if (pn[k-1]==0) jqn[k-1]= jqn[k-1]+20 ;
        if (pn[k+1]==0) jqn[k+1]= jqn[k+1]+20 ;
        if (pn[k-15]==0) jqn[k-15]= jqn[k-15]+20 ;
        if (pn[k+15]==0) jqn[k+15]= jqn[k+15]+20 ;
        if (pn[k-14]==0) jqn[k-14]= jqn[k-14]+20 ;
        if (pn[k+14]==0) jqn[k+14]= jqn[k+14]+20 ;
        if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+20 ;
        if (pn[k+16]==0) jqn[k+16]= jqn[k+16]+20 ;
                }//pn

 //二连  002200  为成活三冲四进攻点
    if (j>1&&j<13){
    if (pn[k]==2&&pn[k+1]==2){  //左右
       if (pn[k-1]==0) jqn[k-1]= jqn[k-1]+200 ;   
       if (pn[k-1]==0&&pn[k-2]==0) { jqn[k-2]= jqn[k-2]+310 ;   jqn[k-1]= jqn[k-1]+310 ;  }
       if (pn[k+2]==0) jqn[k+2]= jqn[k+2]+200 ;
       if (pn[k+2]==0&&pn[k+3]==0) { jqn[k+3]= jqn[k+3]+310 ;   jqn[k+2]= jqn[k+2]+310 ;  }
            }     }

    if (i>1&&i<13){
    if (pn[k]==2&&pn[k+15]==2){  //上下  
        if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+200 ;
        if (pn[k-15]==0&&pn[k-30]==0) { jqn[k-30]= jqn[k-30]+310 ;   jqn[k-15]= jqn[k-15]+310 ;  }
        if (pn[k+30]==0) jqn[k+30]= jqn[k+30]+200 ; 
        if (pn[k+30]==0&&pn[k+45]==0) { jqn[k+45]= jqn[k+45]+310 ; jqn[k+30]= jqn[k+30]+310 ;  }
              }     }

   if (i>1&&i<13&&j>3&&j<15){
   if (pn[k]==2&&pn[k+14]==2){  //左对角
        if (pn[k-14]==0) jqn[k-14]= jqn[k-14]+200 ;
        if (pn[k-14]==0&&pn[k-28]==0) { jqn[k-28]= jqn[k-28]+310 ;  jqn[k-14]= jqn[k-14]+310 ;  }
        if (pn[k+28]==0) jqn[k+28]= jqn[k+28]+200 ; 
        if (pn[k+28]==0&&pn[k+42]==0) { jqn[k+42]= jqn[k+42]+310 ;   jqn[k+28]= jqn[k+28]+310 ;  }
            }   }

  if (i>1&&i<13&&j>1&&j<13){
  if (pn[k]==2&&pn[k+16]==2){   //右对角
       if (pn[k-16]==0) jqn[k-16]= jqn[k-16]+200 ;
       if (pn[k-16]==0&&pn[k-32]==0) { jqn[k-32]= jqn[k-32]+310 ;  jqn[k-16]= jqn[k-16]+310 ;  }
       if (pn[k+32]==0) jqn[k+32]= jqn[k+32]+200 ; 
       if (pn[k+32]==0&&pn[k+48]==0) { jqn[k+48]= jqn[k+48]+310 ;  jqn[k+32]= jqn[k+32]+310 ;  }
             }       }

//二连  020020
  if (j>1&&j<13){
  if (pn[k]==2&&pn[k+3]==2){  //左右
       if (pn[k-1]==0&&pn[k+1]==0)  jqn[k+1]= jqn[k+1]+510 ;
       if (pn[k+4]==0&&pn[k+2]==0)  jqn[k+2]= jqn[k+2]+510 ;       }  }

  if (i>1&&i<13){
  if (pn[k]==2&&pn[k+45]==2){  //上下
       if (pn[k-15]==0&&pn[k+15]==0)  jqn[k+15]= jqn[k+15]+510 ;
       if (pn[k+60]==0&&pn[k+30]==0)  jqn[k+30]= jqn[k+30]+510 ;     }  }

if (i>1&&i<13&&j>3&&j<15){
   if (pn[k]==2&&pn[k+42]==2){  //左对角
       if (pn[k-14]==0&&pn[k+14]==0)  jqn[k+14]= jqn[k+14]+510 ;
       if (pn[k+56]==0&&pn[k+28]==0)  jqn[k+28]= jqn[k+28]+510 ;     }  }

 if (i>1&&i<13&&j>1&&j<13){
 if (pn[k]==2&&pn[k+48]==2){   //右对角
       if (pn[k-16]==0&&pn[k+16]==0)  jqn[k+16]= jqn[k     +16]+510 ;
       if (pn[k+64]==0&&pn[k+32]==0) jqn[k+32]= jqn[k+32]+510 ;    }  }

//嵌三   02020    为成活三冲四进攻点
  if (j>1&&j<13){
if (pn[k]==2&&pn[k+1]==0&&pn[k+2]==2){  //左右
          jqn[k+1]= jqn[k+1]+510 ;   
      if (pn[k-1]==0)  jqn[k-1]= jqn[k-1]+310 ; 
      if (pn[k+3]==0)  jqn[k+3]= jqn[k+3]+310 ; } }

  if (i>1&&i<13){
if (pn[k]==2&&pn[k+15]==0&&pn[k+30]==2){  //上下
          jqn[k+15]= jqn[k+15]+510 ;   
      if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+310 ; 
      if (pn[k+45]==0)  jqn[k+45]= jqn[k+45]+310 ; } }

  if (i>1&&i<13&&j>3&&j<15){
if (pn[k]==2&&pn[k+14]==0&&pn[k+28]==2){//左对角
          jqn[k+14]= jqn[k+14]+510 ;   
      if (pn[k-14]==0)  jqn[k-14]= jqn[k-14]+310 ; 
      if (pn[k+42]==0)  jqn[k+42]= jqn[k+42]+310 ; } }

  if (i>1&&i<13&&j>1&&j<13){
if (pn[k]==2&&pn[k+16]==0&&pn[k+32]==2){//右对角
          jqn[k+16]= jqn[k+16]+510 ;   
      if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+310 ; 
      if (pn[k+48]==0)  jqn[k+48]= jqn[k+48]+310 ; } }

//三连,眠三抢冲四  12220  02221 逢三必堵
  if (j>1&&j<13){
  if (pn[k]==2&&pn[k+1]==2&&pn[k+2]==2){  //左右
  //三连成嵌五  +550 叠加分进攻点
     if (pn[k-1]==0)  jqn[k-1]= jqn[k-1]+310 ;   
     if (pn[k-1]==0&&pn[k-2]==0) jqn[k-1]= jqn[k-1]+410 ;   //必杀点加权分
     if (pn[k-1]==0&&pn[k-2]==0)  jqn[k-2]= jqn[k-2]+550 ;   
     if (pn[k+3]==0)  jqn[k+3]= jqn[k+3]+310 ;   
     if (pn[k+3]==0&&pn[k+4]==0) jqn[k+3]= jqn[k+3]+410 ; 
     if (pn[k+3]==0&&pn[k+4]==0)   jqn[k+4]= jqn[k+4]+550 ;    }  }

 if (i>1&&i<13){
 if (pn[k]==2&&pn[k+15]==2&&pn[k+30]==2){  //上下
     //三连成嵌五  +550 叠加分进攻点
     if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+310 ;   
     if (pn[k-15]==0&&pn[k-30]==0) jqn[k-15]= jqn[k-15]+410 ; 
     if (pn[k-15]==0&&pn[k-30]==0)  jqn[k-30]= jqn[k-30]+550 ;   
     if (pn[k+45]==0) jqn[k+45]= jqn[k+45]+310 ;   
     if (pn[k+45]==0&&pn[k+60]==0) jqn[k+45]= jqn[k+45]+410 ; 
     if (pn[k+45]==0&&pn[k+60]==0) jqn[k+60]= jqn[k+60]+550 ;  }  }
  
  if (i>1&&i<13&&j>3&&j<15){
if (pn[k]==2&&pn[k+14]==2&&pn[k+28]==2){//左对角
     //三连成嵌五  +550 叠加分进攻点
    if (pn[k-14]==0)  jqn[k-14]= jqn[k-14]+310 ;   
     if (pn[k-14]==0&&pn[k-28]==0)  jqn[k-14]= jqn[k-14]+410 ;   
     if (pn[k-14]==0&&pn[k-28]==0)  jqn[k-28]= jqn[k-28]+550 ;  
     if (pn[k+42]==0) jqn[k+42]= jqn[k+42]+310 ;   
     if (pn[k+42]==0&&pn[k+56]==0) jqn[k+42]= jqn[k+42]+410 ; 
     if (pn[k+42]==0&&pn[k+56]==0)  jqn[k+56]= jqn[k+56]+550 ;   
         }  }

   if (i>1&&i<13&&j>1&&j<13){
 if (pn[k]==2&&pn[k+16]==2&&pn[k+32]==2){//右对角
     //三连成嵌五  +550 叠加分进攻点
     if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+310 ;   
     if (pn[k-16]==0&&pn[k-32]==0) jqn[k-16]= jqn[k-16]+410 ; 
     if (pn[k-16]==0&&pn[k-32]==0)  jqn[k-32]= jqn[k-32]+550 ;   
     if (pn[k+48]==0) jqn[k+48]= jqn[k+48]+310 ;   
     if (pn[k+48]==0&&pn[k+64]==0) jqn[k+48]= jqn[k+48]+410 ; 
     if (pn[k+48]==0&&pn[k+64]==0) jqn[k+64]= jqn[k+64]+550 ;  }  }

//三连,活三变活四,必杀  0022200  与上叠加  
    if(pn[k2]==0&&pn[k1]==0&&pn[k]==2&&pn[k+1]==2&&pn[k+2]==2&&pn[k+3]==0&&pn[k+4]==0){  //左右
     jqn[k-1]= jqn[k-1]+1350 ;  
     jqn[k+3]= jqn[k+3]+1350 ;   }

   if(pn[k-30]==0&&pn[k-15]==0&&pn[k]==2&&pn[k+15]==2&&pn[k+30]==2&&pn[k+45]==0&&pn[k+60]==0){  //上下
     jqn[k-15]= jqn[k-15]+1350 ;  
     jqn[k+45]= jqn[k+45]+1350 ;   }
  
    if(pn[k-28]==0&&pn[k-14]==0&&pn[k]==2&&pn[k+14]==2&&pn[k+28]==2&&pn[k+42]==0&&pn[k+56]==0){//左对角
      jqn[k-14]= jqn[k-14]+1350 ;  
      jqn[k+42]= jqn[k+42]+1350 ;   }

 if(pn[k-32]==0&&pn[k-16]==0&&pn[k]==2&&pn[k+16]==2&&pn[k+32]==2&&pn[k+48]==0&&pn[k+64]==0){//右对角
      jqn[k-16]= jqn[k-16]+1350 ;  
      jqn[k+48]= jqn[k+48]+1350 ;   }

//*********
//白子算杀,做杀,找活三嵌四交点 +250
//白棋进攻态势,与二连三连计分叠加抢先手

//嵌四类 做冲四 2022  2202   布杀点 +350
// 120220  122020 020221 022021
   if (j>1&&j<13){
  if (pn[k]==2&&pn[k+1]==0&&pn[k+2]==2&&pn[k+3]==2){  //左右
      if (pn[k-1]==0||pn[k+4]==0){ jqn[k+1]= jqn[k+1]+350 ;   }  }
   if (pn[k]==2&&pn[k+1]==2&&pn[k+2]==0&&pn[k+3]==2){  //左右
    if (pn[k-1]==0||pn[k+4]==0){ jqn[k+2]= jqn[k+2]+350 ;   }   }
           } //j<12

   if (i>1&&i<13){
 if (pn[k]==2&&pn[k+15]==0&&pn[k+30]==2&&pn[k+45]==2){  //上下
     if (pn[k-15]==0||pn[k+60]==0){  jqn[k+15]= jqn[k+15]+350 ;   }   }
   if (pn[k]==2&&pn[k+15]==2&&pn[k+30]==0&&pn[k+45]==2){  //上下
     if (pn[k-15]==0||pn[k+60]==0){  jqn[k+30]= jqn[k+30]+350 ;   }   }
           } 

      if(j>3&&i>1&&i<13){ //行2--12
 if (pn[k]==2&&pn[k+14]==0&&pn[k+28]==2&&pn[k+42]==2){  //斜左
     if (pn[k-14]==0||pn[k+56]==0){ jqn[k+14]= jqn[k+14]+350 ;   }  }
   if (pn[k]==2&&pn[k+14]==2&&pn[k+28]==0&&pn[k+42]==2){  //斜左
     if (pn[k-14]==0||pn[k+56]==0){jqn[k+28]= jqn[k+28]+350 ;   }  }
            } //j>4, i<12
         
        if (j>1&&j<13&&i<13){  //列2--12
  if (pn[k]==2&&pn[k+16]==0&&pn[k+32]==2&&pn[k+48]==2){  //右斜
         if (pn[k-16]==0||pn[k+64]==0){ jqn[k+16]= jqn[k+16]+350 ;   }  }
   if (pn[k]==2&&pn[k+16]==2&&pn[k+32]==0&&pn[k+48]==2){  //右斜
        if (pn[k-16]==0||pn[k+64]==0){  jqn[k+32]= jqn[k+32]+350 ;   }  }
            } //i<12&&j<12

//嵌四 020220  022020  必杀点+350  j<12  防越界
  if (j>1&&j<12){
   if(pn[k-1]==0&&pn[k]==2&&pn[k+1]==0&&pn[k+2]==2&&pn[k+3]==2&&pn[k+4]==0){  //左右
        jqn[k+1]= jqn[k+1]+1350 ;   }
   if(pn[k-1]==0&&pn[k]==2&&pn[k+1]==2&&pn[k+2]==0&&pn[k+3]==2&&pn[k+4]==0){  //左右
        jqn[k+2]= jqn[k+2]+1350 ;   }    }

    if (i>1&&i<12){
  if(pn[k-15]==0&&pn[k]==2&&pn[k+15]==0&&pn[k+30]==2&&pn[k+45]==2&&pn[k+60]==0){  //上下
        jqn[k+15]= jqn[k+15]+1350 ;   }
   if(pn[k-15]==0&&pn[k]==2&&pn[k+15]==2&&pn[k+30]==0&&pn[k+45]==2&&pn[k+60]==0){  //上下
        jqn[k+30]= jqn[k+30]+1350 ;   }    }

  if (j>3&&j<15&&i>1&&i<12){
  if(pn[k-14]==0&&pn[k]==2&&pn[k+14]==0&&pn[k+28]==2&&pn[k+42]==2&&pn[k+56]==0){  //斜左
        jqn[k+14]= jqn[k+14]+1350 ;   }
   if(pn[k-14]==0&&pn[k]==2&&pn[k+14]==2&&pn[k+28]==0&&pn[k+42]==2&&pn[k+56]==0){  //斜左
        jqn[k+28]= jqn[k+28]+1350 ;   }    }

        if (j>1&&j<12&&i>1&&i<12){
 if(pn[k-16]==0&&pn[k]==2&&pn[k+16]==0&&pn[k+32]==2&&pn[k+48]==2&&pn[k+64]==0){  //右斜
        jqn[k+16]= jqn[k+16]+1350 ;   }
   if(pn[k-16]==0&&pn[k]==2&&pn[k+16]==2&&pn[k+32]==0&&pn[k+48]==2&&pn[k+64]==0){  //右斜
        jqn[k+32]= jqn[k+32]+1350 ;   }    }

//活四冲四成五连 022220  122220  022221   
//此是必杀点  +1990  j<12  防越界

//必杀点黑子 +1200, 白子 +1990 先胜
    if (j>1&&j<12){
 if (pn[k]==2&&pn[k+1]==2&&pn[k+2]==2&&pn[k 
+3]==2){  //左右
    if (pn[k-1]==0)  jqn[k-1]= jqn[k-1]+1990 ;  
    if (pn[k+4]==0)  jqn[k+4]= jqn[k+4]+1990 ;   }  }

    if (i>1&&i<12){
  if (pn[k]==2&&pn[k+15]==2&&pn[k+30]==2&&pn[k+45]==2){  //上下
    if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+1990 ;  
    if (pn[k+60]==0) jqn[k+60]= jqn[k+60]+1990 ; }  }

     if (j>3&&i>1&&i<12){
    if(pn[k]==2&&pn[k+14]==2&&pn[k+28]==2&&pn[k +42]==2){//左对角
      if (pn[k-14]==0) jqn[k-14]= jqn[k-14]+1990 ;  
      if (pn[k+56]==0)  jqn[k+56]= jqn[k+56]+1990 ;   }  }

     if (j>1&&j<12&&i>1&&i<12){
if (pn[k]==2&&pn[k+16]==2&&pn[k+32]==2&&pn[k+48]==2){//右对角  
    if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+1990 ;  
    if (pn[k+64]==0)  jqn[k+64]= jqn[k+64]+1990 ;   } }   
      
//嵌五,此是必杀点 20222  22022  22202 
      if (j<12){      // j<12  防越界
      if ( pn[k]==2&&pn[k+1]==0&&pn[k+2]==2&&pn[k+3]==2&&pn[k+4]==2){  //左右 20222
      jqn[k+1]= jqn[k+1]+1990 ;    }
      if ( pn[k]==2&&pn[k+1]==2&&pn[k+2]==0&&pn[k+3]==2&&pn[k+4]==2){  //左右 22022
      jqn[k+2]= jqn[k+2]+1990 ;    }
      if ( pn[k]==2&&pn[k+1]==2&&pn[k+2]==2&&pn[k+3]==0&&pn[k+4]==2){  //左右 22202
      jqn[k+3]= jqn[k+3]+1990 ;    }     }  //j<12

      if (i<12){
    if ( pn[k]==2&&pn[k+15]==0&&pn[k+30]==2&&pn[k+45]==2&&pn[k+60]==2){  //上下 20222
     jqn[k+15]= jqn[k+15]+1990 ;    }
    if ( pn[k]==2&&pn[k+15]==2&&pn[k+30]==0&&pn[k+45]==2&&pn[k+60]==2){  //上下 22022
     jqn[k+30]= jqn[k+30]+1990 ;    }
    if ( pn[k]==2&&pn[k+15]==2&&pn[k+30]==2&&pn[k+45]==0&&pn[k+60]==2){  //上下 22202
     jqn[k+45]= jqn[k+45]+1990 ;    }    }  //i<12

        if (j>4&&i<12){
    if ( pn[k]==2&&pn[k+14]==0&&pn[k+28]==2&&pn[k+42]==2&&pn[k+56]==2){  //斜左 20222
     jqn[k+14]= jqn[k+14]+1990 ;    }
    if ( pn[k]==2&&pn[k+14]==2&&pn[k+28]==0&&pn[k+42]==2&&pn[k+56]==2){  //斜左 22022
     jqn[k+28]= jqn[k+28]+1990 ;    }
    if ( pn[k]==2&&pn[k+14]==2&&pn[k+28]==2&&pn[k+42]==0&&pn[k+56]==2){  //斜左 22202
     jqn[k+42]= jqn[k+42]+1990 ;    }    }

        if (j<12&&i<12){
   if ( pn[k]==2&&pn[k+16]==0&&pn[k+32]==2&&pn[k+48]==2&&pn[k+64]==2){  //右斜 20222
     jqn[k+16]= jqn[k+16]+1990 ;    }
    if ( pn[k]==2&&pn[k+16]==2&&pn[k+32]==0&&pn[k+48]==2&&pn[k+64]==2){  //右斜 22022
     jqn[k+32]= jqn[k+32]+1990 ;    }
    if ( pn[k]==2&&pn[k+16]==2&&pn[k+32]==2&&pn[k+48]==0&&pn[k+64]==2){  //右斜 22202
     jqn[k+48]= jqn[k+48]+1990 ;    }    }

//****************************
//以下是黑棋估权计分
//黑棋进攻点亦即白棋防守点,白下子亦取高分位
  //独子 左右上下 二对角 八方
     if (pn[k]==1){
        if (pn[k-1]==0) jqn[k-1]= jqn[k-1]+20 ;
        if (pn[k+1]==0) jqn[k+1]= jqn[k+1]+20 ;
        if (pn[k-15]==0) jqn[k-15]= jqn[k-15]+30 ; //直指
        if (pn[k+15]==0) jqn[k+15]= jqn[k+15]+20 ;
        if (pn[k+14]==0) jqn[k+14]= jqn[k+14]+20 ;
        if (pn[k+16]==0) jqn[k+16]= jqn[k+16]+20 ;
        if (pn[k-14]==0) jqn[k-14]= jqn[k-14]+30 ; //斜指
        if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+20 ;
             }//pn

 //二连  001100  为成活三冲四进攻点
    if (j>1&&j<13){
    if (pn[k]==1&&pn[k+1]==1){  //左右
       if (pn[k-1]==0) jqn[k-1]= jqn[k-1]+100 ; 
       if (pn[k-1]==0&&pn[k-2]==0) { jqn[k-2]= jqn[k-2]+200 ;   jqn[k-1]= jqn[k-1]+300 ;  }
       if (pn[k+2]==0) jqn[k+2]= jqn[k+2]+100 ; 
       if (pn[k+2]==0&&pn[k+3]==0) { jqn[k+3]= jqn[k+3]+200 ;   jqn[k+2]= jqn[k+2]+300 ;  }
             } }

    if (i>1&&i<13){
    if (pn[k]==1&&pn[k+15]==1){  //上下
       if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+100 ;
       if (pn[k-15]==0&&pn[k-30]==0) { jqn[k-30]= jqn[k-30]+200 ;  jqn[k-15]= jqn[k-15]+300 ;  }
       if (pn[k+30]==0) jqn[k+30]= jqn[k+30]+100 ; 
       if (pn[k+30]==0&&pn[k+45]==0) { jqn[k+45]= jqn[k+45]+200 ;  jqn[k+30]= jqn[k+30]+300 ;  }
          } }

   if (i>1&&i<13&&j>3&&j<15){
   if (pn[k]==1&&pn[k+14]==1){  //左对角
       if (pn[k-14]==0) jqn[k-14]= jqn[k-14]+100 ;
       if (pn[k-14]==0&&pn[k-28]==0) { jqn[k-28]= jqn[k-28]+200 ;  jqn[k-14]= jqn[k-14]+300 ;  }
       if (pn[k+28]==0) jqn[k+28]= jqn[k+28]+100 ; 
       if (pn[k+28]==0&&pn[k+42]==0) { jqn[k+42]= jqn[k+42]+200 ;  jqn[k+28]= jqn[k+28]+300 ;  }
         } }

  if (i>1&&i<13&&j>1&&j<13){
  if (pn[k]==1&&pn[k+16]==1){   //右对角
       if (pn[k-16]==0) jqn[k-16]= jqn[k-16]+100 ;
       if (pn[k-16]==0&&pn[k-32]==0) { jqn[k-32]= jqn[k-32]+200 ;  jqn[k-16]= jqn[k-16]+300 ;  }
       if (pn[k+32]==0) jqn[k+32]= jqn[k+32]+100 ; 
       if (pn[k+32]==0&&pn[k+48]==0) { jqn[k+48]= jqn[k+48]+200 ;  jqn[k+32]= jqn[k+32]+300 ;  }
          } }

//连二  010010
    if (j>1&&j<13){
if (pn[k]==1&&pn[k+3]==1){  //左右
       if (pn[k-1]==0&&pn[k+1]==0)  jqn[k+1]= jqn[k+1]+200 ;
       if (pn[k+4]==0&&pn[k+2]==0)  jqn[k+2]= jqn[k+2]+200 ;       }  }

    if (i>1&&i<13){
if (pn[k]==1&&pn[k+45]==1){  //上下
       if (pn[k-15]==0&&pn[k+15]==0)  jqn[k+15]= jqn[k+15]+200 ;
       if (pn[k+60]==0&&pn[k+30]==0)  jqn[k+30]= jqn[k+30]+200 ;     }  }

   if (i>1&&i<13&&j>3&&j<15){
  if (pn[k]==1&&pn[k+42]==1){  //左对角
       if (pn[k-14]==0&&pn[k+14]==0)  jqn[k+14]= jqn[k+14]+200 ;
       if (pn[k+56]==0&&pn[k+28]==0)  jqn[k+28]= jqn[k+28]+200 ;     }  }

  if (i>1&&i<13&&j>1&&j<13){
 if (pn[k]==1&&pn[k+48]==1){   //右对角
       if (pn[k-16]==0&&pn[k+16]==0)  jqn[k+16]= jqn[k+16]+200 ;
       if (pn[k+64]==0&&pn[k+32]==0) jqn[k+32]= jqn[k+32]+200 ;    }  }

//嵌三   01010   可成双活三
   if (j>1&&j<13){
if (pn[k]==1&&pn[k+1]==0&&pn[k+2]==1){  //左右
          jqn[k+1]= jqn[k+1]+500 ;   
      if (pn[k-1]==0)  jqn[k-1]= jqn[k-1]+300 ; 
      if (pn[k+3]==0)  jqn[k+3]= jqn[k+3]+300 ; } }

  if (i>1&&i<13){
 if (pn[k]==1&&pn[k+15]==0&&pn[k+30]==1){  //上下
          jqn[k+15]= jqn[k+15]+500 ;   
      if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+300 ; 
      if (pn[k+30]==0)  jqn[k+30]= jqn[k+30]+300 ; } }

   if (i>1&&i<13&&j>3&&j<15){
if (pn[k]==1&&pn[k+14]==0&&pn[k+28]==1){//左对角
          jqn[k+14]= jqn[k+14]+500 ;   
      if (pn[k-14]==0)  jqn[k-14]= jqn[k-14]+300 ; 
      if (pn[k+28]==0)  jqn[k+28]= jqn[k+28]+300 ; } }

  if (i>1&&i<13&&j>1&&j<13){
 if (pn[k]==1&&pn[k+16]==0&&pn[k+32]==1){//右对角
          jqn[k+16]= jqn[k+16]+500 ;   
      if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+300 ; 
      if (pn[k+32]==0)  jqn[k+32]= jqn[k+32]+300 ; } }

//三连,眠三21110  01112 抢冲四 
   if (j>1&&j<13){
if (pn[k]==1&&pn[k+1]==1&&pn[k+2]==1){  //左右
    //三连成嵌五  +550 叠加分进攻点
     if (pn[k-1]==0)  jqn[k-1]= jqn[k-1]+300 ;   
     if (pn[k-1]==0&&pn[k-2]==0) jqn[k-1]= jqn[k-1]+400 ;   //必杀点加权分
     if (pn[k-1]==0&&pn[k-2]==0)  jqn[k-2]= jqn[k-2]+550 ;   
     if (pn[k+3]==0)  jqn[k+3]= jqn[k+3]+300 ;   
     if (pn[k+3]==0&&pn[k+4]==0) jqn[k+3]= jqn[k+3]+400 ; 
     if (pn[k+3]==0&&pn[k+4]==0)   jqn[k+4]= jqn[k+4]+550 ;    }  }

   if (i>1&&i<13){
if (pn[k]==1&&pn[k+15]==1&&pn[k+30]==1){  //上下
    //三连成嵌五  +550 叠加分进攻点
     if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+300 ;   
     if (pn[k-15]==0&&pn[k-30]==0) jqn[k-15]= jqn[k-15]+400 ; 
     if (pn[k-15]==0&&pn[k-30]==0)  jqn[k-30]= jqn[k-30]+550 ;   
   //  if (pn[k-15]==2&&pn[k+45]==0) jqn[k+45]= jqn[k+45]-200 ;   //眠三可不堵,???
     if (pn[k+45]==0) jqn[k+45]= jqn[k+45]+300 ;   
     if (pn[k+45]==0&&pn[k+60]==0) jqn[k+45]= jqn[k+45]+400 ; 
     if (pn[k+45]==0&&pn[k+60]==0) jqn[k+60]= jqn[k+60]+550 ;
             }  }

   if (i>1&&i<13&&j>3&&j<15){
if (pn[k]==1&&pn[k+14]==1&&pn[k+28]==1){//斜左
    //三连成嵌五  +550 叠加分进攻点
     if (pn[k-14]==0)  jqn[k-14]= jqn[k-14]+300 ;   
     if (pn[k-14]==0&&pn[k-28]==0) jqn[k-14]= jqn[k-14]+400 ; 
     if (pn[k-14]==0&&pn[k-28]==0)  jqn[k-28]= jqn[k-28]+550 ;   
     if (pn[k+42]==0) jqn[k+42]= jqn[k+42]+300 ;   
     if (pn[k+42]==0&&pn[k+56]==0) jqn[k+42]= jqn[k+42]+400 ; 
     if (pn[k+42]==0&&pn[k+56]==0) jqn[k+56]= jqn[k+56]+550 ;  }  }

  if (i>1&&i<13&&j>1&&j<13){
 if (pn[k]==1&&pn[k+16]==1&&pn[k+32]==1){//右斜
    //三连成嵌五  +550 叠加分进攻点
     if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+300 ;   
     if (pn[k-16]==0&&pn[k-32]==0) jqn[k-16]= jqn[k-16]+400 ; 
     if (pn[k-16]==0&&pn[k-32]==0)  jqn[k-32]= jqn[k-32]+550 ;   
     if (pn[k+48]==0) jqn[k+48]= jqn[k+48]+300 ;   
     if (pn[k+48]==0&&pn[k+64]==0) jqn[k+48]= jqn[k+48]+400 ; 
     if (pn[k+48]==0&&pn[k+64]==0) jqn[k+64]= jqn[k+64]+550 ;  }  }

//三连,活三变活四  01110  白方逢三必堵
    if(pn[k-2]==0&&pn[k-1]==0&&pn[k]==1&&pn[k+1]==1&&pn[k+2]==1&&pn[k+3]==0&&pn[k+4]==0){  //左右
     jqn[k-1]= jqn[k-1]+800 ;  
     jqn[k+3]= jqn[k+3]+800 ;   }

   if(pn[k-30]==0&&pn[k-15]==0&&pn[k]==1&&pn[k+15]==1&&pn[k+30]==1&&pn[k+45]==0&&pn[k+60]==0){  //上下
     jqn[k-15]= jqn[k-15]+800 ;  
     jqn[k+45]= jqn[k+45]+800 ;   }
  
    if(pn[k-28]==0&&pn[k-14]==0&&pn[k]==1&&pn[k+14]==1&&pn[k+28]==1&&pn[k+42]==0&&pn[k+56]==0){//左对角
      jqn[k-14]= jqn[k-14]+800 ;  
      jqn[k+42]= jqn[k+42]+800 ;   }

 if(pn[k-32]==0&&pn[k-16]==0&&pn[k]==1&&pn[k+16]==1&&pn[k+32]==1&&pn[k+48]==0&&pn[k+64]==0){//右对角
      jqn[k-16]= jqn[k-16]+800 ;  
      jqn[k+48]= jqn[k+48]+800 ;   }

//黑方的必杀点就是白方的防守要点
//嵌四 010110   011010   必杀点 +350
   if (j>1&&j<12){
 if(pn[k-1]==0&&pn[k]==1&&pn[k+1]==0&&pn[k+2]==1&&pn[k+3]==1&&pn[k+4]==0){  //左右
        jqn[k+1]= jqn[k+1]+350 ;   }
   if(pn[k-1]==0&&pn[k]==1&&pn[k+1]==1&&pn[k+2]==0&&pn[k+3]==1&&pn[k+4]==0){  //左右
        jqn[k+2]= jqn[k+2]+350 ;   }  }

    if (i>1&&i<12){
if(pn[k-15]==0&&pn[k]==1&&pn[k+15]==0&&pn[k+30]==1&&pn[k+45]==1&&pn[k+60]==0){  //上下
        jqn[k+15]= jqn[k+15]+350 ;   }
   if(pn[k-15]==0&&pn[k]==1&&pn[k+15]==1&&pn[k+30]==0&&pn[k+45]==1&&pn[k+60]==0){  //上下
        jqn[k+30]= jqn[k+30]+350 ;   }  }

   if (i>1&&i<12&&j>3&&j<15){
 if(pn[k-14]==0&&pn[k]==1&&pn[k+14]==0&&pn[k+28]==1&&pn[k+42]==1&&pn[k+56]==0){  //斜左
        jqn[k+14]= jqn[k+14]+350 ;   }
   if(pn[k-14]==0&&pn[k]==1&&pn[k+14]==1&&pn[k+28]==0&&pn[k+42]==1&&pn[k+56]==0){  //斜左
        jqn[k+28]= jqn[k+28]+350 ;   }  }

    if (i>1&&i<12&&j>1&&j<12){
if(pn[k-16]==0&&pn[k]==1&&pn[k+16]==0&&pn[k+32]==1&&pn[k+48]==1&&pn[k+64]==0){  //右斜
        jqn[k+16]= jqn[k+16]+350 ;   }
   if(pn[k-16]==0&&pn[k]==1&&pn[k+16]==1&&pn[k+32]==0&&pn[k+48]==1&&pn[k+64]==0){  //右斜
        jqn[k+32]= jqn[k+32]+350 ;   }  }

//活四冲四 此是必杀点 211110  011112   +1200
//黑有此白必堵,此是必杀点 如白无连五则必应 
    if (j>1&&j<12){      // j<12  防越界
    if ( pn[k]==1&&pn[k+1]==1&&pn[k+2]==1&&pn[k+3]==1){  //左右
    if (pn[k-1]==0)  jqn[k-1]= jqn[k-1]+1200 ;  
    if (pn[k+4]==0)  jqn[k+4]= jqn[k+4]+1200 ;   }  }

   if (i>1&&i<12){
   if (pn[k]==1&&pn[k+15]==1&&pn[k+30]==1&&pn[k+45]==1){  //上下
    if (pn[k-15]==0)  jqn[k-15]= jqn[k-15]+1200 ;  
    if (pn[k+60]==0)  jqn[k+60]= jqn[k+60]+1200 ;   }  }

  if (i>1&&i<12&&j>3&&j<15){
  if(pn[k]==1&&pn[k+14]==1&&pn[k+28]==1&&pn[k+42]==1){//左对角
    if (pn[k-14]==0)  jqn[k-14]= jqn[k-14]+1200 ;  
    if (pn[k+56]==0)  jqn[k+56]= jqn[k+56]+1200 ;   }  }

   if (i>1&&i<12&&j>1&&j<12){
  if (pn[k]==1&&pn[k+16]==1&&pn[k+32]==1&&pn[k+48]==1){//右对角
     if (pn[k-16]==0)  jqn[k-16]= jqn[k-16]+1200 ;  
    if (pn[k+64]==0)  jqn[k+64]= jqn[k+64]+1200 ;   }  }
 
//嵌五 10111  11011  11101   +1200
//此是必杀点 如白无连五则必应 
      if ( pn[k]==1&&pn[k+1]==0&&pn[k+2]==1&&pn[k+3]==1&&pn[k+4]==1){  //左右 10111
      jqn[k+1]= jqn[k+1]+1200 ;    }
      if ( pn[k]==1&&pn[k+1]==1&&pn[k+2]==0&&pn[k+3]==1&&pn[k+4]==1){  //左右 11011
      jqn[k+2]= jqn[k+2]+1200 ;    }
      if ( pn[k]==1&&pn[k+1]==1&&pn[k+2]==1&&pn[k+3]==0&&pn[k+4]==1){  //左右 11101
      jqn[k+3]= jqn[k+3]+1200 ;    }

    if ( pn[k]==1&&pn[k+15]==0&&pn[k+30]==1&&pn[k+45]==1&&pn[k+60]==1){  //上下 10111
     jqn[k+15]= jqn[k+15]+1200 ;    }
    if ( pn[k]==1&&pn[k+15]==1&&pn[k+30]==0&&pn[k+45]==1&&pn[k+60]==1){  //上下 11011
     jqn[k+30]= jqn[k+30]+1200 ;    }
    if ( pn[k]==1&&pn[k+15]==1&&pn[k+30]==1&&pn[k+45]==0&&pn[k+60]==1){  //上下 11101
     jqn[k+45]= jqn[k+45]+1200 ;    }

    if ( pn[k]==1&&pn[k+14]==0&&pn[k+28]==1&&pn[k+42]==1&&pn[k+56]==1){  //斜左 10111
     jqn[k+14]= jqn[k+14]+1200 ;    }
    if ( pn[k]==1&&pn[k+14]==1&&pn[k+28]==0&&pn[k+42]==1&&pn[k+56]==1){  //斜左 11011
     jqn[k+28]= jqn[k+28]+1200 ;    }
    if ( pn[k]==1&&pn[k+14]==1&&pn[k+28]==1&&pn[k+42]==0&&pn[k+56]==1){  //斜左 11101
     jqn[k+42]= jqn[k+42]+1200 ;    }

    if ( pn[k]==1&&pn[k+16]==0&&pn[k+32]==1&&pn[k+48]==1&&pn[k+64]==1){  //右斜 10111
     jqn[k+16]= jqn[k+16]+1200 ;    }
    if ( pn[k]==1&&pn[k+16]==1&&pn[k+32]==0&&pn[k+48]==1&&pn[k+64]==1){  //右斜 11011
     jqn[k+32]= jqn[k+32]+1200 ;    }
    if ( pn[k]==1&&pn[k+16]==1&&pn[k+32]==1&&pn[k+48]==0&&pn[k+64]==1){  //右斜 11101
     jqn[k+48]= jqn[k+48]+1200 ;    }

  }    }    //test i , j   pn(225) 棋盘点位

//******************************
//测试:显示加权计分情况,最高分白下子
   if (isDo==0) return ;
     cs.SetTextSize (14);
     cs.SetTextStyle (0);
     cs.SetColor (255,0,0,240) ;
       for (i=1;i<=225;i++){    //scan
           if (jqn[i] !=0) {
             //print i,"  qn= ",jqn[i] ;    //测试
             s=intToString ( jqn[i]) ;
     dx=(i-(i/15*15))*40;
     dy=(i/15)*40+40;
       if (dx==0){ dx=15*40;    dy=dy-40;   }
            cs.DrawText (s,dx,dy) ;    //标记分值
          }     }
 
//计算最高分
      jqf=0 ;
 for (i=1;i<=225;i++){  
       k= jqn[i] ;
       if ( k>jqf) { jqf=k ;  jqfn=i ;   }
             } //计算最高分 
       sn=jqfn ;     //计权最高分点位转坐标
 //   print " sn= ",jqfn ," jqf= ",jqf ;  //test
      dx=(sn-(sn/15*15))*40;
      dy=(sn/15)*40+40;
       if (dx==0) {dx=15*40;   dy=dy-40;   }
      cs.SetColor (255,250,250,0);  
      cs.DrawCircle (dx,dy,5);  //标记下子点
         cs.Update () ;   
         //sleep (500) ;   //test 查看
         n=sn ;      //下子点号sn转换为n,  draw board
         px=dx ;  py=dy ;    //board ()标记下子点
 //**** AI 走子 ********************** 
}//testAIq ()

swapabc (){  //传入col , 输出 ss = "ABC"
   //pn(225) 转显示 H8 ...G9...
 string abc$ ;
    abc$="sABCDEFGHIJKLMNO" ;
    ss=subString (abc$,col,1) ;
}//swapabc ()

black_do (){    //黑棋下子
         pn[n]=1;    
         s6="⚪棋选子";   
        row=15-(n/15) ;
        col=(n-(n/15*15)) ;
        if (col==0){ col=15 ;    row=row+1 ;   }
        swapabc () ;   //return ss
        cordp=" B   "+intToString (n);    //走子记录
        cordp1=" B  "+ss+intToString (row) ;
     if (cordp != ss2) {    //不重复记录
           dn=dn+1;       //print dn;   
           print dn," ",cordp,"    " , ss,row ;  //打印记录
             ss2=cordp; 
           dwn[dn]=n ;    //print play number
           fudat[dn]=n;    fusum=dn;  //复盘数据                           
       board ();               }
       testAIq ();     //AI 算法测试 ****
  //scan restricted move and draw mark
   if (jsset==0)  restrict_move () ;  //禁手设置标记
   if (mode==1) {     //人机模式下子
           white_do () ;      }    // AI Do  白下子
}//black_do ()

white_do (){    //白棋下子
     //if (isDo==0) return ;
        pn[n]=2;
          s6="⚫棋选子";        
       row=15-(n/15) ;
       col=(n-(n/15*15)) ;
       if (col==0){ col=15 ;    row=row+1 ;   }
       swapabc () ;   //return ss
       cordp=" W  "+intToString (n);     //走子记录
       cordp1="W  "+ss+intToString (row) ;
     if (cordp != ss2) { 
          dn=dn+1;    
          print dn," ",cordp,"    " , ss,row ;  //打印记录
            ss2=cordp;  
          dwn[dn]=n ;    //print play number
          fudat[dn]=n;    fusum=dn;  //复盘数据
       board () ;           }
       testAIq ();     //AI 算法测试 ****
   //scan restricted move and draw mark
   if (jsset==0)  restrict_move () ;  //禁手设置标记
 }//white_do ()

 board (){  //绘制棋板,更新棋板
     if (isDo==0) return ;   //结束标志   
  fname="/storage/emulated/0/go02.jpg";
     cs.DrawBitmap(fname,0,0);  //加底图
   //** draw board grids 棋盘方格
    cs.SetFillMode (1);//0不填色,1填色
    cs.SetColor (155,0,0,0);  //底板底线
    cs.DrawRect(634,13,638,633);
    cs.DrawRect(13,632,638,636);
    cs.SetColor (85,220,150,50);  //pad棋板
    cs.DrawRect (8,8,636,632);
    cs.SetFillMode (0);//0不填色,1填色
     for (i=1;i<15;i++){       //draw grids棋盘格
        for (j=1;j<15;j++){    
    cs.SetColor (255,150,150,150);  //grid 格线
        cs.DrawRect(i*40-1,j*40-1,i*40+39,j*40+39);  
    cs.SetColor (255,255,255,255);  //grid 
        cs.DrawRect(i*40,j*40,i*40+40,j*40+40);  
               }        }    //格线
    cs.SetColor (255,0,0,0);  // rectangle line
       cs.DrawRect (8,8,634,632);
       cs.DrawRect (21,21,620,620);
       cs.DrawRect (20,20,620,620);

    //draw flag points
    cs.SetFillMode (1);//0不填色,1填色
     cs.SetColor (255,140,140,140);  
       cs.DrawCircle(160,160,5);     //星
       cs.DrawCircle(480,160,5);
       cs.DrawCircle(160,480,5);
       cs.DrawCircle(480,480,5);
       cs.DrawCircle(320,320,5);    //中元
  cs.SetColor (255,255,255,255);  
       cs.DrawCircle(161,161,5);     //星
       cs.DrawCircle(481,161,5);
       cs.DrawCircle(161,481,5);
       cs.DrawCircle(481,481,5);
       cs.DrawCircle(321,321,5);    //中元
   // 绘出棋盘坐标编码 1-15 , A-O
   cs.SetColor (255,60,40,20);  
     cs.SetTextStyle (1);
     cs.SetTextSize (14);
string abc$ ;
    abc$="sABCDEFGHIJKLMNO" ;
       a=0 ;   b=0 ;   //set print tab
   for (i=1;i<=15;i++){    
           ss1=intToString (i) ;
        if (i>9) a=4 ;       //tab for print number
           cs.DrawText (ss1,25-a,645-i*40) ;  
           ss=subString (abc$,i,1) ;
        if (i==9) b=2 ;       //"I"  + tab  调整
        if (i>10) b=-1 ;       //"K...O"  + tab
          cs.DrawText (ss,i*40-4+b,615) ;    }
 //draw button 绘制按钮
  cs.SetColor (125,50,150,150);  
    cs.DrawRect (40,900,181,961);
    cs.DrawRect (210,900,351,961);
    cs.DrawRect (380,900,521,961);
      for (i=1;i<60;i++){    //按钮渐变色
    cs.SetColor (125,250-i*4,250-i*3,250-i*3);  
      cs.DrawLine (41,900+i,180,900+i);  
      cs.DrawLine (211,900+i,350,900+i);  
      cs.DrawLine (381,900+i,520,900+i);  
            }    
      cs.SetColor(255,255,250,0);
      cs.SetTextStyle (1);
      cs.SetTextSize (32);
      cs.DrawText ("复  盘",72,940);
      cs.DrawText ("悔  棋",242,940);
      cs.DrawText ("演  示",412,940);
   //print title
      cs.SetTextSize (80);
      cs.SetTextStyle (1);
   cs.SetColor (150,50,50,50);  
        cs.DrawText ("五子棋",50,793);
        cs.DrawText ("Gobang",50,873);
   cs.SetColor (155,240,160,110);  
        cs.DrawText ("五子棋",52,790);
        cs.DrawText ("Gobang",52,870);
    s="编制人:张纯叔 ( micelu@126.com ) " ;
        cs.SetTextSize (24);
        cs.DrawText (s, 40, 990);
   for (i=1;i<=225;i++){    
  //draw chess pieces 画出已下黑白子
     dx=(i-(i/15*15))*40;
     dy=(i/15)*40+40;
       if (dx==0){ dx=15*40;    dy=dy-40;   }
 if ( pn[i]==2){  //white
    cs.SetColor (255,140,80,40);  //piecesW
       cs.DrawCircle(dx+2,dy+2,17);
    cs.SetColor (255,220,220,220);  //pieceW
       cs.DrawCircle(dx,dy,17);
    cs.SetColor (255,255,255,255);  //pieceW
       cs.DrawCircle(dx-6,dy-6,2);   }
 if (pn[i]==1){  //black
    cs.SetColor (255,220,100,40);  //piecesB
       cs.DrawCircle(dx+1,dy+1,17);
    cs.SetColor (255,90,90,90);  //pieceB
       cs.DrawCircle(dx,dy,17);
    cs.SetColor (255,200,200,200);  //pieceB
       cs.DrawCircle(dx-6,dy-6,2);       }
               }     //draw chess pieces
     cs.SetColor (255,240,0,0);  //刚落子标记
       cs.DrawCircle(px,py,5);
    //提示选子
     cs.SetTextSize (42);
     cs.SetColor(95,255,0,0);
     cs.DrawRect (390,670,600,740);
     cs.SetColor(255,240,240,240);  
     cs.DrawText (s6,410,720);    
     cs.SetTextSize (36);     //print s7=模式
    if (mode==0) cs.SetColor(255,255,60,180);
    if (mode==1) cs.SetColor(255,100,200,0);
    cs.DrawText (s7,20,680);      //模式
         cs.SetTextSize (26);
     if(jsset==0){  //禁手设置 on ****
         cs.SetColor(255,250,80,120);
         cs.DrawText ("有禁手",600,720);  
         cs.SetColor (255,180,0,180) ;
         cs.DrawCircle (690,710,9) ;  }//draw mark
     if(jsset==1){
         cs.SetColor(255,250,80,120);
         cs.DrawText ("无禁手",600,720);  
         cs.SetColor (255,250,250,0) ;
         cs.DrawCircle (690,710,9) ;   }  //mark      
         cs.SetTextSize (30);    // show开局名$ s8
         cs.SetColor(255,220,0,200);
         cs.DrawText (s8, 382,890);  
     
  //draw pieces number 画出下子序号*****
     for (i=1;i<=dn;i++){    
       s=intToString(i) ;
            kn=dwn[i] ;    
     dx=(kn-(kn/15*15))*40;
     dy=(kn/15)*40+40;
       if (dx==0){ dx=15*40;    dy=dy-40;   }
         cs.SetTextSize (16);
         cs.SetColor (255,0,160,0);  
         cs.DrawText (s,dx-5,dy+5);
 //界面显示记录 
        n=fudat[i] ;
        row=15-(n/15) ;
        col=(n-(n/15*15)) ;
        if (col==0){ col=15 ;    row=row+1 ;   }
      swapabc () ;   //return ss
   if ((i-i/2*2)==0) {s="W " ; }else{s=" B " ;  }
     ss1=s+ss+intToString (row) ;
     cs.SetTextStyle (0);
     cs.SetTextSize (18);
     cs.SetColor(255,0,0,220);
     if(ss1==" B O16") ss1="悔棋" ;
     cs.DrawText (ss1,655,i*16);  //record _G8
                }     
     cs.Update ();
     detect ();   //检测胜负
}//board ()

detect (){    //检测胜负
//detect Black chess  判胜 ******
   for (i=1;i<16;i++){     // B 黑子
       for (j=1;j<12;j++){    
          k=(i-1)*15+j ;    //pn(B) number
       if (pn[k]==1){
      if ( pn[k+1]==1&&pn[k+2]==1&&pn[k+3]==1&&pn[k+4]==1){ 
      if (pn[k+5]==1) pn[k]=2 ;   //超五连,禁手白胜
           goto showwin ;  }   //右
              }   }   }
   for (i=1;i<12;i++){     // B 黑子
       for (j=1;j<16;j++){    
          k=(i-1)*15+j ;    //pn(B) number
       if (pn[k]==1){
    if ( pn[k+15]==1&&pn[k+30]==1&&pn[k+45]==1&&pn[k+60]==1){ 
       if (pn[k+75]==1) pn[k]=2 ; //超五连,禁手白胜      
            goto showwin ;  }  //下 
               }   }    }
  for (i=1;i<12;i++){     // B 黑子
       for (j=1;j<12;j++){    
          k=(i-1)*15+j ;    //pn(B) number
       if (pn[k]==1){
       if ( pn[k+16]==1&&pn[k+32]==1&&pn[k+48]==1&&pn[k+64]==1){  
       if (pn[k+80]==1) pn[k]=2 ; //超五连,禁手白胜
           goto showwin ;  }  //右斜  
               }    }    }
  for (i=1;i<12;i++){     // B 黑子
       for (j=5;j<16;j++){    
          k=(i-1)*15+j ;    //pn(B) number
       if (pn[k]==1){
       if ( pn[k+14]==1&&pn[k+28]==1&&pn[k+42]==1&&pn[k+56]==1){ 
       if (pn[k+70]==1) pn[k]=2 ; //超五连,禁手白胜      
           goto showwin ;  }  //斜左   
               }     }     }        
//********************************
//detect White chess 判胜 ******
    for (i=1;i<16;i++){    // W 白子
       for (j=1;j<12;j++){    
          k=(i-1)*15+j ;    //pn(W) number
        if (pn[k]==2){
      if ( pn[k+1]==2&&pn[k+2]==2&&pn[k+3]==2&&pn[k+4]==2){  goto showwin ;  }   //右
           }    }    }
   for (i=1;i<12;i++){     // W 白子
       for (j=1;j<16;j++){    
          k=(i-1)*15+j ;    //pn(W) number
       if (pn[k]==2){
      if ( pn[k+15]==2&&pn[k+30]==2&&pn[k+45]==2&&pn[k+60]==2){  goto showwin ;  }  //下    
             }    }    }
  for (i=1;i<12;i++){     // W 白子
       for (j=1;j<12;j++){    
          k=(i-1)*15+j ;    //pn(W) number
       if (pn[k]==2){
      if ( pn[k+16]==2&&pn[k+32]==2&&pn[k+48]==2&&pn[k+64]==2){  goto showwin ;  }  //右斜
             }    }    }
   for (i=1;i<12;i++){     // W 白子
       for (j=5;j<16;j++){    
          k=(i-1)*15+j ;    //pn(W) number
       if (pn[k]==2){
      if ( pn[k+14]==2&&pn[k+28]==2&&pn[k+42]==2&&pn[k+56]==2){  goto showwin ;  }  //斜左
             }      }     } 
//*****************************
  if (pn[n]==1&&js[n]>100){   //禁手,判白棋胜
       print "禁手 pn=", n ;
         cs.SetColor(255,255,0,0);
         cs.SetTextSize (16);
     cs.DrawText ("( 禁手 )",655,(dn+2)*16 );   
         cs.SetTextSize (40);
     cs.DrawText ("( 禁手 )",460,530 );   
         ss9="白棋胜  !"; 
         goto heqi;    }
return;
//********
 //** show win flag  判胜负
showwin:    
  if (dn>120) {      //判和棋
       ss9="(  和  棋  )";  goto heqi;    }
       cs.SetTextStyle (0);
        cs.SetTextSize (16);
        cs.SetColor(255,255,0,0);
    if (pn[k]==1) {
        ss9="黑棋胜  !";   print ss9; 
        cs.DrawText (ss9,655,(dn+2)*16);     }
     if (pn[k]==2) { 
        ss9="白棋胜  !";   print ss9; 
        cs.DrawText (ss9,655,(dn+2)*16);     }
     isDo=0;      //结束标志
  
heqi:      //和棋 drawngame 
     cs.SetTextSize (60);
     cs.SetTextStyle (1);
     cs.SetFillMode (1);//0不填色,1填色
     cs.SetColor(255,0,90,0);
        cs.DrawText (ss9,214,544);
      cs.SetColor(255,255,0,0);
         cs.DrawText (ss9,210,540);
    cs.SetFillMode (0);//0不填色,1填色
    cs.SetColor(255,250,250,0);
         cs.DrawText (ss9,210,540);
  print ss9 ;    //record
  cs.Update ();
     isDo=0;      //结束标志
}//detect ()
 
gamestart (){  //开始游戏
    setDisplay (1);  
        isDo=1;         //游戏操作控制
        cord=1 ;        //记录开关
    for (i=1;i<=225;i++){ pn[i]=0;  }   //init pn (n)下子位
    for (i=0;i<=120;i++){ dwn[i]=0;  }  //init dwn (n)复盘
    for (i=1;i<=225;i++){ js[i]=0 ;    }    //init  js (n)禁手
         s6="⚫棋选子";     //init
      px=320 ;  py=320 ;      //标记
        dn=0;  wn=0 ;    n=0 ;   //计数清零
        gn=gn+1;    //game round + 1
        clearOutput();     //清除记录
        s8=" " ;  //演示局名
        jsset=1 ;   //无禁手
        board ();      //绘出棋板
  }//gamestart ()

restrict_set (){   //加禁手设置
    jsset=0 ;    //设置黑棋禁手 set on
    board () ;
}//restrict_set()

restrict_move (){  //禁手设置
 //黑棋禁手,加权计算查找
   for (i=1;i<=225;i++) {  js[i]=0 ;    }  //init scan
 //三三禁手,01010 此情况中间为可成三三的交点
 //此点记100,若有两个三三,此点就计分200,
 //即禁手点位,黑棋若下子即可判负
  for (i=1;i<=15;i++){    //遍历scan 黑子
  for (j=1;j<=15;j++){    
           k=(i-1)*15+j ;    //pn(n) number
  //三三禁手形 0 0  1  010 0,  k前后 0位计权
 //两边为空中间可成活三,有子是假活三
     if (pn[k]==1){  // scan B (k)
      if (pn[k-1]==0&&pn[k+1]==0&&pn[k+2]==1&&pn[k+3]==0){
        js[k+1]= js[k+1]+100 ;
      if ( pn[k-2]==0)  js[k-1]= js[k-1]+100 ;  
      if (pn[k+4]==0)  js[k+3]= js[k+3]+100 ;   
      if ( pn[k-2]==1&&pn[k+4]==1) { //101(0)101四四
            js[k+1]= js[k+1]+200 ;   }     }//左右
   
     if (pn[k-15]==0&&pn[k+15]==0&&pn[k+30]==1&&pn[k+45]==0){  
         js[k+15]= js[k+15]+100 ;   
      if ( pn[k-30]==0) js[k-15]= js[k-15]+100 ;   
      if (pn[k+60]==0) js[k+45]= js[k+45]+100 ;   
      if ( pn[k-30]==1&&pn[k+60]==1) { //四四
             js[k+15]= js[k+15]+200 ;   }     }//上下

     if (pn[k-14]==0&&pn[k+14]==0&&pn[k+28]==1&&pn[k+42]==0){  
          js[k+14]= js[k+14]+200 ;  
     if ( pn[k-28]==0) js[k-14]= js[k-14]+100 ;   
      if (pn[k+56]==0) js[k+42]= js[k+42]+100 ;   
      if ( pn[k-28]==1&&pn[k+42]==1) {  //四四
            js[k+14]= js[k+14]+200 ;   }     }//斜左

     if (pn[k-16]==0&&pn[k+16]==0&&pn[k+32]==1&&pn[k+48]==0){  
          js[k+16]= js[k+16]+100 ;   
      if ( pn[k-32]==0) js[k-16]= js[k-16]+100 ;   
      if (pn[k+64]==0) js[k+48]= js[k+48]+100 ;   
      if ( pn[k-32]==1&&pn[k+64]==1) { //四四
            js[k+16]= js[k+16]+200 ;   }     }//右斜

            }  //00 1 0100

//禁手形 00  1  100 ,  k前后 0位计权
   if (pn[k]==1){  //scan B (k)
   if (pn[k-1]==0&&pn[k+1]==1&&pn[k+2]==0){  
        if (pn[k-2]==0) js[k-2]= js[k-2]+100 ;   
        if (pn[k-2]==0) js[k-1]= js[k-1]+100 ;   //**
        js[k+2]= js[k+2]+100 ;   
    if (pn[k+3]==0) js[k+3]= js[k+3]+100 ;   }  //左右

    if (pn[k-15]==0&&pn[k+15]==1&&pn[k+30]==0){  
        if (pn[k-30]==0) js[k-30]= js[k-30]+100 ;   
        if (pn[k-30]==0) js[k-15]= js[k-15]+100 ;   
        js[k+30]= js[k+30]+100 ;   
    if (pn[k+45]==0) js[k+45]= js[k+45]+100 ;   }  //上下
     
    if (pn[k-14]==0&&pn[k+14]==1&&pn[k+28]==0){  
       if (pn[k-28]==0)  js[k-28]= js[k-28]+100 ;   
       if (pn[k-28]==0) js[k-14]= js[k-14]+100 ;   
        if (j<12) js[k+28]= js[k+28]+100 ;   
   if (pn[k+42]==0) js[k+42]= js[k+42]+100 ;   }  //斜左

   if (pn[k-16]==0&&pn[k+16]==1&&pn[k+32]==0){  
        if (pn[k-32]==0) js[k-32]= js[k-32]+100 ;   
        if (pn[k-32]==0) js[k-16]= js[k-16]+100 ;   
        js[k+32]= js[k+32]+100 ;   
   if (pn[k+48]==0) js[k+48]= js[k+48]+100 ;   }  //右斜
              }   //00 1 100

 //禁手形 0 1  0010 ,  中间 0位计权
   if (pn[k]==1){  //scan B (k)
   if (pn[k-1]==0&&pn[k+1]==0&&pn[k+2]==0&&pn[k+3]==1&&pn[k+4]==0){  
        js[k+1]= js[k+1]+100 ;   
        js[k+2]= js[k+2]+100 ;   }  //左右
   if (pn[k-15]==0&&pn[k+15]==0&&pn[k+30]==0&&pn[k+45]==1&&pn[k+60]==0){  
        js[k+15]= js[k+15]+100 ;   
        js[k+30]= js[k+30]+100 ;   }  //上下
   if (pn[k-14]==0&&pn[k+14]==0&&pn[k+28]==0&&pn[k+42]==1&&pn[k+56]==0){  
        js[k+14]= js[k+14]+100 ;   
        js[k+28]= js[k+28]+100 ;   }  //斜左
   if (pn[k-16]==0&&pn[k+16]==0&&pn[k+32]==0&&pn[k+48]==1&&pn[k+64]==0){  
        js[k+16]= js[k+16]+100 ;   
        js[k+32]= js[k+32]+100 ;   }  //右斜
           }  //010010

//四四禁手算法同三三禁手
//四四禁手形 0 1 110 ,  前后 0 位计权
  if (pn[k]==1){  //scan B (k)
   if (pn[k+1]==1&&pn[k+2]==1){  
     if (pn[k-2]==0&&pn[k-1]==0) js[k-1]= js[k-1]+100 ;   
     if (pn[k+3]==0&&pn[k+4]==0)js[k+3]= js[k+3]+100 ; 
            }  //左右

   if (pn[k+15]==1&&pn[k+30]==1){  
        if(pn[k-30]==0&&pn[k-15]==0) js[k-15]=js[k-15]+100 ;   
        if (pn[k+45]==0&&pn[k+60]==0)js[k+45]= js[k+45]+100 ;  
            }  //上下

     if (pn[k-14]==0&&pn[k+14]==1&&pn[k+28]==1&&pn[k+42]==0){  
      if (pn[k-28]==0) js[k-14]= js[k-14]+100 ;   
      if (pn[k+56]==0)js[k+42]= js[k+42]+100 ; 
     if (pn[k+56]==0)js[k+56]= js[k+56]+100 ;   }  //斜左

   if (pn[k-16]==0&&pn[k+16]==1&&pn[k+32]==1&&pn[k+48]==0){  
      if (pn[k-32]==0) js[k-16]= js[k-16]+100 ;   
     if (pn[k+64]==0)js[k+48]= js[k+48]+100 ;   
     if (pn[k+64]==0)js[k+64]= js[k+64]+100 ;   }  //右斜
           }  //01110

//四四禁手形 0 1 1010 ,  0 1 0110 前后 0 位计权
   if (pn[k]==1){  //scan B (k)
   if (pn[k-1]==0&&pn[k+1]==0&&pn[k+3]==1&&pn[k+4]==0){  
    if (pn[k+1]==0&&pn[k+2]==1)js[k+1]= js[k+1]+100 ;   
    if (pn[k+1]==1&&pn[k+2]==0)js[k+2]= js[k+2]+100 ;  
               }  //左右

    if (pn[k-15]==0&&pn[k+15]==0&&pn[k+45]==1&&pn[k+60]==0){  
    if (pn[k+15]==0&&pn[k+30]==1)js[k+15]= js[k+15]+100 ;   
    if (pn[k+15]==1&&pn[k+30]==0)js[k+30]= js[k+30]+100 ;  
               }  //上下

    if (pn[k-14]==0&&pn[k+14]==0&&pn[k+42]==1&&pn[k+56]==0){  
    if (pn[k+14]==0&&pn[k+28]==1)js[k+14]= js[k+14]+100 ;   
    if (pn[k+14]==1&&pn[k+28]==0)js[k+28]= js[k+28]+100 ;  
               }  //斜左

     if (pn[k-16]==0&&pn[k+16]==0&&pn[k+48]==1&&pn[k+64]==0){  
    if (pn[k+16]==0&&pn[k+32]==1)js[k+16]= js[k+16]+100 ;   
    if (pn[k+16]==1&&pn[k+32]==0)js[k+32]= js[k+32]+100 ;  
               }  //右斜
             } //0 1 1010  0 1 0110

//禁手的基本设置就这样,其他有些特殊的情况暂不
//设置,AI完整智能版需全设置。上述设置是个示例。
 //长连禁手设置:在判胜负函数 detect () 时
 // 黑棋超过五连即判黑负,白棋胜。
              }    }//scan i , j
 //********** 
    cs.SetTextSize (16);
     cs.SetTextStyle (0);
    for (i=1;i<=225;i++){    //test restrict_move
           if (js[i] !=0) {      //Mark it 标记禁手点
             s=intToString ( js[i]) ;
     dx=(i-(i/15*15))*40;
     dy=(i/15)*40+40;
       if (dx==0){ dx=15*40;    dy=dy-40;   }
           cs.SetColor (255,250,250,0) ;
           cs.DrawCircle (dx,dy,3) ;     //draw mark
       if (js[i]>100){
           cs.SetColor (255,180,0,180) ;
           cs.DrawCircle (dx,dy,5) ;  } //draw mark
              }     }
    cs.Update () ;
    // sleep(500) ;
}//restrict_move ()

set_smode ( ) {  //选择开局定式
            if (mode==1) return;    //人机模式不设定式
      gamestart () ;
     smode=doubleInput("选择开局26定式(人机模式不设置定式)",  "1. 寒星局  2. 溪月局  3. 疏星局  4. 花月局  ......  23. 明星局  24. 斜月局  25. 名月局  26. 彗星局    \n      输入 [ 空 ] 或 ( 0 ) 则取消 "  );
            if (smode==0) return;    
            if (smode>26) smode=1 ;  //防选空
    num=(int)smode ;  //double to int 
    n=113 ; wn=0 ; 
    black_do () ;   //开局黑首子天元位
//  1. 寒星局  2. 溪月局  3. 疏星局  
//  4. 花月局  5. 残月局  6. 雨月局
//  7. 金星局  8. 松月局  9. 丘月局
//10. 新月局  11. 瑞星局 12. 山月局   
//13. 游星局        **>  (1-13是直指式)
//14. 长星局  15. 峡月局  16. 恒星局  
//17. 水月局  18. 流星局  19. 云月局  
//20. 浦月局  21. 岚月局  22. 银月局
//23. 明星局  24. 斜月局  25. 名月局
//26. 彗星局        **>(14-26是斜指式)
      if (num==1) {  //直指
             s8=" 1. 寒星局" ;
             n=98 ;  white_do () ;
             n=83;  black_do () ;   }
      if (num==2) {  //直指
             s8=" 2. 溪月局" ;
             n=98 ;  white_do () ;
             n=84 ;  black_do () ;     }
      if (num==3) {  //直指
             s8=" 3. 疏星局" ;
             n=98 ;  white_do () ;
             n=85 ;  black_do () ;     }
      if (num==4) {  //直指
             s8=" 4. 花月局" ;
             n=98 ;  white_do () ;
             n=99 ;  black_do () ;     }
      if (num==5) {  //直指
             s8=" 5. 残月局" ;
             n=98 ;  white_do () ;
             n=100 ;  black_do () ;     }
      if (num==6) {  //直指
             s8=" 6. 雨月局" ;
             n=98 ;  white_do () ;
             n=114 ;  black_do () ;     }
      if (num==7) {  //直指
             s8=" 7. 金星局" ;
             n=98 ;  white_do () ;
             n=115;  black_do () ;   }
      if (num==8) {  //直指
             s8=" 8. 松月局" ;
             n=98 ;  white_do () ;
             n=128 ;  black_do () ;     }
      if (num==9) {  //直指
             s8=" 9. 丘月局" ;
             n=98 ;  white_do () ;
             n=129 ;  black_do () ;     }
      if (num==10) {  //直指
             s8="10. 新月局" ;
             n=98 ;  white_do () ;
             n=130;  black_do () ;   }
      if (num==11) {  //直指
             s8="11. 瑞星局" ;
             n=98 ;  white_do () ;
             n=143 ;  black_do () ;     }
      if (num==12) {  //直指
             s8="12. 山月局" ;
             n=98 ;  white_do () ;
             n=144 ;  black_do () ;     }
      if (num==13) {  //直指
             s8="13. 游星局" ;
             n=98 ;  white_do () ;
             n=145 ;  black_do () ;     }
//以上是直指开局13式,以下是斜指开局13式
      if (num==14) {  //斜指
             s8="14. 长星局" ;
             n=99 ;  white_do () ;
             n=85 ;  black_do () ;     }
      if (num==15) {  //斜指
             s8="15. 峡月局" ;
             n=99 ;  white_do () ;
             n=100 ;  black_do () ;     }
      if (num==16) {  //斜指
             s8="16. 恒星局" ;
             n=99 ;  white_do () ;
             n=115 ;  black_do () ;     }
      if (num==17) {  //斜指
             s8="17. 水月局" ;
             n=99 ;  white_do () ;
             n=130 ;  black_do () ;     }
      if (num==18) {  //斜指
             s8="18. 流星局" ;
             n=99 ;  white_do () ;
             n=145 ;  black_do () ;     }
      if (num==19) {  //斜指
             s8="19. 云月局" ;
             n=99 ;  white_do () ;
             n=114 ;  black_do () ;     }
      if (num==20) {  //斜指
             s8="20. 浦月局" ;
             n=99 ;  white_do () ;
             n=129 ;  black_do () ;     }
      if (num==21) {  //斜指
             s8="21. 岚月局" ;
             n=99 ;  white_do () ;
             n=144 ;  black_do () ;     }
      if (num==22) {  //斜指
             s8="22. 银月局" ;
             n=99 ;  white_do () ;
             n=128 ;  black_do () ;     }
      if (num==23) {  //斜指
             s8="23. 明星局" ;
             n=99 ;  white_do () ;
             n=143 ;  black_do () ;     }
      if (num==24) {  //斜指
             s8="24. 斜月局" ;
             n=99 ;  white_do () ;
             n=127 ;  black_do () ;     }
      if (num==25) {  //斜指
             s8="25. 名月局" ;
             n=99 ;  white_do () ;
             n=142 ;  black_do () ;     }
      if (num==26) {  //斜指
             s8="26. 彗星局" ;
             n=99 ;  white_do () ;
             n=141 ;  black_do () ;     }
}//set_mode ()

undo(){      //悔棋设置
      if (isDo==1) { 
            pn[n]=0;     fudat[dn]=0;
            print "悔 "+intToString (n);
            cs.SetTextStyle (0);
            cs.SetTextSize (16);
            cs.SetColor(255,250,0,0);
            cs.DrawText ("悔",655,dn*16);   
            dn=dn-1 ;  //序号减 1
         if (dn<1) dn=0 ;
            //cs.Update ();
            board ();         }
}//undo ()

replay (){    //复盘
      gamestart ( );
      setDisplay (1);
      print "fusum= " ,fusum;
   for (i=1;i<=fusum;i++){    
  //draw chess pieces 画出复盘黑子白子
     kn=fudat[i] ;     //取得数据
     sd=i-i/2*2 ;       //mod   0=白棋, 1=黑棋
      dx=(kn-(kn/15*15))*40;
      dy=(kn/15)*40+40;
       if (dx==0){ dx=15*40;    dy=dy-40;   }
 if ( sd==0){  //white
       ss=intToString (kn);
       cordp=" W "+ss;
         row=15-(kn/15) ;
         col=(kn-(kn/15*15)) ;
         swapabc () ;
         print i,"  ",cordp,"     " , ss,row ;  //打印记录
         ss4="W  "+ss+intToString (row) ;
    cs.SetColor (255,140,80,40);  //piecesW
       cs.DrawCircle(dx+2,dy+2,17);
    cs.SetColor (255,220,220,220);  //pieceW
       cs.DrawCircle(dx,dy,17);
    cs.SetColor (255,250,250,250);  //pieceW
       cs.DrawCircle(dx-6,dy-6,2);   }
 if ( sd==1){  //black
       ss=intToString (kn);
       cordp=" B "+ss;
         row=15-(kn/15) ;
         col=(kn-(kn/15*15)) ;
         swapabc () ;
         print i,"  ",cordp,"     " , ss,row ;  //打印记录
        ss4=" B  "+ss+intToString (row) ;
    cs.SetColor (255,220,100,40);  //piecesB
       cs.DrawCircle(dx+1,dy+1,17);
    cs.SetColor (255,0,0,0);  //pieceB
       cs.DrawCircle(dx,dy,17);
    cs.SetColor (255,200,200,200);  //pieceB
       cs.DrawCircle(dx-6,dy-6,2);       }
   
    if (i==fusum){
    cs.SetColor (255,0,250,0);    //标志最末胜子点
       cs.DrawCircle(dx,dy,5);      
          cs.SetTextStyle (1);
          cs.SetTextSize (60);   
      cs.SetFillMode (1);//0不填色,1填色
       cs.SetColor (255,160,70,40);  
          cs.DrawText ("复  盘",253, 553) ;   
         cs.SetColor (255,250,250,0);  
          cs.DrawText ("复  盘",250, 550) ;    
      cs.SetFillMode (0);//0不填色,1填色
           cs.SetColor (255,50,250,0);  
          cs.DrawText ("复  盘",250, 550) ;       
       //if ( sd==0)   print "白棋胜 ! " ;
      // if ( sd==1)   print "黑棋胜 ! " ;
          print ss9 ;
                }  //=fusum           
       cs.SetFillMode (1);//0不填色,1填色
       cs.SetTextStyle (0);
       cs.SetTextSize (16);   
       s=intToString (i);       //标记序号
         cs.SetColor (255,250,0,0);  
         cs.DrawText (s,dx-5,dy+5);
      //界面显示记录
        cs.SetTextSize (18);
     cs.SetColor(255,150,0,0);
     cs.DrawText (ss4,655,i*16);      //界面显示记录
     cs.Update ();    
    sleep (1000);
               } //draw replay chess pieces                
     isDo=0 ;      //结束标志   
}//replay ()

myToolBarProc(int nBtn,int nContext)
{
      if(nBtn==100){//开始游戏
           gamestart ();    
                   }
      if(nBtn==101){//选择游戏模式
            mode=mode+1;    //0=人人, 1= 人机
           if (mode>1) mode=0 ;  
           if (mode==0) s7="游戏模式:双人对弈 ";   
           if (mode==1) s7="游戏模式:人机模式 ";  
               gamestart ();   
                   }
      if(nBtn==102){//黑棋下子
          if ( pn[n]==0) black_do() ;    
                    }
      if(nBtn==103){//白棋下子,双人对弈模式
          if (mode==0&&pn[n]==0) white_do () ;    
                     }
      if(nBtn==104){//退出程序
          clearOutput();
          cs.ClearDraw (0,src);
          setDisplay (0);
          exit (0);    
                   }
     if(nBtn==105){//查看记录
           cord=cord+1;
           if (cord>1) cord=0 ;
           if (cord==0) setDisplay (0);    //查看记录
           if (cord==1) setDisplay (1);    //显示棋板
                  }
}//myToolBar ()

myMenuProc(int nMen,int nContext)
{
   if(nMen==200){   //选择开局模式
           //gamestart (); 
           set_smode ( ) ;
                   } 
   if(nMen==201){   //选择游戏模式
            mode=mode+1;    //0=人人, 1= 人机
         if (mode>1) mode=0 ;  
         if (mode==0) s7="游戏模式:双人对弈 ";   
         if (mode==1) s7="游戏模式:人机模式 ";  
               gamestart ();   
                   }          
    if(nMen==202){  //悔棋
          undo ();   
                }
    if (nMen==203){  //复盘
           replay ();
                }
    if (nMen==204){  //禁手设置
           restrict_set () ;    
                 }
    if(nMen==205){   //查看记录
         setDisplay (0);    
                }  
    if(nMen==206){  //显示棋板
         setDisplay (1);    
             }
    if (nMen==207){  //Exit 
        clearOutput();
        cs.ClearDraw (0,src);
        setDisplay (0);
        exit (0);
            }
  }//myMenu()

loadpic (){  //用于装载预设棋盘底图
//use filebox open files and load a picture
         filebox.SetTitle("装载图片(*.bmp;*.jpg;*.png)");
         filebox.SetFilter(".bmp;.jpg;.png");
         filebox.Show();
         if(filebox.GetCount()==1){
            fname=filebox.GetFileName(0);
         if(getPicSize(fname,size)<0){  return;     }
          cs.ClearDraw (0,src);
          cs.DrawBitmap(fname,0,0);
          cs.Update ();        }
}//loadpic ()

 

//****End****

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是五子棋人机对弈算法设计与实现的思路: 1. 基本思路 五子棋是一种纯策略游戏,因此我们需要设计一个算法来评估当前局面。我们先定义一个评估函数,分别对黑方和白方进行评估,评估函数的返回值表示当前局面的得分。 接着,我们需要使用一种搜索算法来寻找最佳的下棋位置,常用的搜索算法有 MiniMax 算法和 Alpha-Beta 剪枝算法。 2. 评估函数 评估函数需要考虑以下因素: - 棋型:比如三连、四连等等。不同的棋型得分不同。 - 棋子数量:棋子数量越多得分越高。 - 棋子位置:中心位置得分更高,边缘位置得分更低。 我们可以将以上因素加权求和,得到一个综合得分。 3. MiniMax 算法 MiniMax 算法是一种递归搜索算法,用于在两个玩家之间进行决策。算法假设一方玩家采取最佳决策,而另一方玩家采取最劣决策。因此,算法会检查所有可能的决策并选择最优解。 MiniMax 算法的缺点是需要搜索整个游戏树,时间复杂度较高。 4. Alpha-Beta 剪枝算法 Alpha-Beta 剪枝算法是 MiniMax 算法的一种优化,通过剪枝减少搜索的分支数,从而提高搜索效率。 Alpha-Beta 剪枝算法假设一方玩家采取最佳决策,而另一方玩家采取最劣决策。在搜索过程中,如果发现某个节点的值已经比当前最优解差,则可以剪枝,停止搜索该节点的子树。 5. 实现思路 我们可以先实现一个基本的 MiniMax 算法,然后再使用 Alpha-Beta 剪枝算法进行优化。 具体实现步骤如下: - 定义评估函数,根据当前局面评估黑方和白方的得分。 - 实现 MiniMax 算法,搜索整个游戏树,返回最佳决策。 - 实现 Alpha-Beta 剪枝算法,优化 MiniMax 算法,减少搜索分支数。 - 设计交互界面,让用户与 AI 进行对弈。 6. 总结 五子棋是一种纯策略游戏,对于 AI 来说,评估函数和搜索算法设计非常重要。我们可以通过定义合适的评估函数和使用优秀的搜索算法,让 AI 学会更好地下棋。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值