五子棋AI算法和开局定式( 直指13式 )破解
先前发了几篇五子棋游戏程序设计的博文,设计了游戏程序,也设计了AI智能奕棋的算法,运行程序检测算法的可行性,完成人机模式游戏功能的设置。这还不够,还要提高算法的实战水平。
对于人机对战的电脑智能应子算法,参阅很多五子棋书籍棋谱和五子棋竞赛的对抗棋谱。我感到白棋的后手防御算法很难取胜,棋界有黑棋高手先手必胜一说。算法么想了很多,既然是人工智能下棋就得按人的思路来算计。棋书阐述有许多思路和棋局解说。如活四冲四,嵌五,活三嵌四,活二嵌三。这些是高级棋手的总结。我就按此思路用加权计权方法来表现此类各种情况。
我对算法的思路是:黑棋的进攻点就是白棋的防守点,反之,白棋的进攻点就是黑棋的防守点。我采用一次遍历棋盘各点位的方法,凡有黑子和白子就判断其四周的空白点,即可下子位,评估棋势加权计分。棋势就是单子、活二活三,嵌三嵌四、活四冲四嵌五。各个棋势的交点就叠加计分,高分点就是双方博弈的必争点。算法的要点是:独子成二是起点,连二到连三是重点,关键的要点是三连子到四连五连。这三点就分出权重的棋势。活三0022200两边的点位是,先手是绝杀点,后手是防守逢三必堵。眠三122200棋势,空位下子成冲四,这是抢先手改势扩势来进攻。若抓到冲四活三,嵌五活三,双活三等棋势的叠加进攻点,权分叠加计权,就能绝杀对方。我的算法思路就这样。
算法想白棋后手取胜,就在白棋的棋势上加小分,这样利于白棋在同等情况下能争得先手,反战进攻取胜。黑棋先手要取胜,从第7手开始和9手11手要保持先手,争外势抢先做活三进攻,之后要保先手,做活三冲四,进攻是决胜的法宝。想法很简单,写算法也不难,而对于棋势的加权分的估量较难。
此算法经许多次测试,还没能做到AI必胜。然而人机对战时,AI执白棋防守和反攻还是较出色的。
图例:
五子棋博弈要算杀,算杀就是计算必杀之局。必杀局有双活三,双冲四,冲四加活三,嵌五加活三,嵌五加冲四,这些必杀局就是必胜法宝。此算法的要点就是如何加权必杀局棋势的加权分。文后附源码中的testAIq( )测试代码,算法至要可见一斑,自己体会一下。游戏程序代码可参阅我本站的其他博文。
算杀的最高境界是做杀,预判算出必杀点提前几子做出必杀局。此谓奕道高手中的高手,乃高高手也。此种算法也就是编程界的高手,是谓大咖也。我望之有些高仰,自感境界还没到。叠加计权计分有趋向于此类。
还有一个方法是大数据,现在一些人工智能就是大数据堆砌,所谓算法就是数据处理。搞一个数据文件包,按26开局定式加不定式开局来定文件目录,给游戏程序喂招,黑棋的胜局就保存为数据文件。对奕时就提取数据来对比,从数据中找同样走法来定落子。就这是必胜法,就是数据量较大。数据处理的计算速度一般PC是可以的。搞个几万个数据的文件包,也不要一个G的。这些开销PC是能行的,运行速度也不会慢。
据传五子棋程序“挑战者”AI算法很好,能黑先手必胜。我试了一下,程序执黑先手AI的算力是可以的。不知道五子棋高手试过否。程序执白的AI算力一般。下图是我执黑VS挑战者程序AI,我执黑先手胜。
图:开局定式(26种定式)
五子棋竞赛规定了开局定式,直指开局13式和斜指开局13式。
下面先列出直指开局13式黑先手胜的破解,虽仅几个图例,感兴趣的可用我的程序和AI算法深入研究。
1、寒星局:黑7手F10先手,15手G8起不失先手连攻,21手H7活三连守带攻,27手H6活三,29手H5冲四进攻,35手G5冲四活三绝杀取胜。
2、溪月局:黑7手F8做二,15手F6活三进攻,15手F8活三抢攻,17手G5活三,19手H4冲四连攻,25手H5活三,27手F4活三攻,29手I 4冲四嵌四绝杀取胜。
3、疏星局:黑11手K8抢攻,15手J8连攻,23手K9活三嵌四杀棋取胜。
4、花月局:黑7手起争外势保先手,23手K6,27手J7进攻,37手L9双嵌四定胜局。
5、残月局:展示AI算法对战演示,黑先手胜。
6、雨月局:黑11手H11活三进攻,19手F8,21手G9,二个活三进攻,接着23手,25手,35手,37手四个冲四做成绝杀取胜。
7、金星局:黑9手G6争外势,15手G7活三进攻,21手G5冲四活三取胜。
8、松月局:黑7手J 9抢攻,11手I 7 连攻,17手J7活三嵌四取胜。
9、丘月局:黑7手G7,15手H6活三进攻,19手G6活三连攻,23手G5冲四活三取胜。
10、新月局:黑19手J6活三进攻,23手G6,25手I 6活三连攻,27手H7双活三杀棋取胜。
11、瑞星局:黑9手G9,13手G8活三连冲四抢攻,17手F8双活三杀局取胜。
12、山月局:展示AI算法对战演示,黑先手胜。
13、游星局:黑11手I 5活三,13手H4冲四进攻,后不失先手,至25手,H3冲四活三,G5J5二个双活三,H3J3二点位冲四嵌四,黑先绝杀获胜。
另外:我在研究查找冲四活三,嵌五活三,双活三点位的算法。上图100分为双活三或活三嵌四的棋势,若150分则有三个棋势叠加,250分以上是冲四活三,冲四嵌四,嵌五活三,嵌五嵌四等各类棋势。
附录:五子棋AI智能算法测试代码
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]+30 ;
if (pn[k+1]==0) jqn[k+1]= jqn[k+1]+30 ;
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]+30 ;
if (pn[k-16]==0) jqn[k-16]= jqn[k-16]+20 ;
if (pn[k+16]==0) jqn[k+16]= jqn[k+16]+30 ;
} //pn(k)=2
//二连 002200 为成活三冲四进攻点
if (j>2&&j<13){
if (pn[k]==2&&pn[k+1]==2){ //左右
if (pn[k-2]==0&&pn[k-1]==0) { jqn[k-1]= jqn[k-1]+1000 ; jqn[k-2]= jqn[k-2]+500 ; }
if (pn[k+3]==0&&pn[k+2]==0) { jqn[k+2]= jqn[k+2]+1000 ; jqn[k+3]= jqn[k+3]+500 ; }
if (pn[k-2]==0&&pn[k-1]==0&&pn[k+3]==0&&pn[k+2]==0) { jqn[k-1]= jqn[k-1]+300 ; jqn[k+2]= jqn[k+2]+300 ; } //活二抢活三
} }
if (i>2&&i<13){
if (pn[k]==2&&pn[k+15]==2){ //上下
if (pn[k-30]==0&&pn[k-15]==0) { jqn[k-15]= jqn[k-15]+1000 ; jqn[k-30]= jqn[k-30]+500 ; }
if (pn[k+45]==0&&pn[k+30]==0) { jqn[k+30]= jqn[k+30]+1000 ; jqn[k+45]= jqn[k+45]+500 ; }
if (pn[k-30]==0&&pn[k-15]==0&&pn[k+45]==0&&pn[k+30]==0) { jqn[k-15]= jqn[k-15]+300 ; jqn[k+30]= jqn[k+30]+300 ; } //活二抢活三
} }
if (i>2&&i<13&&j>4&&j<15){
if (pn[k]==2&&pn[k+14]==2){ //左对角
if (pn[k-28]==0&&pn[k-14]==0) { jqn[k-14]= jqn[k-14]+1000 ; jqn[k-28]= jqn[k-28]+500 ; }
if (pn[k+42]==0&&pn[k+28]==0) { jqn[k+28]= jqn[k+28]+1000 ; jqn[k+42]= jqn[k+42]+500 ; }
if (pn[k-28]==0&&pn[k-14]==0&&pn[k+42]==0&&pn[k+28]==0) { jqn[k-14]= jqn[k-14]+300 ; jqn[k+28]= jqn[k+28]+300 ; } //活二抢活三
} }
if (i>2&&i<13&&j>2&&j<13){
if (pn[k]==2&&pn[k+16]==2){ //右对角
if (pn[k-32]==0&&pn[k-16]==0) { jqn[k-16]= jqn[k-16]+1000 ; jqn[k-32]= jqn[k-32]+500 ; }
if (pn[k+48]==0&&pn[k+32]==0) { jqn[k+32]= jqn[k+32]+1000 ; jqn[k+48]= jqn[k+48]+500 ; }
if (pn[k-32]==0&&pn[k-16]==0&&pn[k+48]==0&&pn[k+32]==0) { jqn[k-16]= jqn[k-16]+300 ; jqn[k+32]= jqn[k+32]+300 ; } //活二抢活三
} }
//二连 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]+300 ;
if (pn[k-1]==0){ jqn[k-1]= jqn[k-1]+600 ; jqn[k+1]= jqn[k+1]+600 ; }
if (pn[k+3]==0){ jqn[k+3]= jqn[k+3]+600 ; jqn[k+1]= jqn[k+1]+600 ; } } }
if (i>1&&i<13){
if (pn[k]==2&&pn[k+15]==0&&pn[k+30]==2){ //上下
jqn[k+15]= jqn[k+15]+300 ;
if (pn[k-15]==0){ jqn[k-15]= jqn[k-15]+600 ; jqn[k+15]= jqn[k+15]+600 ; }
if (pn[k+45]==0){ jqn[k+45]= jqn[k+45]+600 ; jqn[k+15]= jqn[k+15]+500 ; } } }
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]+300 ;
if (pn[k-14]==0){ jqn[k-14]= jqn[k-14]+600 ; jqn[k+14]= jqn[k+14]+600 ; }
if (pn[k+42]==0){ jqn[k+42]= jqn[k+42]+600 ; jqn[k+14]= jqn[k+14]+600 ; } } }
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]+300 ;
if (pn[k-16]==0){ jqn[k-16]= jqn[k-1]+600 ; jqn[k+16]= jqn[k+16]+600 ; }
if (pn[k+48]==0){ jqn[k+48]= jqn[k+48]+600 ; jqn[k+16]= jqn[k+16]+600 ; } } }
//三连,眠三抢冲四 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]+610 ;
if (pn[k-1]==0&&pn[k-2]==0) jqn[k-1]= jqn[k-1]+2100 ; //必杀点加权分
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]+610 ;
if (pn[k+3]==0&&pn[k+4]==0) jqn[k+3]= jqn[k+3]+2100 ;
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]+610 ;
if (pn[k-15]==0&&pn[k-30]==0) jqn[k-15]= jqn[k-15]+2100 ;
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]+610 ;
if (pn[k+45]==0&&pn[k+60]==0) jqn[k+45]= jqn[k+45]+2100 ;
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]+610 ;
if (pn[k-14]==0&&pn[k-28]==0) jqn[k-14]= jqn[k-14]+2100 ;
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]+610 ;
if (pn[k+42]==0&&pn[k+56]==0) jqn[k+42]= jqn[k+42]+2100 ;
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]+610 ;
if (pn[k-16]==0&&pn[k-32]==0) jqn[k-16]= jqn[k-16]+2100 ;
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]+610 ;
if (pn[k+48]==0&&pn[k+64]==0) jqn[k+48]= jqn[k+48]+2100 ;
if (pn[k+48]==0&&pn[k+64]==0) jqn[k+64]= jqn[k+64]+550 ; } }
//三连,活三变活四,必杀 0022200 与上叠加
if ( pn[k-1]==0&&pn[k]==2&&pn[k+1]==2&&pn[k+2]==2&&pn[k+3]==0){ //左右
if (pn[k-2]==0) jqn[k-1]= jqn[k-1]+1500 ;
if (pn[k+4]==0)jqn[k+3]= jqn[k+3]+1500 ; }
if (pn[k-15]==0&&pn[k]==2&&pn[k+15]==2&&pn[k+30]==2&&pn[k+45]==0){ //上下
if (pn[k-30]==0) jqn[k-15]= jqn[k-15]+1500 ;
if (pn[k+60]==0) jqn[k+45]= jqn[k+45]+1500 ; }
if(pn[k-14]==0&&pn[k]==2&&pn[k+14]==2&&pn[k+28]==2&&pn[k+42]==0){//左对角
if (pn[k-28]==0)jqn[k-14]= jqn[k-14]+1500 ;
if (pn[k+56]==0) jqn[k+42]= jqn[k+42]+1500 ; }
if (pn[k-16]==0&&pn[k]==2&&pn[k+16]==2&&pn[k+32]==2&&pn[k+48]==0){//右对角
if (pn[k-32]==0)jqn[k-16]= jqn[k-16]+1500 ;
if (pn[k+64]==0)jqn[k+48]= jqn[k+48]+1500 ; }
//*********
//白子算杀,做杀,找活三嵌四交点 +000
//白棋进攻态势,与二连三连计分叠加抢先手
//嵌四类 做冲四 2022 2202 布杀点 +00
// 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]+550 ; } }
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]+550 ; } }
} //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]+550 ; } }
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]+550 ; } }
}
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]+550 ; } }
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]+550 ; } }
} //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]+550 ; } }
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]+550 ; } }
} //i<12&&j<12
//嵌四 020220 022020 必杀点+ 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]+2850 ; }
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]+2850 ; } }
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]+2850 ; }
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]+2850 ; } }
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]+2850 ; }
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]+2850 ; } }
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]+2850 ; }
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]+2850 ; } }
//活四冲四成五连 022220 122220 022221
//此是绝杀点 黑白方均都 +5000 j<12 防越界
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]+5000 ;
if (pn[k+4]==0) jqn[k+4]= jqn[k+4]+5000 ; } }
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]+5000 ;
if (pn[k+60]==0) jqn[k+60]= jqn[k+60]+5000 ; } }
if (j>4&&j<15&&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]+5000 ;
if (pn[k+56]==0) jqn[k+56]= jqn[k+56]+5000 ; } }
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]+5000 ;
if (pn[k+64]==0) jqn[k+64]= jqn[k+64]+5000 ; } }
//嵌五,此是必杀点 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]+5000 ; }
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]+5000 ; }
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]+5000 ; } } //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]+5000 ; }
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]+5000 ; }
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]+5000 ; } } //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]+5000 ; }
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]+5000 ; }
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]+5000 ; } }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; } }
//****************************
//以下是黑棋估权计分
//黑棋进攻点亦即白棋防守点,白下子亦取高分位
//进攻策略活二抢活三,眠三抢冲四,有冲四活三嵌五活三就必胜,先手不放,如白棋有活三也可冲四抢攻。
//独子 左右上下 二对角 八方
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-2]==0) jqn[k-2]= jqn[k-2]+30 ;
if (pn[k+2]==0) jqn[k+2]= jqn[k+2]+30 ;
if (pn[k-15]==0) jqn[k-15]= jqn[k-15]+70 ; //直指
if (pn[k+15]==0) jqn[k+15]= jqn[k+15]+50 ;
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]+60 ; //斜指
if (pn[k-16]==0) jqn[k-16]= jqn[k-16]+20 ;
}//pn
//二连 001100 0110 为成活三冲四进攻点
if (j>1&&j<13){
if (pn[k]==1&&pn[k+1]==1){ //左右
if (pn[k-2]==0&&pn[k-1]==0) { jqn[k-1]= jqn[k-1]+1000 ; jqn[k-2]= jqn[k-2]+900 ; }
if (pn[k+3]==0&&pn[k+2]==0) { jqn[k+2]= jqn[k+2]+1000 ; jqn[k+3]= jqn[k+3]+900 ; }
if (pn[k-2]==0&&pn[k-1]==0&&pn[k+3]==0&&pn[k+2]==0) { jqn[k-1]= jqn[k-1]+1300 ; jqn[k+2]= jqn[k+2]+1300 ; } //活二抢活三
} }
if (i>1&&i<13){
if (pn[k]==1&&pn[k+15]==1){ //上下
if (pn[k-30]==0&&pn[k-15]==0) { jqn[k-15]= jqn[k-15]+1000 ; jqn[k-30]= jqn[k-30]+900 ; }
if (pn[k+45]==0&&pn[k+30]==0) { jqn[k+30]= jqn[k+30]+1000 ; jqn[k+45]= jqn[k+45]+900 ; }
if (pn[k-30]==0&&pn[k-15]==0&&pn[k+45]==0&&pn[k+30]==0) { jqn[k-15]= jqn[k-15]+1300 ; jqn[k+30]= jqn[k+30]+1300 ; } //活二抢活三
} }
if (i>1&&i<13&&j>3&&j<15){
if (pn[k]==1&&pn[k+14]==1){ //左对角
if (pn[k-28]==0&&pn[k-14]==0) { jqn[k-14]= jqn[k-14]+1000 ; jqn[k-28]= jqn[k-28]+900 ; }
if (pn[k+42]==0&&pn[k+28]==0) { jqn[k+28]= jqn[k+28]+1000 ; jqn[k+42]= jqn[k+42]+900 ; }
if (pn[k-28]==0&&pn[k-14]==0&&pn[k+42]==0&&pn[k+28]==0) { jqn[k-14]= jqn[k-14]+1300 ; jqn[k+28]= jqn[k+28]+1300 ; } //活二抢活三
} }
if (i>1&&i<13&&j>2&&j<13){
if (pn[k]==1&&pn[k+16]==1){ //右对角
if (pn[k-32]==0&&pn[k-16]==0) { jqn[k-16]= jqn[k-16]+1000 ; jqn[k-32]= jqn[k-32]+900 ; }
if (pn[k+48]==0&&pn[k+32]==0) { jqn[k+32]= jqn[k+32]+1000 ; jqn[k+48]= jqn[k+48]+900 ; }
if (pn[k-32]==0&&pn[k-16]==0&&pn[k+48]==0&&pn[k+32]==0) { jqn[k-16]= jqn[k-16]+1300 ; jqn[k+32]= jqn[k+32]+1300 ; } //活二抢活三
} }
//连二 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]+800 ;
if (pn[k+4]==0&&pn[k+2]==0) jqn[k+2]= jqn[k+2]+800 ; } }
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]+800 ;
if (pn[k+60]==0&&pn[k+30]==0) jqn[k+30]= jqn[k+30]+800 ; } }
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]+800 ;
if (pn[k+56]==0&&pn[k+28]==0) jqn[k+28]= jqn[k+28]+800 ; } }
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]+800 ;
if (pn[k+64]==0&&pn[k+32]==0) jqn[k+32]= jqn[k+32]+800 ; } }
//嵌三 01010 可成双活三
if (j>1&&j<13){
if (pn[k]==1&&pn[k+1]==0&&pn[k+2]==1){ //左右
jqn[k+1]= jqn[k+1]+800 ;
if (pn[k-1]==0){ jqn[k-1]= jqn[k-1]+1500 ; jqn[k+1]= jqn[k+1]+900 ; }
if (pn[k+3]==0){ jqn[k+3]= jqn[k+3]+1500 ; jqn[k+1]= jqn[k+1]+900 ; } } }
if (i>1&&i<13){
if (pn[k]==1&&pn[k+15]==0&&pn[k+30]==1){ //上下
jqn[k+15]= jqn[k+15]+800 ;
if (pn[k-15]==0){ jqn[k-15]= jqn[k-15]+1500 ; jqn[k+15]= jqn[k+15]+900 ; }
if (pn[k+45]==0){ jqn[k+45]= jqn[k+45]+1500 ; jqn[k+15]= jqn[k+15]+900 ; } } }
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]+800 ;
if (pn[k-14]==0){ jqn[k-14]= jqn[k-14]+1500 ; jqn[k+14]= jqn[k+14]+900 ; }
if (pn[k+42]==0){ jqn[k+42]= jqn[k+42]+1500 ; jqn[k+14]= jqn[k+14]+900 ; } } }
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]+800 ;
if (pn[k-16]==0){ jqn[k-16]= jqn[k-16]+1500 ; jqn[k+16]= jqn[k+16]+900 ; }
if (pn[k+48]==0){ jqn[k+48]= jqn[k+48]+1500 ; jqn[k+16]= jqn[k+16]+900 ; } } }
//三连,眠三21110 01112 抢冲四
if (j>1&&j<13){
if (pn[k]==1&&pn[k+1]==1&&pn[k+2]==1){ //左右
//三连成嵌五 + 叠加分进攻点
if (pn[k-1]==0) jqn[k-1]= jqn[k-1]+650 ;
if (pn[k-1]==0&&pn[k-2]==0) jqn[k-1]= jqn[k-1]+2700 ; //必杀点加权分
if (pn[k-1]==0&&pn[k-2]==0) jqn[k-2]= jqn[k-2]+1550 ;
if (pn[k+3]==0) jqn[k+3]= jqn[k+3]+650 ;
if (pn[k+3]==0&&pn[k+4]==0) jqn[k+3]= jqn[k+3]+2700 ;
if (pn[k+3]==0&&pn[k+4]==0) jqn[k+4]= jqn[k+4]+1550 ; } }
if (i>1&&i<13){
if (pn[k]==1&&pn[k+15]==1&&pn[k+30]==1){ //上下
//三连成嵌五 + 叠加分进攻点
if (pn[k-15]==0) jqn[k-15]= jqn[k-15]+650 ;
if (pn[k-15]==0&&pn[k-30]==0) jqn[k-15]= jqn[k-15]+2700 ;
if (pn[k-15]==0&&pn[k-30]==0) jqn[k-30]= jqn[k-30]+1550 ;
if (pn[k+45]==0) jqn[k+45]= jqn[k+45]+650 ;
if (pn[k+45]==0&&pn[k+60]==0) jqn[k+45]= jqn[k+45]+2700 ;
if (pn[k+45]==0&&pn[k+60]==0) jqn[k+60]= jqn[k+60]+1550 ;
} }
if (i>1&&i<13&&j>3&&j<15){
if (pn[k]==1&&pn[k+14]==1&&pn[k+28]==1){//斜左
//三连成嵌五 + 叠加分进攻点
if (pn[k-14]==0) jqn[k-14]= jqn[k-14]+650 ;
if (pn[k-14]==0&&pn[k-28]==0) jqn[k-14]= jqn[k-14]+2700 ;
if (pn[k-14]==0&&pn[k-28]==0) jqn[k-28]= jqn[k-28]+1550 ;
if (pn[k+42]==0) jqn[k+42]= jqn[k+42]+650 ;
if (pn[k+42]==0&&pn[k+56]==0) jqn[k+42]= jqn[k+42]+2700 ;
if (pn[k+42]==0&&pn[k+56]==0) jqn[k+56]= jqn[k+56]+1550 ; } }
if (i>1&&i<13&&j>1&&j<13){
if (pn[k]==1&&pn[k+16]==1&&pn[k+32]==1){//右斜
//三连成嵌五 + 叠加分进攻点
if (pn[k-16]==0) jqn[k-16]= jqn[k-16]+650 ;
if (pn[k-16]==0&&pn[k-32]==0) jqn[k-16]= jqn[k-16]+2700 ;
if (pn[k-16]==0&&pn[k-32]==0) jqn[k-32]= jqn[k-32]+1550 ;
if (pn[k+48]==0) jqn[k+48]= jqn[k+48]+650 ;
if (pn[k+48]==0&&pn[k+64]==0) jqn[k+48]= jqn[k+48]+2700 ;
if (pn[k+48]==0&&pn[k+64]==0) jqn[k+64]= jqn[k+64]+1550 ; } }
//三连,活三变活四 0011100 白方逢三必堵#
if ( pn[k-1]==0&&pn[k]==1&&pn[k+1]==1&&pn[k+2]==1&&pn[k+3]==0){ //左右
if (pn[k-2]==0) jqn[k-1]= jqn[k-1]+1500 ;
if (pn[k+4]==0)jqn[k+3]= jqn[k+3]+1500 ; }
if (pn[k-15]==0&&pn[k]==1&&pn[k+15]==1&&pn[k+30]==1&&pn[k+45]==0){ //上下
if (pn[k-30]==0) jqn[k-15]= jqn[k-15]+1500 ;
if (pn[k+60]==0) jqn[k+45]= jqn[k+45]+1500 ; }
if(pn[k-14]==0&&pn[k]==1&&pn[k+14]==1&&pn[k+28]==1&&pn[k+42]==0){//左对角
if (pn[k-28]==0)jqn[k-14]= jqn[k-14]+1500 ;
if (pn[k+56]==0) jqn[k+42]= jqn[k+42]+1500 ; }
if (pn[k-16]==0&&pn[k]==1&&pn[k+16]==1&&pn[k+32]==1&&pn[k+48]==0){//右对角
if (pn[k-32]==0)jqn[k-16]= jqn[k-16]+1500 ;
if (pn[k+64]==0)jqn[k+48]= jqn[k+48]+1500 ; }
//黑方的必杀点就是白方的防守要点
//嵌四类 010110,011010 两边空为必杀点 +000
//嵌四类 1011,1101 两边有一白是冲四 +000
if (j>1&&j<12){
if (pn[k]==1&&pn[k+1]==0&&pn[k+2]==1&&pn[k+3]==1){ //左右
if (pn[k-1]==0&&pn[k+4]==0) jqn[k+1]= jqn[k+1]+2850 ;
if (pn[k-1]==2) jqn[k+1]= jqn[k+1]+1900 ;
if (pn[k+4]==2) jqn[k+1]= jqn[k+1]+1500 ; }
if (pn[k]==1&&pn[k+1]==1&&pn[k+2]==0&&pn[k+3]==1){ //左右
if (pn[k-1]==0&&pn[k+4]==0) jqn[k+2]= jqn[k+2]+2850 ;
if (pn[k-1]==2) jqn[k+2]= jqn[k+2]+1500 ;
if (pn[k+4]==2) jqn[k+2]= jqn[k+2]+1900 ; } }
if (i>1&&i<12){
if (pn[k]==1&&pn[k+15]==0&&pn[k+30]==1&&pn[k+45]==1){ //上下
if (pn[k-15]==0&&pn[k+60]==0) jqn[k+15]= jqn[k+15]+2850 ;
if (pn[k-15]==2) jqn[k+15]= jqn[k+15]+1900 ;
if (pn[k+60]==2) jqn[k+15]= jqn[k+15]+1500 ; }
if (pn[k]==1&&pn[k+15]==1&&pn[k+30]==0&&pn[k+45]==1){ //上下
if (pn[k-15]==0&&pn[k+60]==0) jqn[k+30]= jqn[k+30]+2850 ;
if (pn[k-15]==2) jqn[k+30]= jqn[k+30]+1500 ;
if (pn[k+60]==2) jqn[k+30]= jqn[k+30]+1900 ; } }
if (i>1&&i<12&&j>3&&j<15){
if (pn[k]==1&&pn[k+14]==0&&pn[k+28]==1&&pn[k+42]==1){ //斜左
if (pn[k-14]==0&&pn[k+56]==0) jqn[k+14]= jqn[k+14]+2850 ;
if (pn[k-14]==2) jqn[k+14]= jqn[k+14]+1900 ;
if (pn[k+56]==2) jqn[k+14]= jqn[k+14]+1500 ; }
if (pn[k]==1&&pn[k+14]==1&&pn[k+28]==0&&pn[k+42]==1){ //斜左
if (pn[k-14]==0&&pn[k+56]==0) jqn[k+28]= jqn[k+28]+2850 ;
if (pn[k-14]==2) jqn[k+28]= jqn[k+28]+1500 ;
if (pn[k+56]==2)jqn[k+28]= jqn[k+28]+1900 ; } }
if (i>1&&i<12&&j>1&&j<12){
if (pn[k]==1&&pn[k+16]==0&&pn[k+32]==1&&pn[k+48]==1){ //右斜
if (pn[k-16]==0&&pn[k+64]==0) jqn[k+16]= jqn[k+16]+2850 ;
if (pn[k-16]==2) jqn[k+16]= jqn[k+16]+1900 ;
if (pn[k+64]==2) jqn[k+16]= jqn[k+16]+1500 ; }
if (pn[k]==1&&pn[k+16]==1&&pn[k+32]==0&&pn[k+48]==1){ //右斜
if (pn[k-16]==0&&pn[k+64]==0) jqn[k+32]= jqn[k+32]+2850 ;
if (pn[k-16]==2) jqn[k+32]= jqn[k+32]+1500 ;
if (pn[k+64]==2)jqn[k+32]= jqn[k+32]+1900 ; } }
//嵌四 10101 必杀点+00 j<12 防越界
if (j>1&&j<12){
if (pn[k]==1&&pn[k+1]==0&&pn[k+2]==1&&pn[k+3]==0&&pn[k+4]==1){ //左右
jqn[k+1]= jqn[k+1]+1500 ;
jqn[k+3]= jqn[k+3]+1500 ; } }
if (i>1&&i<12){
if (pn[k]==1&&pn[k+15]==0&&pn[k+30]==1&&pn[k+45]==0&&pn[k+60]==1){ //上下
jqn[k+15]= jqn[k+15]+1500 ;
jqn[k+45]= jqn[k+45]+1500 ; } }
if (i>1&&i<12&&j>3&&j<15){
if(pn[k]==1&&pn[k+14]==0&&pn[k+28]==1&&pn[k+42]==0&&pn[k+56]==1){//左对角
jqn[k+14]= jqn[k+14]+1500 ;
jqn[k+42]= jqn[k+42]+1500 ; } }
if (i>1&&i<12&&j>1&&j<12){
if (pn[k]==1&&pn[k+16]==0&&pn[k+32]==1&&pn[k+48]==0&&pn[k+64]==1){//右对角
jqn[k+16]= jqn[k+16]+1500 ;
jqn[k+48]= jqn[k+48]+1500 ; } }
//活四冲四 此是必杀点 211110 011112 +000
//黑有此白必堵,此是必杀点,先手必杀
//此是绝杀点 黑白方均都 +5000 j<12 防越界
if (j>1&&j<13){ // 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]+5000 ;
if (pn[k+4]==0) jqn[k+4]= jqn[k+4]+5000 ; } }
if (i>1&&i<13){
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]+5000 ;
if (pn[k+60]==0) jqn[k+60]= jqn[k+60]+5000 ; } }
if (i>1&&i<13&&j>4&&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]+5000 ;
if (pn[k+56]==0) jqn[k+56]= jqn[k+56]+5000 ; } }
if (i>1&&i<13&&j>1&&j<13){
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]+5000 ;
if (pn[k+64]==0) jqn[k+64]= jqn[k+64]+5000 ; } }
//嵌五 10111 11011 11101 +000
//此是必杀点:后手则必应 ,先手必杀
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
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]+5000 ; }
} } //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 ()
//End