五子棋游戏禁手算法的改进

五子棋游戏禁手算法的改进

五子棋最新的禁手规则:

1.黑棋禁手判负、白棋无禁手。黑棋禁手有"三三"(包括"四三三")、"四四"(包括"四四三")和"长连"。黑棋只能以"四三"取胜。

2.黑方五连与禁手同时形成,判黑方胜。

3.黑方禁手形成时,白方应立即指出。若白方在之后继续落子,则禁手失效,此后指出禁手也不判黑方负。

注意:本条仅限于"三三"和"四四"禁手点,黑方走出的长连则不同:在对局结束前,白方无论何时指出黑方出现长连,都判白方胜。

禁手设置算法:

禁手有三种基本形,即三三禁手和四四禁手,以及长连禁手。

另外还有三三四,四四三类禁手,以及一些特殊形态的禁手。

三三禁手形态:00 10100 > 0 x K x 1 x 0

00 1100 > 0 x K 1 x 0

0 10010 > 0 K x x 1 0

四四禁手形态:00 11100 > 0 x K 1 1 x 0

0 11010 > 0 K 1 x 1 0

0 10110 > 0 K x 1 1 0

K 是遍历搜索点,if (K=1) 黑子时, x 点位就是三连和四连的禁手点位。

用遍历搜索算法按15 * 15 棋盘点位pn ( 1 -225 ),

分四个方向搜索,即左右,上下,右斜,斜左。遇黑子则计算加权分,赋100分值。此方法可减少计算量,无黑子位不计算。三三四四各形态同时搜索查验加权计算,一次遍历加权计分,最后查验加权分情况,超过100分的点位就是禁手点位。如有超过200分的情况就是三三四和四四三禁手。

长连禁手设置:在判胜负函数detect()时黑棋超过五连即是长连禁手,判黑负,白棋胜。

有一些特殊的形态如扁担阵暂不设置。此程序是简版,完整版本要全面设置。

代码中有显示计算的分值点标记,黄色是100分的点位,紫色是超过100分的点位,即禁手点位。这是测试算法时用来查看的,应用时可注释掉。

此算法是基本的算法,优点是简单和易于理解。

黑棋如设置禁手要想获胜就只有活四和嵌五,还有就是冲四活三,原先发布的博文有bug,当时较仓促,算法测试不充分,忽略了冲四活三的情况。今就此补充修正代码。

这里有个巧妙的算法,在原代码上改一下就成了。算法是三三计权分仍然是100而四四的计权分改为110,这样三三禁手分是200,四四禁手分是220,如是三三四就310分,四四三就320分,

if ( jsi>110 && jsi!=210 ) { ...... }

这样计分大于110就触发禁手,而若等于210分就是冲四活三必胜点。

图例:

黄色点是计分点,紫色点是禁手点

restrict_move ( ) { //禁手设置

//黑棋禁手,加权计算查找

for (i=1;i<=225;i++) { jsi=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 (pnk==1){ // scan B (k)

if (pnk-1==0&&pnk+1==0&&pnk+2==1&&pnk+3==0){

jsk+1= jsk+1+100 ;

if ( pnk-2==0) jsk-1= jsk-1+100 ;

if (pnk+4==0) jsk+3= jsk+3+100 ;

if ( pnk-2==1&&pnk+4==1) { //101(0)101四四的特殊情况

jsk+1= jsk+1+200 ; } }//左右

if (pnk-15==0&&pnk+15==0&&pnk+30==1&&pnk+45==0){

jsk+15= jsk+15+100 ;

if ( pnk-30==0) jsk-15= jsk-15+100 ;

if (pnk+60==0) jsk+45= jsk+45+100 ;

if ( pnk-30==1&&pnk+60==1) { //四四

jsk+15= jsk+15+200 ; } }//上下

if (pnk-14==0&&pnk+14==0&&pnk+28==1&&pnk+42==0){

jsk+14= jsk+14+100 ;

if ( pnk-28==0) jsk-14= jsk-14+100 ;

if (pnk+56==0) jsk+42= jsk+42+100 ;

if ( pnk-28==1&&pnk+56==1) { //四四

jsk+14= jsk+14+200 ; } }//斜左

if (pnk-16==0&&pnk+16==0&&pnk+32==1&&pnk+48==0){

jsk+16= jsk+16+100 ;

if ( pnk-32==0) jsk-16= jsk-16+100 ;

if (pnk+64==0) jsk+48= jsk+48+100 ;

if ( pnk-32==1&&pnk+64==1) { //四四

jsk+16= jsk+16+200 ; } }//右斜

} //00 1 0100 四四 1(0)101的特殊情况

//禁手形 00 1 100 , k前后 0位计权

if (pnk==1){ //scan B (k)

if (pnk-1==0&&pnk+1==1&&pnk+2==0){

if (pnk-2==0) jsk-2= jsk-2+100 ;

if (pnk-2==0) jsk-1= jsk-1+100 ;

if (pnk+3==0) jsk+2= jsk+2+100 ;

if (pnk+3==0) jsk+3= jsk+3+100 ; } //左右

if (pnk-15==0&&pnk+15==1&&pnk+30==0){

if (pnk-30==0) jsk-30= jsk-30+100 ;

if (pnk-30==0) jsk-15= jsk-15+100 ;

if (pnk+45==0) jsk+30= jsk+30+100 ;

if (pnk+45==0) jsk+45= jsk+45+100 ; } //上下

if (pnk-14==0&&pnk+14==1&&pnk+28==0){

if (pnk-28==0) jsk-28= jsk-28+100 ;

if (pnk-28==0) jsk-14= jsk-14+100 ;

if (j<12&&pnk+42==0) jsk+28= jsk+28+100 ;

if (pnk+42==0) jsk+42= jsk+42+100 ; } //斜左

if (pnk-16==0&&pnk+16==1&&pnk+32==0){

if (pnk-32==0) jsk-32= jsk-32+100 ;

if (pnk-32==0) jsk-16= jsk-16+100 ;

if (pnk+48==0) jsk+32= jsk+32+100 ;

if (pnk+48==0) jsk+48= jsk+48+100 ; } //右斜

} //00 1 100

//禁手形 0 1 0010 , 中间 0位计权

if (pnk==1){ //scan B (k)

if (pnk-1==0&&pnk+1==0&&pnk+2==0&&pnk+3==1&&pnk+4==0){

jsk+1= jsk+1+100 ;

jsk+2= jsk+2+100 ; } //左右

if (pnk-15==0&&pnk+15==0&&pnk+30==0&&pnk+45==1&&pnk+60==0){

jsk+15= jsk+15+100 ;

jsk+30= jsk+30+100 ; } //上下

if (pnk-14==0&&pnk+14==0&&pnk+28==0&&pnk+42==1&&pnk+56==0){

jsk+14= jsk+14+100 ;

jsk+28= jsk+28+100 ; } //斜左

if (pnk-16==0&&pnk+16==0&&pnk+32==0&&pnk+48==1&&pnk+64==0){

jsk+16= jsk+16+100 ;

jsk+32= jsk+32+100 ; } //右斜

} //010010

//四四禁手算法同三三禁手

//四四禁手形 00 1 1100 , 前后 0 位计权

//更正:冲四加活三不是禁手!! add 110分

//加:特殊禁手 111 0 x 0 111

if (pnk==1){ //scan B (k)

if (pnk+1==1&&pnk+2==1){

if (pnk-2==0&&pnk-1==0){ jsk-1= jsk-1+110 ; jsk-2= jsk-2+110 ; }

if (pnk+3==0&&pnk+4==0){

jsk+3= jsk+3+110 ; jsk+4= jsk+4+110 ; } } //左右

if (pnk+15==1&&pnk+30==1){

if (pnk-30==0&&pnk-15==0){ jsk-15= jsk-15+110 ; jsk-30= jsk-30+110 ; }

if (pnk+45==0&&pnk+60==0){

jsk+45= jsk+45+110 ; jsk+60= jsk+60+110 ; } } //上下

if (pnk+14==1&&pnk+28==1){

if (pnk-28==0&&pnk-14==0){ jsk-14= jsk-14+110 ; jsk-28= jsk-28+110 ; }

if (pnk+42==0&&pnk+56==0){

jsk+42= jsk+42+110 ; jsk+56= jsk+56+110 ; } } //斜左

if (pnk+16==1&&pnk+32==1){

if (pnk-32==0&&pnk-16==0){ jsk-16= jsk-16+110 ; jsk-32= jsk-32+110 ; }

if (pnk+48==0&&pnk+64==0){

jsk+48= jsk+48+110 ; jsk+64= jsk+64+110 ; } } //右斜

} //0 1 110 ( 111 0x0 111 )

//四四禁手形 0 1 1010 , 0 1 0110 前后 0 位计权

if (pnk==1){ //scan B (k)

if (pnk-1==0&&pnk+1==0&&pnk+3==1&&pnk+4==0){

if (pnk+1==0&&pnk+2==1)jsk+1= jsk+1+110 ;

if (pnk+1==1&&pnk+2==0)jsk+2= jsk+2+110 ;

} //左右

if (pnk-15==0&&pnk+15==0&&pnk+45==1&&pnk+60==0){

if (pnk+15==0&&pnk+30==1)jsk+15= jsk+15+110 ;

if (pnk+15==1&&pnk+30==0)jsk+30= jsk+30+110 ;

} //上下

if (pnk-14==0&&pnk+14==0&&pnk+42==1&&pnk+56==0){

if (pnk+14==0&&pnk+28==1)jsk+14= jsk+14+110 ;

if (pnk+14==1&&pnk+28==0)jsk+28= jsk+28+110 ;

} //斜左

if (pnk-16==0&&pnk+16==0&&pnk+48==1&&pnk+64==0){

if (pnk+16==0&&pnk+32==1)jsk+16= jsk+16+110 ;

if (pnk+16==1&&pnk+32==0)jsk+32= jsk+32+110 ;

} //右斜

} //0 1 1010 0 1 0110

//********

} } //scan i , j 整个搜索过程

//禁手的基本设置就这样

//长连禁手设置:在判胜负函数 detect ( ) 时

// 黑棋超过五连即判黑负,白棋胜。

//**********

cs.SetTextSize (16);

cs.SetTextStyle (0);

cs.SetFillMode (1);//0不填色,1填色

for (i=1;i<=225;i++){ //test restrict_move

if (jsi !=0) { //Mark it 标记禁手点

s=intToString ( jsi) ;

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

//更正:冲四加活三不是禁手!! 四加 110分

if (jsi>110&&jsi!=210){

cs.SetColor (255,180,0,180) ;

cs.DrawCircle (dx,dy,5) ; } //draw mark

} }

cs.Update ( ) ;

}//restrict_move ( )

图例:

在下拉菜单设置禁手

上图E 9, G 10 ,H 6

此三点位就是冲四活三必杀点

全局变量加:

int js225; //禁手设置 遍历棋盘点位

int jsset ; //0=on 有禁手,1=off 无禁手,下拉菜单

在白棋下子后加禁手判断:

white_do ( ){ //白棋下子

............

testAIq ( ); //AI 算法测试 ****

//scan restricted move and draw mark

if (jsset==0) restrict_move ( ) ; //禁手设置标记

}//white_do ( )

在判胜负的function detect ( ) 中加代码,

如触禁手判白棋胜

detect ( ) {

...... ......

//*****************************

if (jsset==0&&pnn==1&&jsn>110&&jsi!=210){

//禁手,判白棋胜

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; }

...... ......

}//detect ( )

其他功能设置感兴趣的朋友可参阅我本站其他博文,

需要游戏程序源码可联系我:micelu@126.com

//**End**

相关推荐
nujnewnehc1 天前
不会 py, 用 ai 写了个游戏辅助的感受
人工智能·游戏
jump_jump2 天前
为了重玩金庸群侠传,我研究了一下 Ruffle 怎么复活 Flash
游戏·rust·github
XIAOHEZIcode3 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
Aloys_Code4 天前
逆向一个被遗忘的DVD游戏格式:从DES加密到Rust模拟器
游戏·模拟器·retroarch·复古游戏·native32·sunplus·赤刃·钢铁风暴
金銀銅鐵4 天前
用 Python 实现 Take-Away 游戏
python·游戏
金銀銅鐵5 天前
用 Pygame 实现 15 puzzle
python·数学·游戏
LDR0066 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
SM177152118387 天前
NSK紧凑型FA系列丝杠技术详解
经验分享·规格说明书
Luminous.7 天前
C语言--day30
c语言·开发语言
玖玥拾7 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器