📄 decision.cpp
字号:
#include "decision.h"
#include "analysechess.h"
/* 功能:空格位置填子进行预测,空格棋子附近两个格内有棋子才是合法字节点(10个子内,合法落子点为1个空格范围内) */
/* 传入参数 */
void Decision::BlankFilter( char (*realgrid)[15], char (*legalblank)[15] )
{
//计算当前棋子总数
int chessnum = 0;
for( int i=0; i<15; i++)
{
for( int j=0; j<15; j++)
{
if ( realgrid[i][j] == 'W' || realgrid[i][j] == 'B' )
{
chessnum++;
}
}
}
//行和列遍历计算的范围,初始置为-2、+2,表示不在棋盘边缘时,计算方圆两个格有没有棋子
int row1, row2, line1, line2;
//遍历整个棋盘空格
for( int i=0; i<15; i++)
{
for( int j=0; j<15; j++)
{
//每个空格处搜索方面两个格内有没有已下的棋子
if( realgrid[i][j] != 'W' && realgrid[i][j] != 'B')
{
//判断该空格在棋盘中的位置
//计算方圆1个格有没有棋子,(10个子内,合法落子点为1个空格范围内)
if( chessnum <= 10 )
{
//判断行
switch( i ){
case 0 :
{ row1 = 0; row2 = 1;break;} //节点在第0行(1)
case 14 :
{ row1 = -1; row2 = 0;break;} //节点在第14行(15)
default:
{ row1 = -1; row2 = 1;}
}
//判断列
switch( j ){
case 0 :
{ line1 = 0; line2 = 1;break;} //节点在第0列(1)
case 14 :
{ line1 = -1; line2 = 0;break;} //节点在第14列(15)
default:
{ line1 = -1; line2 = 1;break;}
}
}
else
{
//判断行
switch( i ){
case 0 :
{ row1 = 0; row2 = 2;break;} //节点在第0行(1)
case 1 :
{ row1 = -1; row2 = 2;break;} //节点在第1行(2)
case 13 :
{ row1 = -2; row2 = 1;break;} //节点在第13行(14)
case 14 :
{ row1 = -2; row2 = 0;break;} //节点在第14行(15)
default:
{ row1 = -2; row2 = 2;}
}
//判断列
switch( j ){
case 0 :
{ line1 = 0; line2 = 2;break;} //节点在第0列(1)
case 1 :
{ line1 = -1; line2 = 2;break;} //节点在第1列(2)
case 13 :
{ line1 = -2; line2 = 1;break;} //节点在第13列(14)
case 14 :
{ line1 = -2; line2 = 0;break;} //节点在第14列(15)
default:
{ line1 = -2; line2 = 2;break;}
}
}
//根据行和列遍历计算的范围row1、row2、line1、line2计算合法空格
int countchess = 0; //方圆两个格内棋子总数
int countblank = 0; //方圆两个格内棋子总数
for( int m=row1; m<=row2; m++)
{
for( int n=line1; n<=line2; n++)
{
if( realgrid[i+m][j+n] == 'W' || realgrid[i+m][j+n] == 'B')
{
countchess++;
}
else
{
countblank++;
}
}
}
//根据方圆两个格内棋子总数(最小为1,节点自身),确定是否为有效空格
if( countchess > 0 && countblank > 0 )
{
legalblank[i][j] = 'T';
}
}
}
}
}
//自己进攻的机会,权重加
//计算有没有三三,冲四,三四
/* 其实判断棋子胜利用的是递归,这里再用搜索的方法有点重复,但是考虑到统一查找方法的复杂度,暂时用两种方法来实现 */
/* 两种方法也不完全一样,分开算更容易理解 */
/* 方法1:递归。判断胜利时只找同色棋子,其两个相对的方向上结果相加 */
/* 方法2:数组循环。判断是否有连,这个连可以间隔一个空格,而且不能两个方向上递归相加,因为空格处没有对象,递归中断 */
/* 经分析,用两种方法比较好,方法2用1、0、-1表示三种棋,好计算 */
float Decision::MyChance( char (*realgrid)[15], const int &m, const int &n )
{
//把棋盘棋子放到数字数组中,以便于搜索
int numbergrid[15][15];
int i,j;
for( i=0; i<15; i++ )
{
for( j=0; j<15; j++ )
{
if( realgrid[i][j] == 'W')
{
numbergrid[i][j] = 1;
}
else if( realgrid[i][j] == 'B')
{
numbergrid[i][j] = -1;
}
else
{
numbergrid[i][j] = 0;
}
}
}
//四个大方向,搜索棋子,统计有所少三三,四四,以确定权值
int five = 0; float a = 100;
int four = 0; float b = 40;
int chongfour = 0; float c = 6.5;
int three = 0; float d = 5;
int chongthree = 0; float e = 0.6;
int two = 0; float f = 1;
int bantwo = 0; float g = 0.8;
int chongtwo = 0; float h = 0.2;
int dire;
for( dire=0; dire<4; dire++ )
{
//判断5连,如果是5连跳出循环,不再判断4连、3连、2连
if( AnalyseChess::Five( numbergrid, m, n, dire ) == 1 )
{
five++;
continue;
}
//判断4连
int checkfour = AnalyseChess::Four( numbergrid, m, n, dire );
if( checkfour == 2 )
{
four++;
continue;
}
else if( checkfour == 1 )
{
chongfour++;
continue;
}
//判断3连
int checkthree = AnalyseChess::Three( numbergrid, m, n, dire );
if( checkthree == 2 )
{
three++;
continue;
}
else if( checkthree == 1 )
{
chongthree++;
continue;
}
//判断2连
int checktwo = AnalyseChess::Two( numbergrid, m, n, dire );
if( checktwo == 3 )
{
two++;
continue;
}
else if( checktwo == 2 )
{
bantwo++;
continue;
}
else if( checktwo == 1 )
{
chongtwo++;
continue;
}
}
//方法1,自己五连 (可堵可空)
//方法2,自己冲四 (可隔一空)(有堵,有足够空格(可暂忽略))
//方法3,自己三连 (可隔一空)(无堵,有足够空格(可暂忽略))
//方法4,自己二连 (可隔一空)(无堵,有足够空格(可暂忽略))
//方法5,自己冲三 (可隔一空)(有堵,至少有2个空格)
//方法6,自己冲二 (可隔一空)(有堵,至少有3个空格)
float nodeweight = five * a + four * b + chongfour * c + three * d + chongthree * e + two * f + bantwo * g + chongtwo * h;
//权重调整
if( chongfour >= 2 )
{
nodeweight = nodeweight *1.5; //双冲四,权重增加
}
if( chongfour >= 1 && three >=1 )
{
nodeweight = nodeweight *1.5; //冲四活三,权重增加
}
if( three >= 2 )
{
nodeweight = nodeweight *1.5; //双活三,权重增加
}
return nodeweight;
}
//对手进攻的机会,权重减,同上
//realgrid不一样,点grid[m][n]处棋子置成相反色了,即把自己的子当成对方的棋子计算棋势和权值
float Decision::RivalChance( char (*realgrid)[15], const int &m, const int &n )
{
//把棋盘棋子放到数字数组中,以便于搜索
int numbergrid[15][15];
int i,j;
for( i=0; i<15; i++ )
{
for( j=0; j<15; j++ )
{
if( realgrid[i][j] == 'W')
{
numbergrid[i][j] = 1;
}
else if( realgrid[i][j] == 'B')
{
numbergrid[i][j] = -1;
}
else
{
numbergrid[i][j] = 0;
}
}
}
//四个大方向,搜索棋子,统计有所少三三,四四,以确定权值
int five = 0; float a = 69; //权值比对方的一半少1,因为五子棋优先进攻
int four = 0; float b = 9; //权值比对方的一半少0.1,因为五子棋优先进攻,这样也能防止权值相同不好处理
int chongfour = 0; float c = 3;
int three = 0; float d = 1.9;
int chongthree = 0; float e = 0.2;
int two = 0; float f = 0.4;
int bantwo = 0; float g = 0.3;
int chongtwo = 0; float h = 0.05;
int dire;
for( dire=0; dire<4; dire++ )
{
//判断5连,如果是5连跳出循环,不再判断4连、3连、2连
if( AnalyseChess::Five( numbergrid, m, n, dire ) == 1 )
{
five++;
continue;
}
//判断4连
int checkfour = AnalyseChess::Four( numbergrid, m, n, dire );
if( checkfour == 2 )
{
four++;
continue;
}
else if( checkfour == 1 )
{
chongfour++;
continue;
}
//判断3连
int checkthree = AnalyseChess::Three( numbergrid, m, n, dire );
if( checkthree == 2 )
{
three++;
continue;
}
else if( checkthree == 1 )
{
chongthree++;
continue;
}
//判断2连
int checktwo = AnalyseChess::Two( numbergrid, m, n, dire );
if( checktwo == 3 )
{
two++;
continue;
}
else if( checktwo == 2 )
{
bantwo++;
continue;
}
else if( checktwo == 1 )
{
chongtwo++;
continue;
}
}
//方法1,自己五连 (可堵可空)
//方法2,自己冲四 (可隔一空)(有堵,有足够空格(可暂忽略))
//方法3,自己三连 (可隔一空)(无堵,有足够空格(可暂忽略))
//方法4,自己二连 (可隔一空)(无堵,有足够空格(可暂忽略))
//方法5,自己冲三 (可隔一空)(有堵,至少有2个空格)
//方法6,自己冲二 (可隔一空)(有堵,至少有3个空格)
float nodeweight = five * a + four * b + chongfour * c + three * d + chongthree * e + two * f + bantwo * g + chongtwo * h;
//权重调整
if( chongfour >= 2 )
{
nodeweight = nodeweight *1.5; //双冲四,权重增加
}
if( chongfour >= 1 && three >=1 )
{
nodeweight = nodeweight *1.5; //冲四活三,权重增加
}
if( three >= 2 )
{
nodeweight = nodeweight *1.5; //双活三,权重增加
}
return nodeweight;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -