先前发了几篇五子棋游戏程序设计的博文,设计了游戏程序,也设计了AI智能奕棋的算法,运行程序检测算法的可行性,完成人机模式游戏功能的设置。本文重点介绍测试方法。
对于人机对战的电脑智能应子算法,参阅很多五子棋书籍棋谱和五子棋竞赛的对抗棋谱。我感到白棋的后手防御算法很难取胜,棋界有黑棋高手先手必胜一说。算法么想了很多,既然是人工智能下棋就得按人的思路来算计。棋书阐述有许多思路和棋局解说。如活四冲四,嵌五,活三嵌四,活二嵌二。这些是高级棋手的总结。我就按此思路用加权计权方法来表现此类各种情况。
我对算法的思路是:黑棋的进攻点就是白棋的防守点,反之,白棋的进攻点就是黑棋的防守点。我采用一次遍历棋盘各点位的方法,凡有黑子和白子就判断其四周的空白点,即可下子位,评估棋势加权计分。棋势就是单子、活二嵌二、活三嵌三嵌四、活四冲四嵌五。各个棋势的交点就叠加计分,高分点就是双方博弈的必争点。算法的要点是:独子成二是起点,连二到连三是重点,关键的要点是三连子到四连五连。这这三点就分出权重的棋势。活三02220两边的点位是,先手是绝杀点,后手是防守逢三必堵。眠三122200棋势,空位下子成冲四,这是抢先手来改势扩势来进攻。若抓到冲四加活三叠加进攻点,权分叠加计权,就能绝杀对方。我的算法思路就这样。算法想白棋后手取胜,就在白棋的棋势上加小分,这样利于白棋在同等情况下能争得先手,反战进攻取胜。想法很简单,写算法也不难,而对于棋势的加权分的估量较难。
图例:
人机模式例:人执黑,AI 执白,无禁手则黑棋可胜,有禁手就AI胜。
五子棋博弈要算杀,算杀就是计算必杀之局。必杀局有双活三,双冲四,冲四加活三,嵌五加活三,嵌五加冲四,这些必杀局就是必胜法宝。此算法的要点就是如何加权必杀局棋势的加权分。文后附源码中的testAIq( ),算法至要可见一斑,自己体会一下。
算杀的最高境界是做杀,预判算出必杀点提前几子做出必杀局。此谓奕道高手中的高手,乃高高手也。此种算法也就是编程界的高手,是谓大咖也。我望之有些高仰,自感境界还没到。叠加计权计分有趋向于此类。还要努力,锲而不舍,持之以恒。
另外在设计上加了算法的测试方法。用来检测和改进算法。
测试算法的方法:
一是:程序运行时在黑白落子周边的空位(即可下子位)显示加权计算的分值,查看加权计分情况。最高分点位画出黄色标记点,即AI选取的下子位。
在双人模式时可以直观的看到AI加权计算的分值,以及选取下子位的过程。
在人机模式时由玩家人下黑子检测白棋的防守和进攻情况 。依据此优化和改进算法。
二是:设置自动演示功能autotest(),不需手动模拟对奕过程,连续点击《演示》按钮逐步显示黑白双方由机器选位下子过程。这就是对战演示功能。
增加26个开局定式对战演示。用以观察加权计分的设置情况,以此来测试和改进算法。也可以每步根据AI计权黄点黑白双方落子位来下子,这样可慢慢地观察加权计分情况。当然在演示功能时可介入手动操作下子,这是方法的灵活应用。
五子棋程序设置双人对奕,人机模式,对战演示三种模式。设置悔棋,记录功能,有禁手设置。另有复盘功能设置。
AI智能奕棋的算法testAIq( ),主要是检测算法,测试算法的可行性。程序设置的对战演示就是为了测试算法,此为研究五子棋算法提供一些参考。
此算法加权偏重于白棋,主要是研究如何对付”黑先必胜”。研究白棋抢先手,拦堵黑棋,反转取胜。
测试了好几个局的例子,白棋的攻防还是可以的。然而如
(例11 例12 例13例15 例16等),
黑棋还是蛮厉害的,如白棋挡不住,就还是黑棋胜。
例4花月局,例7金星局,例8松月局
白棋防守封堵都很漂亮,抢先手反攻取胜,可供参考研究。
例24斜月局,黑棋进攻力度不够,黑21手F8和23手J12失误而失先手,白棋反败为胜。
我测试了26定式局和人机对战的好多局,本文仅例出了一部分。感兴趣的朋友可自己来玩下。此游戏程序可成为喜欢五子棋游戏的练手程序。
连续点击《演示》按钮逐步演示对战:
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 ()
// 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是斜指式)