• 全部
  • 问答

请教如何设计五子棋的人工智能?

zzhouj 2004-07-15 11:08:43
最近在移植和改进一个五子棋游戏,有关五子棋的人工智能,欢迎大家谈谈自己的思路。特别是喜欢玩和编写过五子棋游戏的朋友。
...全文
225 点赞 收藏 10
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
thirdapple 2004-07-19

极大极小+alpha-beta剪枝
回复
名牌大灰狼 2004-07-19
sos http://community.csdn.net/Expert/topic/3188/3188484.xml?temp=.419552
回复
zzhouj 2004-07-19
重新整理一下格式:

/**
* Find best position for next step of computer player, and return the
* step score.
*/
static SINT16 FCMainFindBestPosition(SINT8 * s8SelPosX, SINT8 * s8SelPosY,
UINT8 u8ComputerPlayer,
UINT8 u8PeoplePlayer)
{
int i; /* for loop to count 5 power of u8LimitNum */

UINT8 u8PosX, u8PosY; /* for loop hole chess board */

UINT8 u8LimitNum = 0; /* for loop from five chess lint to two */
/* chess lint */

SINT16 s16Temp = 1; /* power value of 5 power of u8LimitNum */

SINT32 s32NumPosSel = 0; /* for count power of every position which */
/* is FC_NO_PALYER */

SINT32 s32MaxPosSel = 0; /* record max power of all position */

SINT32 s32Temp = 0; /* power value of */
/*FCMainFindConnectLinesByPoint() */

SINT16 s16StepScore = 0; /* return of step score */

/* initial input parameter */
*s8SelPosX = -1;
*s8SelPosY = -1;

/* from five chess lint to two chess lint */
for (u8LimitNum = 5; u8LimitNum >= 2; u8LimitNum--) {
/* loop hole chess board */
for (u8PosX = 0; u8PosX < FC_BOARD_WIDTH; u8PosX++) {
for (u8PosY = 0; u8PosY < FC_BOARD_HEIGHT; u8PosY++) {
/* only count position which is FC_NO_PALYER */
if (nFiveChessBoard[u8PosX][u8PosY] == FC_NO_PALYER) {
/* count 5 power of u8LimitNum */
s16Temp = 1;
for (i = 0; i < 5; i++) {
s16Temp = s16Temp * u8LimitNum;
}

/* first count computer player's power value */
s32Temp =
FCMainFindConnectLinesByPoint(u8PosX, u8PosY,
(UINT8)
nComputerPlayer,
u8LimitNum);
/* count power of the position */
s32NumPosSel =
(s32Temp * s16Temp + 1) * 10 +
FCMainPositionPower(u8PosX, u8PosY);
if (s32NumPosSel > s32MaxPosSel) {
s32MaxPosSel = s32NumPosSel;
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
} else if (s32NumPosSel == s32MaxPosSel) {
if ((FCPalRand() & 0x01) == 1) {
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
}
}

/* the count people player's power value */
s32Temp =
FCMainFindConnectLinesByPoint(u8PosX, u8PosY,
(UINT8)
nPeoplePlayer,
u8LimitNum);
s32NumPosSel =
(s32Temp * s16Temp) * 10 +
FCMainPositionPower(u8PosX, u8PosY);
if (s32NumPosSel == s32MaxPosSel) {
if ((FCPalRand() & 0x01) == 1) {
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
}
} else if (s32NumPosSel > s32MaxPosSel) {
s32MaxPosSel = s32NumPosSel;
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
}
} /* if */
} /* for */
} /* for */
} /* for */

s16StepScore = (SINT16) s32MaxPosSel;
FCPalSprintf(szGameLog, "(x, y) := (%d, %d)", *s8SelPosX, *s8SelPosY);
FCPalLogStr(szGameLog);
return s16StepScore;
}
回复
zzhouj 2004-07-19
各位非常感谢,但是我所面临的环境是一个资源受限的嵌入式设备,其task的堆栈很小可能只有1K,不能使用深度递归算法。不知下面的算法是否满足要求:

/**
* Find best position for next step of computer player, and return the step score.
*/
static SINT16 FCMainFindBestPosition(SINT8 * s8SelPosX, SINT8 * s8SelPosY, UINT8 u8ComputerPlayer, UINT8 u8PeoplePlayer)
{
int i; /* for loop to count 5 power of u8LimitNum */
UINT8 u8PosX, u8PosY; /* for loop hole chess board */
UINT8 u8LimitNum = 0; /* for loop from five chess lint to two chess lint */
SINT16 s16Temp = 1; /* power value of 5 power of u8LimitNum */

SINT32 s32NumPosSel = 0; /* for count power of every position which is FC_NO_PALYER */
SINT32 s32MaxPosSel = 0; /* record max power of all position */
SINT32 s32Temp = 0; /* power value of FCMainFindConnectLinesByPoint() */

SINT16 s16StepScore = 0; /* return of step score */

/* initial input parameter */
*s8SelPosX = -1;
*s8SelPosY = -1;

/* from five chess lint to two chess lint */
for (u8LimitNum = 5; u8LimitNum >= 2; u8LimitNum--) {
/* loop hole chess board */
for (u8PosX = 0; u8PosX < FC_BOARD_WIDTH; u8PosX++) {
for (u8PosY = 0; u8PosY < FC_BOARD_HEIGHT; u8PosY++) {
/* only count position which is FC_NO_PALYER */
if (nFiveChessBoard[u8PosX][u8PosY] == FC_NO_PALYER) {
/* count 5 power of u8LimitNum */
s16Temp = 1;
for (i = 0; i < 5; i++) {
s16Temp = s16Temp * u8LimitNum;
}

/* first count computer player's power value */
s32Temp = FCMainFindConnectLinesByPoint(u8PosX, u8PosY, (UINT8) nComputerPlayer, u8LimitNum);
/* count power of the position */
s32NumPosSel = (s32Temp * s16Temp + 1) * 10 + FCMainPositionPower(u8PosX, u8PosY);
if (s32NumPosSel > s32MaxPosSel) {
s32MaxPosSel = s32NumPosSel;
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
} else if (s32NumPosSel == s32MaxPosSel) {
if ((FCPalRand() & 0x01) == 1) {
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
}
}

/* the count people player's power value */
s32Temp = FCMainFindConnectLinesByPoint(u8PosX, u8PosY, (UINT8) nPeoplePlayer, u8LimitNum);
s32NumPosSel = (s32Temp * s16Temp) * 10 + FCMainPositionPower(u8PosX, u8PosY);
if (s32NumPosSel == s32MaxPosSel) {
if ((FCPalRand() & 0x01) == 1) {
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
}
} else if (s32NumPosSel > s32MaxPosSel) {
s32MaxPosSel = s32NumPosSel;
*s8SelPosX = u8PosX;
*s8SelPosY = u8PosY;
}
} /* if */
} /* for */
} /* for */
} /* for */

s16StepScore = (SINT16) s32MaxPosSel;
FCPalSprintf(szGameLog, "(x, y) := (%d, %d)", *s8SelPosX, *s8SelPosY);
FCPalLogStr(szGameLog);
return s16StepScore;
}

回复
shines77 2004-07-17
上面int alpha_bate(board, color, alpha, beta)
应该为 int alpha_beta(board, depth, color, alpha, beta)

下面的是int alpha_beta(board, depth, color, beta, alpha) // alpha, beta窗口必须交换

必须加入搜索深度,才知道什么时候停,但搜索GetCaptureMoves的时候例外,一般是一方GetCaptureMoves() = 0 就停止搜索,如果你实在怕搜索得太深,也可以强制加一个深度限制
回复
shines77 2004-07-17
没种棋都不一样,中国象棋麻烦点,因为数据结构无法利用bitboard,国际象棋是8x8的格子,稍微好处理一点,不同的棋类游戏不同的只是规则和评估函数,搜索和剪枝基本都是通用的,不过象棋的规则导致逻辑上稍微复杂一点,比如不能连续3次将军,20回合双方不吃子算和棋

象棋程序中常用静态搜索(就是假设一方不走棋,一方连续走),我想五子棋也有必要使用,象棋中有个特别的就是,搜索到最后一步,把可以对子(就是可以吃对方的棋)的棋逐一编历搜索(中间也有剪枝),这个搜索往往是不定长的,所以用了会有点慢,但对局面评估有相当大的帮助,大致结构像下面:

int alpha_bate(board, color, alpha, beta)
{
......
nMove = GetCaptureMoves(board, color, moveLists);
for(int i=0; i<nMove; i++)
{
......
alpha_bate(board, 1-color, alpha, beta);
}
......
return value;
}

其实很多算法都可以从国际象棋的代码里学到,网上国际象棋的资料比较多一些,但多数都是英文的,可以自己搜搜,我很久不看也不知道推荐什么了,基本的alpha-beta剪枝是要会的
回复
chenzhengzhanglu 2004-07-17
楼上的象棋 应该比较难吧?
回复
shines77 2004-07-17
应该是alpha-beta剪枝,和局面评估函数(重点就在这,影响棋力)

剪枝可以使用Nega-Sount(常用),还有MTD(f), SS*等等Alpha-Beta的变种

哈西表也是一个较关键的应用,我没有写过五子棋的,只写过黑白棋和中国象棋,黑白棋有可以比一般剪枝搜索得更深的MPC算法(要求要有比较稳定准确的局面评估函数)

AI的关键就在评估函数这快,所以没有NowCan(((((( ★ ))))))想象的那么难,掌握了剪枝以后就是评估函数的设计了
回复
NowCan 2004-07-16
我喜欢玩五子棋,但算法水平还达不到编写一个AI。
回复
chenzhengzhanglu 2004-07-16
我觉得
首先对棋子的个种情况确定好分数
递归分析时 用哈希表记录已经分析过的局面 避免重复分析 缩短时间
递归分析的最后一层要处理好

呵呵 个人直觉!
回复
相关推荐
发帖
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
帖子事件
创建了帖子
2004-07-15 11:08
社区公告
暂无公告