// 生成文本棋盘(红子用()表示,黑子用[]表示) void BoardText(char *szBoard, const PositionStruct &pos, bool bAnsi) { char *lpBoard; int i, j, pc; lpBoard = szBoard; if (bAnsi) { lpBoard += sprintf(lpBoard, "\33[0m"); } for (i = 0; i < 19; i ++) { if (i % 2 == 0) { for (j = FILE_LEFT; j <= FILE_RIGHT; j ++) { pc = pos.ucpcSquares[COORD_XY(j, i / 2 + RANK_TOP)]; if ((pc & SIDE_TAG(0)) != 0) { lpBoard += sprintf(lpBoard, bAnsi ? "(\33[1;31m%.2s\33[0m)" : "(%.2s)", (const char *) &lpcwPiece2Word[0][PIECE_TYPE(pc)]); } else if ((pc & SIDE_TAG(1)) != 0) { lpBoard += sprintf(lpBoard, bAnsi ? "[\33[1;32m%.2s\33[0m]" : "[%.2s]", (const char *) &lpcwPiece2Word[1][PIECE_TYPE(pc)]); } else { lpBoard += sprintf(lpBoard, "%.4s", lpcszBoardStr[i] + (j - FILE_LEFT) * 4); } } lpBoard += sprintf(lpBoard, "\r\n"); } else { lpBoard += sprintf(lpBoard, "%s\r\n", lpcszBoardStr[i]); } } }
// 入口过程 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int i; MSG msg; WNDCLASSEX wce; // 初始化全局变量 Xqwl.hInst = hInstance; Xqwl.bFlipped = FALSE; Startup(); // 装入图片 Xqwl.bmpBoard = LoadResBmp(IDB_BOARD); Xqwl.bmpSelected = LoadResBmp(IDB_SELECTED); for (i = PIECE_KING; i <= PIECE_PAWN; i ++) { Xqwl.bmpPieces[SIDE_TAG(0) + i] = LoadResBmp(IDB_RK + i); Xqwl.bmpPieces[SIDE_TAG(1) + i] = LoadResBmp(IDB_BK + i); } // 设置窗口 wce.cbSize = sizeof(WNDCLASSEX); wce.style = 0; wce.lpfnWndProc = (WNDPROC) WndProc; wce.cbClsExtra = wce.cbWndExtra = 0; wce.hInstance = hInstance; wce.hIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, LR_SHARED); wce.hCursor = (HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); wce.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); wce.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU); wce.lpszClassName = "XQWLIGHT"; wce.hIconSm = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_SHARED); RegisterClassEx(&wce); // 打开窗口 Xqwl.hWnd = CreateWindow("XQWLIGHT", "象棋小巫师", WINDOW_STYLES, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (Xqwl.hWnd == NULL) { return 0; } ShowWindow(Xqwl.hWnd, nCmdShow); UpdateWindow(Xqwl.hWnd); // 接收消息 while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }
// 点击格子事件处理 static void ClickSquare(int sq) { int pc; Xqwl.hdc = GetDC(Xqwl.hWnd); Xqwl.hdcTmp = CreateCompatibleDC(Xqwl.hdc); sq = Xqwl.bFlipped ? SQUARE_FLIP(sq) : sq; pc = pos.ucpcSquares[sq]; if ((pc & SIDE_TAG(pos.sdPlayer)) != 0) { // 如果点击自己的子,那么直接选中该子 if (Xqwl.sqSelected != 0) { DrawSquare(Xqwl.sqSelected); } Xqwl.sqSelected = sq; DrawSquare(sq, DRAW_SELECTED); if (Xqwl.mvLast != 0) { DrawSquare(SRC(Xqwl.mvLast)); DrawSquare(DST(Xqwl.mvLast)); } PlayResWav(IDR_CLICK); // 播放点击的声音 } else if (Xqwl.sqSelected != 0) { // 如果点击的不是自己的子,但有子选中了(一定是自己的子),那么走这个子 Xqwl.mvLast = MOVE(Xqwl.sqSelected, sq); pos.MakeMove(Xqwl.mvLast); DrawSquare(Xqwl.sqSelected, DRAW_SELECTED); DrawSquare(sq, DRAW_SELECTED); Xqwl.sqSelected = 0; PlayResWav(pc == 0 ? IDR_MOVE : IDR_CAPTURE); // 播放走子或吃子的声音 } DeleteDC(Xqwl.hdcTmp); ReleaseDC(Xqwl.hWnd, Xqwl.hdc); }
int AdvisorShape(const PositionStruct *lppos) { int pcCannon, pcRook, sq, sqAdv1, sqAdv2, x, y, nShape; int vlWhitePenalty, vlBlackPenalty; SlideMaskStruct *lpsms; vlWhitePenalty = vlBlackPenalty = 0; if ((lppos->wBitPiece[0] & ADVISOR_BITPIECE) == ADVISOR_BITPIECE) { if (lppos->ucsqPieces[SIDE_TAG(0) + KING_FROM] == 0xc7) { sqAdv1 = lppos->ucsqPieces[SIDE_TAG(0) + ADVISOR_FROM]; sqAdv2 = lppos->ucsqPieces[SIDE_TAG(0) + ADVISOR_TO]; if (false) { } else if (sqAdv1 == 0xc6) { // 红方一个仕在左侧底线 nShape = (sqAdv2 == 0xc8 ? SHAPE_CENTER : sqAdv2 == 0xb7 ? SHAPE_LEFT : SHAPE_NONE); } else if (sqAdv1 == 0xc8) { // 红方一个仕在右侧底线 nShape = (sqAdv2 == 0xc6 ? SHAPE_CENTER : sqAdv2 == 0xb7 ? SHAPE_RIGHT : SHAPE_NONE); } else if (sqAdv1 == 0xb7) { // 红方一个仕在花心 nShape = (sqAdv2 == 0xc6 ? SHAPE_LEFT : sqAdv2 == 0xc8 ? SHAPE_RIGHT : SHAPE_NONE); } else { nShape = SHAPE_NONE; } switch (nShape) { case SHAPE_NONE: break; case SHAPE_CENTER: for (pcCannon = SIDE_TAG(1) + CANNON_FROM; pcCannon <= SIDE_TAG(1) + CANNON_TO; pcCannon ++) { sq = lppos->ucsqPieces[pcCannon]; if (sq != 0) { x = FILE_X(sq); if (x == FILE_CENTER) { y = RANK_Y(sq); lpsms = lppos->FileMaskPtr(x, y); if ((lpsms->wRookCap & WHITE_KING_BITFILE) != 0) { // 计算空头炮的威胁 vlWhitePenalty += PreEvalEx.vlHollowThreat[RANK_FLIP(y)]; } else if ((lpsms->wSuperCap & WHITE_KING_BITFILE) != 0 && (lppos->ucpcSquares[0xb7] == 21 || lppos->ucpcSquares[0xb7] == 22)) { // 计算炮镇窝心马的威胁 vlWhitePenalty += PreEvalEx.vlCentralThreat[RANK_FLIP(y)]; } } } } break; case SHAPE_LEFT: case SHAPE_RIGHT: for (pcCannon = SIDE_TAG(1) + CANNON_FROM; pcCannon <= SIDE_TAG(1) + CANNON_TO; pcCannon ++) { sq = lppos->ucsqPieces[pcCannon]; if (sq != 0) { x = FILE_X(sq); y = RANK_Y(sq); if (x == FILE_CENTER) { if ((lppos->FileMaskPtr(x, y)->wSuperCap & WHITE_KING_BITFILE) != 0) { // 计算一般中炮的威胁,帅(将)门被对方控制的还有额外罚分 vlWhitePenalty += (PreEvalEx.vlCentralThreat[RANK_FLIP(y)] >> 2) + (lppos->Protected(1, nShape == SHAPE_LEFT ? 0xc8 : 0xc6) ? 20 : 0); // 如果车在底线保护帅(将),则给予更大的罚分! for (pcRook = SIDE_TAG(0) + ROOK_FROM; pcRook <= SIDE_TAG(0) + ROOK_TO; pcRook ++) { sq = lppos->ucsqPieces[pcRook]; if (sq != 0) { y = RANK_Y(sq); if (y == RANK_BOTTOM) { x = FILE_X(sq); if ((lppos->RankMaskPtr(x, y)->wRookCap & KING_BITRANK) != 0) { vlWhitePenalty += 80; } } } } } } else if (y == RANK_BOTTOM) { if ((lppos->RankMaskPtr(x, y)->wRookCap & KING_BITRANK) != 0) { // 计算沉底炮的威胁 vlWhitePenalty += PreEvalEx.vlWhiteBottomThreat[x]; } } } }
BOOL _PositionStruct::Checked() const { int i, j, sqSrc, sqDst; int pcSelfSide, pcOppSide, pcDst, nDelta; pcSelfSide = SIDE_TAG(sdPlayer); pcOppSide = OPP_SIDE_TAG(sdPlayer); for (sqSrc = 0; sqSrc < 256; sqSrc ++) { if (ucpcSquares[sqSrc] != pcSelfSide + PIECE_KING) { continue; } if (ucpcSquares[SQUARE_FORWARD(sqSrc, sdPlayer)] == pcOppSide + PIECE_PAWN) { return TRUE; } for (nDelta = -1; nDelta <= 1; nDelta += 2) { if (ucpcSquares[sqSrc + nDelta] == pcOppSide + PIECE_PAWN) { return TRUE; } } for (i = 0; i < 4; i ++) { if (ucpcSquares[sqSrc + ccAdvisorDelta[i]] != 0) { continue; } for (j = 0; j < 2; j ++) { pcDst = ucpcSquares[sqSrc + ccKnightCheckDelta[i][j]]; if (pcDst == pcOppSide + PIECE_KNIGHT) { return TRUE; } } } for (i = 0; i < 4; i ++) { nDelta = ccKingDelta[i]; sqDst = sqSrc + nDelta; while (IN_BOARD(sqDst)) { pcDst = ucpcSquares[sqDst]; if (pcDst != 0) { if (pcDst == pcOppSide + PIECE_ROOK || pcDst == pcOppSide + PIECE_KING) { return TRUE; } break; } sqDst += nDelta; } sqDst += nDelta; while (IN_BOARD(sqDst)) { int pcDst = ucpcSquares[sqDst]; if (pcDst != 0) { if (pcDst == pcOppSide + PIECE_CANNON) { return TRUE; } break; } sqDst += nDelta; } } return FALSE; } return FALSE; }
BOOL _PositionStruct::LegalMove(int mv) const { int sqSrc, sqDst, sqPin; int pcSelfSide, pcSrc, pcDst, nDelta; sqSrc = SRC(mv); pcSrc = ucpcSquares[sqSrc]; pcSelfSide = SIDE_TAG(sdPlayer); if ((pcSrc & pcSelfSide) == 0) { return FALSE; } sqDst = DST(mv); pcDst = ucpcSquares[sqDst]; if ((pcDst & pcSelfSide) != 0) { return FALSE; } switch (pcSrc - pcSelfSide) { case PIECE_KING: return IN_FORT(sqDst) && KING_SPAN(sqSrc, sqDst); case PIECE_ADVISOR: return IN_FORT(sqDst) && ADVISOR_SPAN(sqSrc, sqDst); case PIECE_BISHOP: return SAME_HALF(sqSrc, sqDst) && BISHOP_SPAN(sqSrc, sqDst) && ucpcSquares[BISHOP_PIN(sqSrc, sqDst)] == 0; case PIECE_KNIGHT: sqPin = KNIGHT_PIN(sqSrc, sqDst); return sqPin != sqSrc && ucpcSquares[sqPin] == 0; case PIECE_ROOK: case PIECE_CANNON: if (SAME_RANK(sqSrc, sqDst)) { nDelta = (sqDst < sqSrc ? -1 : 1); } else if (SAME_FILE(sqSrc, sqDst)) { nDelta = (sqDst < sqSrc ? -16 : 16); } else { return FALSE; } sqPin = sqSrc + nDelta; while (sqPin != sqDst && ucpcSquares[sqPin] == 0) { sqPin += nDelta; } if (sqPin == sqDst) { return pcDst == 0 || pcSrc - pcSelfSide == PIECE_ROOK; } else if (pcDst != 0 && pcSrc - pcSelfSide == PIECE_CANNON) { sqPin += nDelta; while (sqPin != sqDst && ucpcSquares[sqPin] == 0) { sqPin += nDelta; } return sqPin == sqDst; } else { return FALSE; } case PIECE_PAWN: if (AWAY_HALF(sqDst, sdPlayer) && (sqDst == sqSrc - 1 || sqDst == sqSrc + 1)) { return TRUE; } return sqDst == SQUARE_FORWARD(sqSrc, sdPlayer); default: return FALSE; } }
int _PositionStruct::GenerateMovesFrom(int sqSrc, int *mvs, BOOL bCapture) const { int i, j, nGenMoves, nDelta, sqDst; int pcSelfSide, pcOppSide, pcSrc, pcDst; nGenMoves = 0; pcSelfSide = SIDE_TAG(sdPlayer); pcOppSide = OPP_SIDE_TAG(sdPlayer); if (sqSrc >= 0 && sqSrc < 256) { pcSrc = ucpcSquares[sqSrc]; if ((pcSrc & pcSelfSide) == 0) { return nGenMoves; } switch (pcSrc - pcSelfSide) { case PIECE_KING: for (i = 0; i < 4; i ++) { sqDst = sqSrc + ccKingDelta[i]; if (!IN_FORT(sqDst)) { continue; } pcDst = ucpcSquares[sqDst]; if (bCapture ? (pcDst & pcOppSide) != 0 : (pcDst & pcSelfSide) == 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } break; case PIECE_ADVISOR: for (i = 0; i < 4; i ++) { sqDst = sqSrc + ccAdvisorDelta[i]; if (!IN_FORT(sqDst)) { continue; } pcDst = ucpcSquares[sqDst]; if (bCapture ? (pcDst & pcOppSide) != 0 : (pcDst & pcSelfSide) == 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } break; case PIECE_BISHOP: for (i = 0; i < 4; i ++) { sqDst = sqSrc + ccAdvisorDelta[i]; if (!(IN_BOARD(sqDst) && HOME_HALF(sqDst, sdPlayer) && ucpcSquares[sqDst] == 0)) { continue; } sqDst += ccAdvisorDelta[i]; pcDst = ucpcSquares[sqDst]; if (bCapture ? (pcDst & pcOppSide) != 0 : (pcDst & pcSelfSide) == 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } break; case PIECE_KNIGHT: for (i = 0; i < 4; i ++) { sqDst = sqSrc + ccKingDelta[i]; if (ucpcSquares[sqDst] != 0) { continue; } for (j = 0; j < 2; j ++) { sqDst = sqSrc + ccKnightDelta[i][j]; if (!IN_BOARD(sqDst)) { continue; } pcDst = ucpcSquares[sqDst]; if (bCapture ? (pcDst & pcOppSide) != 0 : (pcDst & pcSelfSide) == 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } } break; case PIECE_ROOK: for (i = 0; i < 4; i ++) { nDelta = ccKingDelta[i]; sqDst = sqSrc + nDelta; while (IN_BOARD(sqDst)) { pcDst = ucpcSquares[sqDst]; if (pcDst == 0) { if (!bCapture) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } else { if ((pcDst & pcOppSide) != 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } break; } sqDst += nDelta; } } break; case PIECE_CANNON: for (i = 0; i < 4; i ++) { nDelta = ccKingDelta[i]; sqDst = sqSrc + nDelta; while (IN_BOARD(sqDst)) { pcDst = ucpcSquares[sqDst]; if (pcDst == 0) { if (!bCapture) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } else { break; } sqDst += nDelta; } sqDst += nDelta; while (IN_BOARD(sqDst)) { pcDst = ucpcSquares[sqDst]; if (pcDst != 0) { if ((pcDst & pcOppSide) != 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } break; } sqDst += nDelta; } } break; case PIECE_PAWN: sqDst = SQUARE_FORWARD(sqSrc, sdPlayer); if (IN_BOARD(sqDst)) { pcDst = ucpcSquares[sqDst]; if (bCapture ? (pcDst & pcOppSide) != 0 : (pcDst & pcSelfSide) == 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } if (AWAY_HALF(sqSrc, sdPlayer)) { for (nDelta = -1; nDelta <= 1; nDelta += 2) { sqDst = sqSrc + nDelta; if (IN_BOARD(sqDst)) { pcDst = ucpcSquares[sqDst]; if (bCapture ? (pcDst & pcOppSide) != 0 : (pcDst & pcSelfSide) == 0) { mvs[nGenMoves] = MOVE(sqSrc, sqDst); nGenMoves ++; } } } } break; } } return nGenMoves; }
// 获得某个棋子对于本方视角的纵线优先坐标,棋子编号从0到15 inline int FILESQ_SIDE_PIECE(const PositionStruct &pos, int nPieceNum) { int sq; sq = pos.ucsqPieces[SIDE_TAG(pos.sdPlayer) + nPieceNum]; return (sq == 0 ? -1 : pos.sdPlayer == 0 ? SQUARE_FILESQ(sq) : SQUARE_FILESQ(SQUARE_FLIP(sq))); }
// “捉”的检测 int PositionStruct::ChasedBy(int mv) const { int i, nSideTag, pcMoved, pcCaptured; int sqSrc, sqDst, x, y; uint8_t *lpucsqDst, *lpucsqPin; SlideMoveStruct *lpsmv; sqSrc = DST(mv); pcMoved = this->ucpcSquares[sqSrc]; nSideTag = SIDE_TAG(this->sdPlayer); __ASSERT_SQUARE(sqSrc); __ASSERT_PIECE(pcMoved); __ASSERT_BOUND(0, pcMoved - OPP_SIDE_TAG(this->sdPlayer), 15); // “捉”的判断包括以下几部分内容: switch (pcMoved - OPP_SIDE_TAG(this->sdPlayer)) { // 1. 走了马,判断是否捉车或捉有根的炮兵(卒) case KNIGHT_FROM: case KNIGHT_TO: // 逐一检测马踩的八个位置 lpucsqDst = PreGen.ucsqKnightMoves[sqSrc]; lpucsqPin = PreGen.ucsqKnightPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0) { pcCaptured = this->ucpcSquares[sqDst]; if ((pcCaptured & nSideTag) != 0) { pcCaptured -= nSideTag; __ASSERT_BOUND(0, pcCaptured, 15); // 技巧:优化兵种判断的分枝 if (pcCaptured <= ROOK_TO) { // 马捉仕(士)、相(象)和马的情况不予考虑 if (pcCaptured >= ROOK_FROM) { // 马捉到了车 return pcCaptured; } } else { if (pcCaptured <= CANNON_TO) { // 马捉到了炮,要判断炮是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } else { // 马捉到了兵(卒),要判断兵(卒)是否过河并受保护 if (AWAY_HALF(sqDst, sdPlayer) && !Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } } } } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } break; // 2. 走了车,判断是否捉有根的马炮兵(卒) case ROOK_FROM: case ROOK_TO: x = FILE_X(sqSrc); y = RANK_Y(sqSrc); if (((SRC(mv) ^ sqSrc) & 0xf) == 0) { // 如果车纵向移动了,则判断车横向吃到的子 lpsmv = RankMovePtr(x, y); for (i = 0; i < 2; i ++) { sqDst = lpsmv->ucRookCap[i] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = this->ucpcSquares[sqDst]; if ((pcCaptured & nSideTag) != 0) { pcCaptured -= nSideTag; __ASSERT_BOUND(0, pcCaptured, 15); // 技巧:优化兵种判断的分枝 if (pcCaptured <= ROOK_TO) { // 车捉仕(士)、相(象)的情况不予考虑 if (pcCaptured >= KNIGHT_FROM) { if (pcCaptured <= KNIGHT_TO) { // 车捉到了马,要判断马是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } // 车捉车的情况不予考虑 } } else { if (pcCaptured <= CANNON_TO) { // 车捉到了炮,要判断炮是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } else { // 车捉到了兵(卒),要判断兵(卒)是否过河并受保护 if (AWAY_HALF(sqDst, sdPlayer) && !Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } } } } } } else { // 如果车横向移动了,则判断车纵向吃到的子 lpsmv = FileMovePtr(x, y); for (i = 0; i < 2; i ++) { sqDst = lpsmv->ucRookCap[i] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = this->ucpcSquares[sqDst]; if ((pcCaptured & nSideTag) != 0) { pcCaptured -= nSideTag; __ASSERT_BOUND(0, pcCaptured, 15); // 技巧:优化兵种判断的分枝 if (pcCaptured <= ROOK_TO) { // 车捉仕(士)、相(象)的情况不予考虑 if (pcCaptured >= KNIGHT_FROM) { if (pcCaptured <= KNIGHT_TO) { // 车捉到了马,要判断马是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } // 车捉车的情况不予考虑 } } else { if (pcCaptured <= CANNON_TO) { // 车捉到了炮,要判断炮是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } else { // 车捉到了兵(卒),要判断兵(卒)是否过河并受保护 if (AWAY_HALF(sqDst, sdPlayer) && !Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } } } } } } break; // 3. 走了炮,判断是否捉车或捉有根的马兵(卒) case CANNON_FROM: case CANNON_TO: x = FILE_X(sqSrc); y = RANK_Y(sqSrc); if (((SRC(mv) ^ sqSrc) & 0xf) == 0) { // 如果炮纵向移动了,则判断炮横向吃到的子 lpsmv = RankMovePtr(x, y); for (i = 0; i < 2; i ++) { sqDst = lpsmv->ucCannonCap[i] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = this->ucpcSquares[sqDst]; if ((pcCaptured & nSideTag) != 0) { pcCaptured -= nSideTag; __ASSERT_BOUND(0, pcCaptured, 15); // 技巧:优化兵种判断的分枝 if (pcCaptured <= ROOK_TO) { // 炮捉仕(士)、相(象)的情况不予考虑 if (pcCaptured >= KNIGHT_FROM) { if (pcCaptured <= KNIGHT_TO) { // 炮捉到了马,要判断马是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } else { // 炮捉到了车 return pcCaptured; } } } else { // 炮捉炮的情况不予考虑 if (pcCaptured >= PAWN_FROM) { // 炮捉到了兵(卒),要判断兵(卒)是否过河并受保护 if (AWAY_HALF(sqDst, sdPlayer) && !Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } } } } } } else { // 如果炮横向移动了,则判断炮纵向吃到的子 lpsmv = FileMovePtr(x, y); for (i = 0; i < 2; i ++) { sqDst = lpsmv->ucCannonCap[i] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = this->ucpcSquares[sqDst]; if ((pcCaptured & nSideTag) != 0) { pcCaptured -= nSideTag; __ASSERT_BOUND(0, pcCaptured, 15); // 技巧:优化兵种判断的分枝 if (pcCaptured <= ROOK_TO) { // 炮捉仕(士)、相(象)的情况不予考虑 if (pcCaptured >= KNIGHT_FROM) { if (pcCaptured <= KNIGHT_TO) { // 炮捉到了马,要判断马是否受保护 if (!Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } else { // 炮捉到了车 return pcCaptured; } } } else { // 炮捉炮的情况不予考虑 if (pcCaptured >= PAWN_FROM) { // 炮捉到了兵(卒),要判断兵(卒)是否过河并受保护 if (AWAY_HALF(sqDst, sdPlayer) && !Protected(this->sdPlayer, sqDst)) { return pcCaptured; } } } } } } } break; } return 0; }
// 不吃子着法生成器 int PositionStruct::GenNonCapMoves(MoveStruct *lpmvs) const { int i, sqSrc, sqDst, x, y, nSideTag; SlideMoveStruct *lpsmv; uint8_t *lpucsqDst, *lpucsqPin; MoveStruct *lpmvsCurr; // 生成不吃子着法的过程包括以下几个步骤: lpmvsCurr = lpmvs; nSideTag = SIDE_TAG(sdPlayer); // 1. 生成帅(将)的着法 sqSrc = ucsqPieces[nSideTag + KING_FROM]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKingMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); // 找到一个着法后,首先判断是否吃到棋子 if (ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } // 2. 生成仕(士)的着法 for (i = ADVISOR_FROM; i <= ADVISOR_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqAdvisorMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } } // 3. 生成相(象)的着法 for (i = BISHOP_FROM; i <= BISHOP_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqBishopMoves[sqSrc]; lpucsqPin = PreGen.ucsqBishopPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0 && ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } } } // 4. 生成马的着法 for (i = KNIGHT_FROM; i <= KNIGHT_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKnightMoves[sqSrc]; lpucsqPin = PreGen.ucsqKnightPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0 && ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } } } // 5. 生成车和炮的着法,没有必要判断是否吃到本方棋子 for (i = ROOK_FROM; i <= CANNON_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmv = RankMovePtr(x, y); sqDst = lpsmv->ucNonCap[0] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst --; } sqDst = lpsmv->ucNonCap[1] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst ++; } lpsmv = FileMovePtr(x, y); sqDst = lpsmv->ucNonCap[0] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst -= 16; } sqDst = lpsmv->ucNonCap[1] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst += 16; } } } // 6. 生成兵(卒)的着法 for (i = PAWN_FROM; i <= PAWN_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqPawnMoves[sdPlayer][sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } } return lpmvsCurr - lpmvs; }
// 棋子保护判断 bool PositionStruct::Protected(int sd, int sqSrc, int sqExcept) const { // 参数"sqExcept"表示排除保护的棋子(指格子编号),考虑被牵制子的保护时,需要排除牵制目标子的保护 int i, sqDst, sqPin, pc, x, y, nSideTag; SlideMaskStruct *lpsmsRank, *lpsmsFile; // 棋子保护判断包括以下几个步骤: __ASSERT_SQUARE(sqSrc); nSideTag = SIDE_TAG(sd); if (HOME_HALF(sqSrc, sd)) { if (IN_FORT(sqSrc)) { // 1. 判断受到帅(将)的保护 sqDst = ucsqPieces[nSideTag + KING_FROM]; if (sqDst != 0 && sqDst != sqExcept) { __ASSERT_SQUARE(sqDst); if (KING_SPAN(sqSrc, sqDst)) { return true; } } // 2. 判断受到仕(士)的保护 for (i = ADVISOR_FROM; i <= ADVISOR_TO; i ++) { sqDst = ucsqPieces[nSideTag + i]; if (sqDst != 0 && sqDst != sqExcept) { __ASSERT_SQUARE(sqDst); if (ADVISOR_SPAN(sqSrc, sqDst)) { return true; } } } } // 3. 判断受到相(象)的保护 for (i = BISHOP_FROM; i <= BISHOP_TO; i ++) { sqDst = ucsqPieces[nSideTag + i]; if (sqDst != 0 && sqDst != sqExcept) { __ASSERT_SQUARE(sqDst); if (BISHOP_SPAN(sqSrc, sqDst) && ucpcSquares[BISHOP_PIN(sqSrc, sqDst)] == 0) { return true; } } } } else { // 4. 判断受到过河兵(卒)横向的保护 for (sqDst = sqSrc - 1; sqDst <= sqSrc + 1; sqDst += 2) { // 如果棋子在边线,那么断言不成立 // __ASSERT_SQUARE(sqDst); if (sqDst != sqExcept) { pc = ucpcSquares[sqDst]; if ((pc & nSideTag) != 0 && PIECE_INDEX(pc) >= PAWN_FROM) { return true; } } } } // 5. 判断受到兵(卒)纵向的保护 sqDst = SQUARE_BACKWARD(sqSrc, sd); // 如果棋子在底线,那么断言不成立 // __ASSERT_SQUARE(sqDst); if (sqDst != sqExcept) { pc = ucpcSquares[sqDst]; if ((pc & nSideTag) != 0 && PIECE_INDEX(pc) >= PAWN_FROM) { return true; } } // 6. 判断受到马的保护 for (i = KNIGHT_FROM; i <= KNIGHT_TO; i ++) { sqDst = ucsqPieces[nSideTag + i]; if (sqDst != 0 && sqDst != sqExcept) { __ASSERT_SQUARE(sqDst); sqPin = KNIGHT_PIN(sqDst, sqSrc); // 注意,sqSrc和sqDst是反的! if (sqPin != sqDst && ucpcSquares[sqPin] == 0) { return true; } } } x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmsRank = RankMaskPtr(x, y); lpsmsFile = FileMaskPtr(x, y); // 7. 判断受到车的保护,参阅"position.cpp"里的"CheckedBy()"函数 for (i = ROOK_FROM; i <= ROOK_TO; i ++) { sqDst = ucsqPieces[nSideTag + i]; if (sqDst != 0 && sqDst != sqSrc && sqDst != sqExcept) { if (x == FILE_X(sqDst)) { if ((lpsmsFile->wRookCap & PreGen.wBitFileMask[sqDst]) != 0) { return true; } } else if (y == RANK_Y(sqDst)) { if ((lpsmsRank->wRookCap & PreGen.wBitRankMask[sqDst]) != 0) { return true; } } } } // 8. 判断受到炮的保护,参阅"position.cpp"里的"CheckedBy()"函数 for (i = CANNON_FROM; i <= CANNON_TO; i ++) { sqDst = ucsqPieces[nSideTag + i]; if (sqDst && sqDst != sqSrc && sqDst != sqExcept) { if (x == FILE_X(sqDst)) { if ((lpsmsFile->wCannonCap & PreGen.wBitFileMask[sqDst]) != 0) { return true; } } else if (y == RANK_Y(sqDst)) { if ((lpsmsRank->wCannonCap & PreGen.wBitRankMask[sqDst]) != 0) { return true; } } } } return false; }
// 吃子着法生成器,按MVV(LVA)设定分值 int PositionStruct::GenCapMoves(MoveStruct *lpmvs) const { int i, sqSrc, sqDst, pcCaptured; int x, y, nSideTag, nOppSideTag; bool bCanPromote; SlideMoveStruct *lpsmv; uint8_t *lpucsqDst, *lpucsqPin; MoveStruct *lpmvsCurr; // 生成吃子着法的过程包括以下几个步骤: lpmvsCurr = lpmvs; nSideTag = SIDE_TAG(sdPlayer); nOppSideTag = OPP_SIDE_TAG(sdPlayer); bCanPromote = PreEval.bPromotion && CanPromote(); // 1. 生成帅(将)的着法 sqSrc = ucsqPieces[nSideTag + KING_FROM]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKingMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); // 找到一个着法后,首先判断吃到的棋子是否是对方棋子,技巧是利用"nOppSideTag"的标志(16和32颠倒), // 如果是对方棋子,则保存MVV(LVA)值,即如果被吃子无保护,则只记MVV,否则记MVV-LVA(如果MVV>LVA的话)。 pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 5); // 帅(将)的价值是5 lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } // 2. 生成仕(士)的着法 for (i = ADVISOR_FROM; i <= ADVISOR_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqAdvisorMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 1); // 仕(士)的价值是1 lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } if (bCanPromote && CAN_PROMOTE(sqSrc)) { lpmvsCurr->wmv = MOVE(sqSrc, sqSrc); lpmvsCurr->wvl = 0; lpmvsCurr ++; } } } // 3. 生成相(象)的着法 for (i = BISHOP_FROM; i <= BISHOP_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqBishopMoves[sqSrc]; lpucsqPin = PreGen.ucsqBishopPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 1); // 相(象)的价值是1 lpmvsCurr ++; } } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } if (bCanPromote && CAN_PROMOTE(sqSrc)) { lpmvsCurr->wmv = MOVE(sqSrc, sqSrc); lpmvsCurr->wvl = 0; lpmvsCurr ++; } } } // 4. 生成马的着法 for (i = KNIGHT_FROM; i <= KNIGHT_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKnightMoves[sqSrc]; lpucsqPin = PreGen.ucsqKnightPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 马的价值是3 lpmvsCurr ++; } } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } } } // 5. 生成车的着法 for (i = ROOK_FROM; i <= ROOK_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmv = RankMovePtr(x, y); sqDst = lpsmv->ucRookCap[0] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } sqDst = lpsmv->ucRookCap[1] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } lpsmv = FileMovePtr(x, y); sqDst = lpsmv->ucRookCap[0] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } sqDst = lpsmv->ucRookCap[1] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } } } // 6. 生成炮的着法 for (i = CANNON_FROM; i <= CANNON_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmv = RankMovePtr(x, y); sqDst = lpsmv->ucCannonCap[0] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } sqDst = lpsmv->ucCannonCap[1] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } lpsmv = FileMovePtr(x, y); sqDst = lpsmv->ucCannonCap[0] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } sqDst = lpsmv->ucCannonCap[1] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } } } // 7. 生成兵(卒)的着法 for (i = PAWN_FROM; i <= PAWN_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqPawnMoves[sdPlayer][sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 2); // 兵(卒)的价值是2 lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } } return lpmvsCurr - lpmvs; }
void PositionStruct::PreEvaluate(void) { int i, sq, nMidgameValue, nWhiteAttacks, nBlackAttacks, nWhiteSimpleValue, nBlackSimpleValue; uint8_t ucvlPawnPiecesAttacking[256], ucvlPawnPiecesAttackless[256]; if (!bInit) { bInit = true; // 初始化"PreEvalEx.cPopCnt16"数组,只需要初始化一次 for (i = 0; i < 65536; i ++) { PreEvalEx.cPopCnt16[i] = PopCnt16(i); } } // 首先判断局势处于开中局还是残局阶段,方法是计算各种棋子的数量,按照车=6、马炮=3、其它=1相加。 nMidgameValue = PopCnt32(this->dwBitPiece & BOTH_BITPIECE(ADVISOR_BITPIECE | BISHOP_BITPIECE | PAWN_BITPIECE)) * OTHER_MIDGAME_VALUE; nMidgameValue += PopCnt32(this->dwBitPiece & BOTH_BITPIECE(KNIGHT_BITPIECE | CANNON_BITPIECE)) * KNIGHT_CANNON_MIDGAME_VALUE; nMidgameValue += PopCnt32(this->dwBitPiece & BOTH_BITPIECE(ROOK_BITPIECE)) * ROOK_MIDGAME_VALUE; // 使用二次函数,子力很少时才认为接近残局 nMidgameValue = (2 * TOTAL_MIDGAME_VALUE - nMidgameValue) * nMidgameValue / TOTAL_MIDGAME_VALUE; __ASSERT_BOUND(0, nMidgameValue, TOTAL_MIDGAME_VALUE); PreEval.vlAdvanced = (TOTAL_ADVANCED_VALUE * nMidgameValue + TOTAL_ADVANCED_VALUE / 2) / TOTAL_MIDGAME_VALUE; __ASSERT_BOUND(0, PreEval.vlAdvanced, TOTAL_ADVANCED_VALUE); for (sq = 0; sq < 256; sq ++) { if (IN_BOARD(sq)) { PreEval.ucvlWhitePieces[0][sq] = PreEval.ucvlBlackPieces[0][SQUARE_FLIP(sq)] = (uint8_t) ((cucvlKingPawnMidgameAttacking[sq] * nMidgameValue + cucvlKingPawnEndgameAttacking[sq] * (TOTAL_MIDGAME_VALUE - nMidgameValue)) / TOTAL_MIDGAME_VALUE); PreEval.ucvlWhitePieces[3][sq] = PreEval.ucvlBlackPieces[3][SQUARE_FLIP(sq)] = (uint8_t) ((cucvlKnightMidgame[sq] * nMidgameValue + cucvlKnightEndgame[sq] * (TOTAL_MIDGAME_VALUE - nMidgameValue)) / TOTAL_MIDGAME_VALUE); PreEval.ucvlWhitePieces[4][sq] = PreEval.ucvlBlackPieces[4][SQUARE_FLIP(sq)] = (uint8_t) ((cucvlRookMidgame[sq] * nMidgameValue + cucvlRookEndgame[sq] * (TOTAL_MIDGAME_VALUE - nMidgameValue)) / TOTAL_MIDGAME_VALUE); PreEval.ucvlWhitePieces[5][sq] = PreEval.ucvlBlackPieces[5][SQUARE_FLIP(sq)] = (uint8_t) ((cucvlCannonMidgame[sq] * nMidgameValue + cucvlCannonEndgame[sq] * (TOTAL_MIDGAME_VALUE - nMidgameValue)) / TOTAL_MIDGAME_VALUE); ucvlPawnPiecesAttacking[sq] = PreEval.ucvlWhitePieces[0][sq]; ucvlPawnPiecesAttackless[sq] = (uint8_t) ((cucvlKingPawnMidgameAttackless[sq] * nMidgameValue + cucvlKingPawnEndgameAttackless[sq] * (TOTAL_MIDGAME_VALUE - nMidgameValue)) / TOTAL_MIDGAME_VALUE); } } for (i = 0; i < 16; i ++) { PreEvalEx.vlHollowThreat[i] = cvlHollowThreat[i] * (nMidgameValue + TOTAL_MIDGAME_VALUE) / (TOTAL_MIDGAME_VALUE * 2); __ASSERT_BOUND(0, PreEvalEx.vlHollowThreat[i], cvlHollowThreat[i]); PreEvalEx.vlCentralThreat[i] = cvlCentralThreat[i]; } // 然后判断各方是否处于进攻状态,方法是计算各种过河棋子的数量,按照车马2炮兵1相加。 nWhiteAttacks = nBlackAttacks = 0; for (i = SIDE_TAG(0) + KNIGHT_FROM; i <= SIDE_TAG(0) + ROOK_TO; i ++) { if (this->ucsqPieces[i] != 0 && BLACK_HALF(this->ucsqPieces[i])) { nWhiteAttacks += 2; } } for (i = SIDE_TAG(0) + CANNON_FROM; i <= SIDE_TAG(0) + PAWN_TO; i ++) { if (this->ucsqPieces[i] != 0 && BLACK_HALF(this->ucsqPieces[i])) { nWhiteAttacks ++; } } for (i = SIDE_TAG(1) + KNIGHT_FROM; i <= SIDE_TAG(1) + ROOK_TO; i ++) { if (this->ucsqPieces[i] != 0 && WHITE_HALF(this->ucsqPieces[i])) { nBlackAttacks += 2; } } for (i = SIDE_TAG(1) + CANNON_FROM; i <= SIDE_TAG(1) + PAWN_TO; i ++) { if (this->ucsqPieces[i] != 0 && WHITE_HALF(this->ucsqPieces[i])) { nBlackAttacks ++; } } // 如果本方轻子数比对方多,那么每多一个轻子(车算2个轻子)威胁值加2。威胁值最多不超过8。 nWhiteSimpleValue = PopCnt16(this->wBitPiece[0] & ROOK_BITPIECE) * 2 + PopCnt16(this->wBitPiece[0] & (KNIGHT_BITPIECE | CANNON_BITPIECE)); nBlackSimpleValue = PopCnt16(this->wBitPiece[1] & ROOK_BITPIECE) * 2 + PopCnt16(this->wBitPiece[1] & (KNIGHT_BITPIECE | CANNON_BITPIECE)); if (nWhiteSimpleValue > nBlackSimpleValue) { nWhiteAttacks += (nWhiteSimpleValue - nBlackSimpleValue) * 2; } else { nBlackAttacks += (nBlackSimpleValue - nWhiteSimpleValue) * 2; } nWhiteAttacks = MIN(nWhiteAttacks, TOTAL_ATTACK_VALUE); nBlackAttacks = MIN(nBlackAttacks, TOTAL_ATTACK_VALUE); PreEvalEx.vlBlackAdvisorLeakage = TOTAL_ADVISOR_LEAKAGE * nWhiteAttacks / TOTAL_ATTACK_VALUE; PreEvalEx.vlWhiteAdvisorLeakage = TOTAL_ADVISOR_LEAKAGE * nBlackAttacks / TOTAL_ATTACK_VALUE; __ASSERT_BOUND(0, nWhiteAttacks, TOTAL_ATTACK_VALUE); __ASSERT_BOUND(0, nBlackAttacks, TOTAL_ATTACK_VALUE); __ASSERT_BOUND(0, PreEvalEx.vlBlackAdvisorLeakage, TOTAL_ADVISOR_LEAKAGE); __ASSERT_BOUND(0, PreEvalEx.vlBlackAdvisorLeakage, TOTAL_ADVISOR_LEAKAGE); for (sq = 0; sq < 256; sq ++) { if (IN_BOARD(sq)) { PreEval.ucvlWhitePieces[1][sq] = PreEval.ucvlWhitePieces[2][sq] = (uint8_t) ((cucvlAdvisorBishopThreatened[sq] * nBlackAttacks + (PreEval.bPromotion ? cucvlAdvisorBishopPromotionThreatless[sq] : cucvlAdvisorBishopThreatless[sq]) * (TOTAL_ATTACK_VALUE - nBlackAttacks)) / TOTAL_ATTACK_VALUE); PreEval.ucvlBlackPieces[1][sq] = PreEval.ucvlBlackPieces[2][sq] = (uint8_t) ((cucvlAdvisorBishopThreatened[SQUARE_FLIP(sq)] * nWhiteAttacks + (PreEval.bPromotion ? cucvlAdvisorBishopPromotionThreatless[SQUARE_FLIP(sq)] : cucvlAdvisorBishopThreatless[SQUARE_FLIP(sq)]) * (TOTAL_ATTACK_VALUE - nWhiteAttacks)) / TOTAL_ATTACK_VALUE); PreEval.ucvlWhitePieces[6][sq] = (uint8_t) ((ucvlPawnPiecesAttacking[sq] * nWhiteAttacks + ucvlPawnPiecesAttackless[sq] * (TOTAL_ATTACK_VALUE - nWhiteAttacks)) / TOTAL_ATTACK_VALUE); PreEval.ucvlBlackPieces[6][sq] = (uint8_t) ((ucvlPawnPiecesAttacking[SQUARE_FLIP(sq)] * nBlackAttacks + ucvlPawnPiecesAttackless[SQUARE_FLIP(sq)] * (TOTAL_ATTACK_VALUE - nBlackAttacks)) / TOTAL_ATTACK_VALUE); } } for (i = 0; i < 16; i ++) { PreEvalEx.vlWhiteBottomThreat[i] = cvlBottomThreat[i] * nBlackAttacks / TOTAL_ATTACK_VALUE; PreEvalEx.vlBlackBottomThreat[i] = cvlBottomThreat[i] * nWhiteAttacks / TOTAL_ATTACK_VALUE; } // 检查预评价是否对称 #ifndef NDEBUG for (sq = 0; sq < 256; sq ++) { if (IN_BOARD(sq)) { for (i = 0; i < 7; i ++) { __ASSERT(PreEval.ucvlWhitePieces[i][sq] == PreEval.ucvlWhitePieces[i][SQUARE_MIRROR(sq)]); __ASSERT(PreEval.ucvlBlackPieces[i][sq] == PreEval.ucvlBlackPieces[i][SQUARE_MIRROR(sq)]); } } } for (i = FILE_LEFT; i <= FILE_RIGHT; i ++) { __ASSERT(PreEvalEx.vlWhiteBottomThreat[i] == PreEvalEx.vlWhiteBottomThreat[FILE_FLIP(i)]); __ASSERT(PreEvalEx.vlBlackBottomThreat[i] == PreEvalEx.vlBlackBottomThreat[FILE_FLIP(i)]); } #endif // 调整不受威胁方少掉的仕(士)相(象)分值 this->vlWhite = ADVISOR_BISHOP_ATTACKLESS_VALUE * (TOTAL_ATTACK_VALUE - nBlackAttacks) / TOTAL_ATTACK_VALUE; this->vlBlack = ADVISOR_BISHOP_ATTACKLESS_VALUE * (TOTAL_ATTACK_VALUE - nWhiteAttacks) / TOTAL_ATTACK_VALUE; // 如果允许升变,那么不受威胁的仕(士)相(象)分值就少了一半 if (PreEval.bPromotion) { this->vlWhite /= 2; this->vlBlack /= 2; } // 最后重新计算子力位置分 for (i = 16; i < 32; i ++) { sq = this->ucsqPieces[i]; if (sq != 0) { __ASSERT_SQUARE(sq); this->vlWhite += PreEval.ucvlWhitePieces[PIECE_TYPE(i)][sq]; } } for (i = 32; i < 48; i ++) { sq = this->ucsqPieces[i]; if (sq != 0) { __ASSERT_SQUARE(sq); this->vlBlack += PreEval.ucvlBlackPieces[PIECE_TYPE(i)][sq]; } } }
void FromFen(const char *szFen) { int i, j, k; int pcWhite[7]; int pcBlack[7]; const char *lpFen; // FEN串的识别包括以下几个步骤: // 1. 初始化,清空棋盘 pcWhite[0] = SIDE_TAG(0) + KING_FROM; pcWhite[1] = SIDE_TAG(0) + ADVISOR_FROM; pcWhite[2] = SIDE_TAG(0) + BISHOP_FROM; pcWhite[3] = SIDE_TAG(0) + KNIGHT_FROM; pcWhite[4] = SIDE_TAG(0) + ROOK_FROM; pcWhite[5] = SIDE_TAG(0) + CANNON_FROM; pcWhite[6] = SIDE_TAG(0) + PAWN_FROM; for (i = 0; i < 7; i ++) { pcBlack[i] = pcWhite[i] + 16; } /* 数组"pcWhite[7]"和"pcBlack[7]"分别代表红方和黑方每个兵种即将占有的序号, * 以"pcWhite[7]"为例,由于棋子16到31依次代表“帅仕仕相相马马车车炮炮兵兵兵兵兵”, * 所以最初应该是"pcWhite[7] = {16, 17, 19, 21, 23, 25, 27}",每添加一个棋子,该项就增加1, * 这种做法允许添加多余的棋子(例如添加第二个帅,就变成仕了),但添加前要做边界检测 */ // ClearBoard(); lpFen = szFen; if (*lpFen == '\0') { // SetIrrev(); return; } // 2. 读取棋盘上的棋子 i = RANK_TOP; j = FILE_LEFT; while (*lpFen != ' ') { if (*lpFen == '/') { j = FILE_LEFT; i ++; if (i > RANK_BOTTOM) { break; } } else if (*lpFen >= '1' && *lpFen <= '9') { for (k = 0; k < (*lpFen - '0'); k ++) { if (j >= FILE_RIGHT) { break; } j ++; } } else if (*lpFen >= 'A' && *lpFen <= 'Z') { if (j <= FILE_RIGHT) { k = FenPiece(*lpFen); if (k < 7) { if (pcWhite[k] < 32) { //if (this->ucsqPieces[pcWhite[k]] == 0) { AddPiece(COORD_XY(j, i), pcWhite[k]); pcWhite[k] ++; //} } } j ++; } } else if (*lpFen >= 'a' && *lpFen <= 'z') { if (j <= FILE_RIGHT) { //k = FenPiece(*lpFen + 'A' - 'a'); k = FenPiece(*lpFen); if (6<k < 14) { if (pcBlack[k-7] < 48) { //if (this->ucsqPieces[pcBlack[k]] == 0) { AddPiece(COORD_XY(j, i), pcBlack[k-7]); pcBlack[k-7] ++; //} } } j ++; } } lpFen ++; if (*lpFen == '\0') { //SetIrrev(); return; } } lpFen ++; // 3. 确定轮到哪方走 // if (this->sdPlayer == (*lpFen == 'b' ? 0 : 1)) { // ChangeSide(); // } // // 4. 把局面设成“不可逆” // SetIrrev(); }