65.9K
CodeProject 正在变化。 阅读更多。
Home

3D 国际象棋(opengl)与人工智能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (12投票s)

2010 年 5 月 18 日

CPOL

3分钟阅读

viewsIcon

64457

downloadIcon

7382

一款可以由计算机和人类对弈的 3D 国际象棋游戏

引言

国际象棋是一种两人对弈的策略游戏,玩家轮流尝试将对方的王将死。每回合,玩家必须移动自己的一个棋子。每个棋子都有特定的移动方式,在64个黑白相间的棋盘格上移动。有关游戏规则的更多信息,请访问维基百科上的国际象棋条目。

背景

这个国际象棋游戏主要分为5个阶段开发

  1. 棋盘表示:由于编译器是32位,使用两个无符号int数字来表示棋盘。通过重载所有必需的运算符,创建了一个具有64位功能的类。
  2. 移动生成:所有不同棋子的可能移动都预先计算并存储在位棋盘中。由于只需要移位操作,计算变得容易。
  3. 评估函数:为棋子分配了点数,并为保护和攻击对方棋子分配了点数。为将死和将军国王分配了点数。
  4. 深度搜索:添加评估函数还不够,需要深度思考,实现了Minmax树。
  5. 残局:阻止导致王被将死的可能移动,并实现了将死条件,以便游戏结束。

Using the Code

该类定义了一个位棋盘,包含两个U32数字。这构成了一个64位的棋盘。所有位运算符都已重载,以便与两个32位数字一起使用。

class U64 
{ 
public: 
    U32 l, h;
    U64()
    {  
        l = 0x0; 
        h = 0x0; 
    }

    U64 operator |(U64); 
    U64 operator &(U64); 
    U64 operator ^(U64); 
    U64 operator ~(void); 
    U64 operator <<(int a); 
    U64 operator >>(int b); 
    void operator =(int sq); 
    void operator |=(int sq); 
 
    void display(); 
    int getAndClearLSB(); 

    bool check(){ 
        if( !( l | h) ) 
            return false; 
        else 
            return true; 
    }  
};

定义各种棋子位棋盘的类还定义了预先计算和存储的各种棋盘,例如可能的移动。构造函数声明了各种棋子的位棋盘的初始状态。

class CBoard {

public:   

    int side; 
    U64 Pieces[2][7]; 
    U64 Knightsmove[64]; 
    U64 Kingmove[64]; 
    U64 right_board[64]; 
    U64 left_board[64]; 
    U64 up_board[64]; 
    U64 down_board[64]; 
    U64 _45deg_board[64]; 
    U64 _225deg_board[64]; 
    U64 _135deg_board[64]; 
    U64 _315deg_board[64]; 
    U64 Pawnsmove[64][2]; 
    U64 Pawnsdoublemove[64][2]; 
    U64 Pawnsattackmove[64][2]; 
    U64 fullboard[2]; 
    U64 occupiedboard[2]; 
    U64 unoccupiedboard[2]; 
    U64 enemyboard[2]; 
    U64 notfriendlyboard[2]; 
    U64 friendlyboard[2]; 
    U64 attackboard[2]; 
    U64 doubledpawn[2]; 
    U64 isolatedpawn[2]; 
    U64 backwardpawn[2]; 
    U64 kngchk[7]; 

    void validmove();
    CBoard(); 
}bitboard;

我想演示使用位移操作生成车可能的移动方式。首先,预先计算以下位棋盘

  • right_board[64] - 对于每个格子,将格子右侧的所有格子设置为1的位棋盘
  • left_board[64] - 对于每个格子,将格子左侧的所有格子设置为1的位棋盘
  • up_board[64] - 对于每个格子,将格子上方的所有格子设置为1的位棋盘
  • down_board[64] - 对于每个格子,将格子下方的所有格子设置为1的位棋盘

要计算车可以移动到的右侧格子,我们执行以下操作

//right_moves = right_board[sq] AND occupiedboard

我们这样做是因为第一个棋子会阻止车向右移动。由于第一个棋子会阻止车,我们需要填充棋子右侧的所有格子(<< 1表示左移一位,< 2 表示左移2位,等等)

right_moves = (right_moves<<1) OR (right_moves<<2) OR (right_moves<<3) OR 
(right_moves<<4) OR (right_moves<<5) OR (right_moves<<6)

为了消除溢出到下一行的位,我们使用AND运算符将结果与right_board相与。

right_moves = right_moves AND right_board

这是车不能移动到的所有右侧格子。要获得车可以移动到的格子,我们对棋盘与right_board进行异或运算OR

right_moves = right_moves XOR right_board

您会注意到,这些是车可以移动到的右侧的所有格子。但是,如果F3上的兵是一个黑色的兵呢?那么我们不能吃掉它,因此我们需要进行最后一步操作:right_moves = right moves AND enemy_and_empty_squares

inline U64 genRookAttackBoard(int sq)
{     
    bool side=bitboard.side;
    U64 leftboard = (bitboard.occupiedboard[side] & bitboard.left_board[sq]); 
    leftboard = (leftboard>>1)|(leftboard>>2)|(leftboard>>3)|
	(leftboard>>4)|(leftboard>>5)|(leftboard>>6); 
    leftboard = (leftboard & bitboard.left_board[sq])^bitboard.left_board[sq]; 
 
    U64 rightboard = (bitboard.occupiedboard[side] & bitboard.right_board[sq]); 
    rightboard = (rightboard<<1)|(rightboard<<2)|(rightboard<<3)|
                 (rightboard<<4)|(rightboard<<5)|(rightboard<<6); 
    rightboard = (rightboard & bitboard.right_board[sq]) ^ bitboard.right_board[sq]; 
 
    U64 upboard = (bitboard.occupiedboard[side] & bitboard.up_board[sq]); 
    upboard = (upboard<<8)|(upboard<<16)|(upboard<<24)|
              (upboard<<32)|(upboard<<40)|(upboard<<48); 
    upboard = (upboard & bitboard.up_board[sq]) ^ bitboard.up_board[sq]; 

    U64 downboard = (bitboard.occupiedboard[side] & bitboard.down_board[sq]); 
    downboard = (downboard>>8)|(downboard>>16)|(downboard>>24)|
                (downboard>>32)|(downboard>>40)|(downboard>>48); 
    downboard = (downboard & bitboard.down_board[sq]) ^ bitboard.down_board[sq]; 

    return (leftboard | rightboard | upboard | downboard) & 
	bitboard.notfriendlyboard[side]; 
}
© . All rights reserved.