Beispiel #1
0
void BuildPos(PositionStruct &pos, const UcciCommStruct &UcciComm) {
  int i, mv;
  pos.FromFen(UcciComm.szFenStr);
  for (i = 0; i < UcciComm.nMoveNum; i ++) {
    mv = COORD_MOVE(UcciComm.lpdwMovesCoord[i]);
    if (mv == 0) {
      break;
    }
    if (pos.LegalMove(mv) && pos.MakeMove(mv) && pos.LastMove().CptDrw > 0) {
      // 始终让pos.nMoveNum反映没吃子的步数
      pos.SetIrrev();
    }
  }
}
Beispiel #2
0
void BuildPos(PositionStruct &pos, const UcciCommStruct &UcciComm) {
    int i, mv;
    pos.FromFen(UcciComm.szFenStr);
    for (i = 0; i < UcciComm.nMoveNum; i ++) {
        mv = COORD_MOVE(UcciComm.lpdwMovesCoord[i]);
        if (mv == 0) {
            break;
        }
        if (pos.ucpcSquares[SRC(mv)] == 0) {
            break;
        }
        pos.MakeMove(mv);
    }
}
Beispiel #3
0
// UCCI支持 - 输出Hash表中的局面信息
bool PopHash(const PositionStruct &pos) {
  HashStruct hsh;
  uint32_t dwMoveStr;
  int i;

  for (i = 0; i < HASH_LAYERS; i ++) {
    hsh = HASH_ITEM(pos, i);
    if (HASH_POS_EQUAL(hsh, pos)) {
      printf("pophash");
      if (hsh.wmv != 0) {
        __ASSERT(pos.LegalMove(hsh.wmv));
        dwMoveStr = MOVE_COORD(hsh.wmv);
        printf(" bestmove %.4s", (const char *) &dwMoveStr);
      }
      if (hsh.ucBetaDepth > 0) {
        printf(" lowerbound %d depth %d", hsh.svlBeta, hsh.ucBetaDepth);
      }
      if (hsh.ucAlphaDepth > 0) {
        printf(" upperbound %d depth %d", hsh.svlAlpha, hsh.ucAlphaDepth);
      }
      printf("\n");
      fflush(stdout);
      return true;
    }
  }
  return false;
}
Beispiel #4
0
// 点击格子事件处理
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);
}
Beispiel #5
0
// 翻转棋盘
void FlipBoard(PositionStruct &pos) {
  int i, sq;
  uint8_t ucsqList[32];
  for (i = 16; i < 48; i ++) {
    sq = pos.ucsqPieces[i];
    ucsqList[i - 16] = sq;
    if (sq != 0) {
      pos.AddPiece(sq, i, DEL_PIECE);
    }
  }
  for (i = 16; i < 48; i ++) {
    sq = ucsqList[i - 16]; // 这行不同于ExchangeSide
    if (sq != 0) {
      pos.AddPiece(SQUARE_FLIP(sq), i);
    }
  }
}
Beispiel #6
0
// 检测下一个着法是否稳定,有助于减少置换表的不稳定性
inline bool MoveStable(PositionStruct &pos, int mv) {
  // 判断下一个着法是否稳定的依据是:
  // 1. 没有后续着法,则假定是稳定的;
  if (mv == 0) {
    return true;
  }
  // 2. 吃子着法是稳定的;
  __ASSERT(pos.LegalMove(mv));
  if (pos.ucpcSquares[DST(mv)] != 0) {
    return true;
  }
  // 3. 可能因置换表引起路线迁移,使得路线超过"MAX_MOVE_NUM",此时应立刻终止路线,并假定是稳定的。
  if (!pos.MakeMove(mv)) {
    return true;
  }
  return false;
}
Beispiel #7
0
int Node::playRollout(){
	PositionStruct p = pos;
	int player = p.sdPlayer;
	int k = K;
	int mv[128];
	int i;
	for (i = 0; i < k; i++){
		mv[k] = move[k];
	}
	while (1){
		p.MakeMove(mv[ppi(pos2fen(&p), k, mv)]);
		genMove(&p, k, mv);
		if (k == 0){ //无子可走被将死
			if (p.sdPlayer == player){ //自己被将死
				return 0;
			}
			else{
				return 1;
			}
		}
	}
}
Beispiel #8
0
static void AddEcco(const char *szPgnFile, const EccoApiStruct &EccoApi) {
  int i, nStatus;
  uint32_t dwEccoIndex, dwFileMove[20];
  PgnFileStruct pgn;
  PositionStruct pos;

  if (pgn.Read(szPgnFile, NO_ADVERT)) {
    pos.FromFen(cszStartFen);
    for (i = 1; i <= MIN(pgn.nMaxMove, 20); i ++) {
      dwFileMove[i - 1] = Move2File(pgn.wmvMoveTable[i], pos);
      TryMove(pos, nStatus, pgn.wmvMoveTable[i]);
    }
    if (pgn.nMaxMove < 20) {
      dwFileMove[pgn.nMaxMove] = 0;
    }
    dwEccoIndex = EccoApi.EccoIndex((const char *) dwFileMove);
    strcpy(pgn.szEcco, (const char *) &dwEccoIndex);
    strcpy(pgn.szOpen, EccoApi.EccoOpening(dwEccoIndex));
    strcpy(pgn.szVar, EccoApi.EccoVariation(dwEccoIndex));
    pgn.Write(szPgnFile);
  }
}
Beispiel #9
0
// 无害裁剪
static int HarmlessPruning(const PositionStruct &pos, int vlBeta) {
  int vl, vlRep;

  // 1. 杀棋步数裁剪;
  vl = pos.nDistance - MATE_VALUE;
  if (vl >= vlBeta) {
    return vl;
  }

  // 2. 和棋裁剪;
  if (pos.IsDraw()) {
    return 0; // 安全起见,这里不用"pos.DrawValue()";
  }

  // 3. 重复裁剪;
  vlRep = pos.RepStatus();
  if (vlRep > 0) {
    return pos.RepValue(vlRep);
  }

  return -MATE_VALUE;
}
Beispiel #10
0
// 无害裁剪
int HarmlessPruning ( void ) {
	// 1. 和局局面
	if ( pos.IsDraw() ) {
		return 0; // eleeye上表示,为了安全起见,不用pos.DrawValue()
	}

	// 2. 路径重复
	const int vRep = roll.RepStatus ();
	if ( vRep != REP_NONE ) {
		return roll.RepValue ( vRep );
	}

	return - MATE_VALUE;
}
Beispiel #11
0
// 获取置换表局面信息(没有命中时,返回"-MATE_VALUE")
int ProbeHash(const PositionStruct &pos, int vlAlpha, int vlBeta, int nDepth, bool bNoNull, int &mv) {
  HashStruct hsh;
  int i, vl;
  bool bBanNode, bMateNode;
  // 获取置换表局面信息的过程包括以下几个步骤:

  // 1. 逐层获取置换表项
  mv = 0;
  for (i = 0; i < HASH_LAYERS; i ++) {
    hsh = HASH_ITEM(pos, i);
    if (HASH_POS_EQUAL(hsh, pos)) {
      mv = hsh.wmv;
      __ASSERT(mv == 0 || pos.LegalMove(mv));
      break;
    }
  }
  if (i == HASH_LAYERS) {
    return -MATE_VALUE;
  }

  // 2. 判断是否符合Beta边界
  if (hsh.ucBetaDepth > 0) {
    vl = ValueAdjust(pos, bBanNode, bMateNode, hsh.svlBeta);
    if (!bBanNode && !(hsh.wmv == 0 && bNoNull) && (hsh.ucBetaDepth >= nDepth || bMateNode) && vl >= vlBeta) {
      __ASSERT_BOUND(1 - MATE_VALUE, vl, MATE_VALUE - 1);
      if (hsh.wmv == 0 || PosStable(pos, hsh.wmv)) {
        return vl;
      }
    }
  }

  // 3. 判断是否符合Alpha边界
  if (hsh.ucAlphaDepth > 0) {
    vl = ValueAdjust(pos, bBanNode, bMateNode, hsh.svlAlpha);
    if (!bBanNode && (hsh.ucAlphaDepth >= nDepth || bMateNode) && vl <= vlAlpha) {
      __ASSERT_BOUND(1 - MATE_VALUE, vl, MATE_VALUE - 1);
      if (hsh.wmv == 0 || PosStable(pos, hsh.wmv)) {
        return vl;
      }
    }
  }
  return -MATE_VALUE;
}
Beispiel #12
0
// 尝试某个着法,并返回着法状态,参阅"cchess.h"
bool TryMove(PositionStruct &pos, int &nStatus, int mv) {
  if (!pos.LegalMove(mv)) {
    nStatus = MOVE_ILLEGAL;
    return false;
  }
  if (!pos.MakeMove(mv)) {
    nStatus = MOVE_INCHECK;
    return false;
  }
  nStatus = 0;
  nStatus += (pos.LastMove().CptDrw > 0 ? MOVE_CAPTURE : 0);
  nStatus += (pos.LastMove().ChkChs > 0 ? MOVE_CHECK : 0);
  nStatus += (pos.IsMate() ? MOVE_MATE : 0);
  nStatus += pos.RepStatus(3) * MOVE_PERPETUAL; // 提示:参阅"position.cpp"中的"IsRep()"函数
  nStatus += (pos.IsDraw() ? MOVE_DRAW : 0);
  pos.UndoMakeMove();
  return true;
}
Beispiel #13
0
/* 判断获取置换表要符合哪些条件,置换表的分值针对四个不同的区间有不同的处理:
 * 一、如果分值在"WIN_VALUE"以内(即介于"-WIN_VALUE"到"WIN_VALUE"之间,下同),则只获取满足搜索深度要求的局面;
 * 二、如果分值在"WIN_VALUE"和"BAN_VALUE"之间,则不能获取置换表中的值(只能获取最佳着法仅供参考),目的是防止由于长将而导致的“置换表的不稳定性”;
 * 三、如果分值在"BAN_VALUE"以外,则获取局面时不必考虑搜索深度要求,因为这些局面已经被证明是杀棋了;
 * 四、如果分值是"DrawValue()"(是第一种情况的特殊情况),则不能获取置换表中的值(原因与第二种情况相同)。
 * 注意:对于第三种情况,要对杀棋步数进行调整!
 */
inline int ValueAdjust(const PositionStruct &pos, bool &bBanNode, bool &bMateNode, int vl) {
  bBanNode = bMateNode = false;
  if (vl > WIN_VALUE) {
    if (vl <= BAN_VALUE) {
      bBanNode = true;
    } else {
      bMateNode = true;
      vl -= pos.nDistance;
    }
  } else if (vl < -WIN_VALUE) {
    if (vl >= -BAN_VALUE) {
      bBanNode = true;
    } else {
      bMateNode = true;
      vl += pos.nDistance;
    }
  } else if (vl == pos.DrawValue()) {
    bBanNode = true;
  }
  return vl;
}
Beispiel #14
0
// 存储置换表局面信息
void RecordHash(const PositionStruct &pos, int nFlag, int vl, int nDepth, int mv) {
  HashStruct hsh;
  int i, nHashDepth, nMinDepth, nMinLayer;
  // 存储置换表局面信息的过程包括以下几个步骤:

  // 1. 对分值做杀棋步数调整;
  __ASSERT_BOUND(1 - MATE_VALUE, vl, MATE_VALUE - 1);
  __ASSERT(mv == 0 || pos.LegalMove(mv));
  if (vl > WIN_VALUE) {
    if (mv == 0 && vl <= BAN_VALUE) {
      return; // 导致长将的局面(不进行置换裁剪)如果连最佳着法也没有,那么没有必要写入置换表
    }
    vl += pos.nDistance;
  } else if (vl < -WIN_VALUE) {
    if (mv == 0 && vl >= -BAN_VALUE) {
      return; // 同理
    }
    vl -= pos.nDistance;
  } else if (vl == pos.DrawValue() && mv == 0) {
    return;   // 同理
  }

  // 2. 逐层试探置换表;
  nMinDepth = 512;
  nMinLayer = 0;
  for (i = 0; i < HASH_LAYERS; i ++) {
    hsh = HASH_ITEM(pos, i);

    // 3. 如果试探到一样的局面,那么更新置换表信息即可;
    if (HASH_POS_EQUAL(hsh, pos)) {
      // 如果深度更深,或者边界缩小,都可更新置换表的值
      if ((nFlag & HASH_ALPHA) != 0 && (hsh.ucAlphaDepth <= nDepth || hsh.svlAlpha >= vl)) {
        hsh.ucAlphaDepth = nDepth;
        hsh.svlAlpha = vl;
      }
      // Beta结点要注意:不要用Null-Move的结点覆盖正常的结点
      if ((nFlag & HASH_BETA) != 0 && (hsh.ucBetaDepth <= nDepth || hsh.svlBeta <= vl) && (mv != 0 || hsh.wmv == 0)) {
        hsh.ucBetaDepth = nDepth;
        hsh.svlBeta = vl;
      }
      // 最佳着法是始终覆盖的
      if (mv != 0) {
        hsh.wmv = mv;
      }
      HASH_ITEM(pos, i) = hsh;
      return;
    }

    // 4. 如果不是一样的局面,那么获得深度最小的置换表项;
    nHashDepth = MAX((hsh.ucAlphaDepth == 0 ? 0 : hsh.ucAlphaDepth + 256),
        (hsh.wmv == 0 ? hsh.ucBetaDepth : hsh.ucBetaDepth + 256));
    __ASSERT(nHashDepth < 512);
    if (nHashDepth < nMinDepth) {
      nMinDepth = nHashDepth;
      nMinLayer = i;
    }
  }

  // 5. 记录置换表。
  hsh.dwZobristLock0 = pos.zobr.dwLock0;
  hsh.dwZobristLock1 = pos.zobr.dwLock1;
  hsh.wmv = mv;
  hsh.ucAlphaDepth = hsh.ucBetaDepth = 0;
  hsh.svlAlpha = hsh.svlBeta = 0;
  if ((nFlag & HASH_ALPHA) != 0) {
    hsh.ucAlphaDepth = nDepth;
    hsh.svlAlpha = vl;
  }
  if ((nFlag & HASH_BETA) != 0) {
    hsh.ucBetaDepth = nDepth;
    hsh.svlBeta = vl;
  }
  HASH_ITEM(pos, nMinLayer) = hsh;
}
Beispiel #15
0
int Xqf2Pgn(const char *szXqfFile, const char *szPgnFile, const EccoApiStruct &EccoApi) {
  int i, nArg0, nArgs[4];
  int nCommentLen, mv, nStatus;
  bool bHasNext;
  PgnFileStruct pgn;
  PositionStruct pos;

  FILE *fp;
  XqfHeaderStruct xqfhd;  
  XqfMoveStruct xqfmv;
  // 版本号和加密偏移值
  int nXqfVer, nPieceOff, nSrcOff, nDstOff, nCommentOff;
  // 密钥流
  int nEncStream[32];
  // 密钥流索引号
  int nEncIndex;
  // 局面初始位置
  int nPiecePos[32];

  uint32_t dwEccoIndex, dwFileMove[20];

  fp = fopen(szXqfFile, "rb");
  if (fp == NULL) {
    return XQF2PGN_ERROR_OPEN;
  }
  fread(&xqfhd, sizeof(xqfhd), 1, fp);
  fseek(fp, sizeof(xqfhd), SEEK_CUR);
  if (xqfhd.szTag[0] == 'X' && xqfhd.szTag[1] == 'Q') {
    // PGN文件可以打开,现在正式解析XQF文件
    nXqfVer = xqfhd.szTag[2];
    if (nXqfVer < 11) {
      nPieceOff = nSrcOff = nDstOff = nCommentOff = 0;
      for (i = 0; i < 32; i ++) {
        nEncStream[i] = 0;
      }
    } else {
      // 局面初始位置的加密偏移值
      nPieceOff = (uint8_t) (Square54Plus221((uint8_t) xqfhd.szTag[13]) * (uint8_t) xqfhd.szTag[13]);
      // 着法起点的加密偏移值
      nSrcOff = (uint8_t) (Square54Plus221((uint8_t) xqfhd.szTag[14]) * nPieceOff);
      // 着法终点的加密偏移值
      nDstOff = (uint8_t) (Square54Plus221((uint8_t) xqfhd.szTag[15]) * nSrcOff);
      // 注释的加密偏移值
      nCommentOff = ((uint8_t) xqfhd.szTag[12] * 256 + (uint8_t) xqfhd.szTag[13]) % 32000 + 767;
      // 基本掩码
      nArg0 = xqfhd.szTag[3];
      // 密钥 = 前段密钥 | (后段密钥 & 基本掩码)
       for (i = 0; i < 4; i ++) {
        nArgs[i] = xqfhd.szTag[8 + i] | (xqfhd.szTag[12 + i] & nArg0);
      }
      // 密钥流 = 密钥 & 密钥流掩码
      for (i = 0; i < 32; i ++) {
        nEncStream[i] = (uint8_t) (nArgs[i % 4] & cszEncStreamMask[i]);
      }
    }
    nEncIndex = 0;

    // 记录棋谱信息
    if (xqfhd.szEvent[0] == 0) {
      GetXqfString(pgn.szEvent, xqfhd.szTitle);
    } else {
      GetXqfString(pgn.szEvent, xqfhd.szEvent);
    }
    GetXqfString(pgn.szDate, xqfhd.szDate);
    GetXqfString(pgn.szSite, xqfhd.szSite);
    GetXqfString(pgn.szRed, xqfhd.szRed);
    GetXqfString(pgn.szBlack, xqfhd.szBlack);
    pgn.nResult = cnResultTrans[(int) xqfhd.szResult[3]];

    if (xqfhd.szSetUp[0] < 2) {
      // 如果是开局或者全局,那么直接设置起始局面
      pgn.posStart.FromFen(cszStartFen);
    } else {
      // 如果是中局或者排局,那么根据"xqfhd.szPiecePos[32]"的内容摆放局面
      // 当版本号达到12时,还要进一步解密局面初始位置
      if (nXqfVer < 12) {
        for (i = 0; i < 32; i ++) {
          nPiecePos[i] = (uint8_t) (xqfhd.szPiecePos[i] - nPieceOff);
        }
      } else {
        for (i = 0; i < 32; i ++) {
          nPiecePos[(nPieceOff + 1 + i) % 32] = (uint8_t) (xqfhd.szPiecePos[i] - nPieceOff);
        }
      }
      // 把"nPiecePos[32]"的数据放到"PositionStruct"中
      pgn.posStart.ClearBoard();
      for (i = 0; i < 32; i ++) {
        if (nPiecePos[i] < 90) {
          pgn.posStart.AddPiece(cucsqXqf2Square[nPiecePos[i]], cpcXqf2Piece[i]);
        }
      }
      pgn.posStart.SetIrrev();
    }
    pos = pgn.posStart;

    bHasNext = true;
    while (bHasNext && pgn.nMaxMove < MAX_MOVE_LEN) {
      // 读取着法记录
      if (nXqfVer < 11) {
        fread(&xqfmv, sizeof(xqfmv), 1, fp);
        fread(&nCommentLen, sizeof(int), 1, fp);
        if ((xqfmv.ucTag & 0xf0) == 0) {
          bHasNext = false;
        }
      } else {
        ReadAndDecrypt(fp, &xqfmv, sizeof(xqfmv), nEncStream, nEncIndex);
        if ((xqfmv.ucTag & 0x20) != 0) {
          ReadAndDecrypt(fp, &nCommentLen, sizeof(int), nEncStream, nEncIndex);
          nCommentLen -= nCommentOff;
        } else {
          nCommentLen = 0;
        }
        if ((xqfmv.ucTag & 0x80) == 0) {
          bHasNext = false;
        }
      }
      if (pgn.nMaxMove > 0) {
        // 记录着法
        mv = MOVE(cucsqXqf2Square[(uint8_t) (xqfmv.ucSrc - 24 - nSrcOff)], cucsqXqf2Square[(uint8_t) (xqfmv.ucDst - 32 - nDstOff)]);
        if (pgn.nMaxMove == 1) {
          if ((pgn.posStart.ucpcSquares[SRC(mv)] & 32) != 0) {
            pgn.posStart.ChangeSide();
            pos.ChangeSide();
          }
        }
        if (xqfhd.szSetUp[0] < 2 && pgn.nMaxMove <= 20) {
          dwFileMove[pgn.nMaxMove - 1] = Move2File(mv, pos);
        }
        TryMove(pos, nStatus, mv);
        pgn.wmvMoveTable[pgn.nMaxMove] = mv;
        if (pos.nMoveNum == MAX_MOVE_NUM) {
          pos.SetIrrev();
        }
      }
      if (nCommentLen > 0) {
        pgn.szCommentTable[pgn.nMaxMove] = new char[nCommentLen + 1];
        ReadAndDecrypt(fp, pgn.szCommentTable[pgn.nMaxMove], nCommentLen, nEncStream, nEncIndex);
        pgn.szCommentTable[pgn.nMaxMove][nCommentLen] = '\0';
      }
      pgn.nMaxMove ++;
    }
    pgn.nMaxMove --;

    // 解析ECCO
    if (xqfhd.szSetUp[0] < 2) {
      if (pgn.nMaxMove < 20) {
        dwFileMove[pgn.nMaxMove] = 0;
      }
      if (EccoApi.Available()) {
        dwEccoIndex = EccoApi.EccoIndex((const char *) dwFileMove);
        strcpy(pgn.szEcco, (const char *) &dwEccoIndex);
        strcpy(pgn.szOpen, EccoApi.EccoOpening(dwEccoIndex));
        strcpy(pgn.szVar, EccoApi.EccoVariation(dwEccoIndex));
      }
    }

    fclose(fp);
    return (pgn.Write(szPgnFile) ? XQF2PGN_OK : XQF2PGN_ERROR_CREATE);
  } else {
    fclose(fp);
    return XQF2PGN_ERROR_FORMAT;
  }
}
Beispiel #16
0
// 零窗口搜索
int SearchCut ( int depth, int beta, bool bNoNull = false ) {
	int mv, vl;
	int bmv = 0;
	int bvl = - MATE_VALUE;
	MoveSortStruct mvsort;

	if ( TimeOut() ) { // 超时
		return bvl;
	}

	// 无害裁剪
	vl = HarmlessPruning ();
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 置换裁剪
	vl = QueryValueInHashTable ( depth, beta - 1, beta );
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 达到极限深度
	if ( depth <= 0 ) {
		return SearchQuiesc ( beta - 1, beta );
	}

	// 空着裁剪 : 大切に
	if ( !bNoNull && pos.checked == false && pos.NullOkay() ) {
		pos.NullMove ();
		vl = - SearchCut ( depth - NULL_DEPTH - 1, beta, true );
		pos.UndoNullMove ();
		if ( TimeOut() ) { // 超时
			return bvl;
		}

		if ( vl >= beta ) {
			if ( pos.NullSafe() ) {
				InsertInfoToHashTable ( MAX(depth, NULL_DEPTH + 1), 0, vl, HASH_TYPE_BETA );
				return vl;
			}
			else if ( SearchCut(depth - NULL_DEPTH, beta, true) >= beta ) {
				InsertInfoToHashTable ( MAX(depth, NULL_DEPTH), 0, vl, HASH_TYPE_BETA );
				return vl;
			}
		}
	}

	// 生成着法
	int nMoveNum = mvsort.InitMove ();
	Search.nNode ++;

	// 大搜索
	while ( (mv = mvsort.NextMove()) != 0 ) {
		pos.MakeMove ( mv );
		int newDepth = ( pos.checked || nMoveNum == 1 ) ? depth : depth - 1;
		vl = - SearchCut ( newDepth, 1 - beta );
		pos.UndoMakeMove ();

		if ( TimeOut() ) { // 超时
			return bvl;
		}

		// 边界
		if ( vl > bvl ) {
			bvl = vl;
			bmv = mv;
			if ( bvl >= beta ) {
				Search.nBeta ++;
				InsertInfoToHashTable ( depth, bmv, bvl, HASH_TYPE_BETA );
				InsertHistoryTable ( bmv, depth );
				return bvl;
			}
		}
	}

	// 最后
	InsertInfoToHashTable ( depth, bmv, bvl, HASH_TYPE_ALPHA );
	return bvl;
}
Beispiel #17
0
// Alpha-Beta 搜索
int SearchAlphaBeta ( int depth, int alpha, int beta ) {
	int mv, vl;
	int bmv[nBest], bvl[nBest];
	ClearBmvBvl ( bmv, bvl );
	int hash_type = HASH_TYPE_ALPHA;
	MoveSortStruct mvsort;

	if ( TimeOut() ) { // 超时
		return bvl[0];
	}

	// 无害裁剪
	vl = HarmlessPruning ();
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 置换裁剪
	vl = QueryValueInHashTable ( depth, alpha, beta );
	if ( vl > - MATE_VALUE ) {
		Search.bmv[0] = QueryMoveInHashTable ( depth, alpha, beta );
		Search.bvl[0] = vl;
		return vl;
	}

	// 达到极限深度
	if ( depth <= 0 ) {
		return SearchQuiesc ( alpha, beta );
	}

	// 内部迭代加深启发
	if ( depth > 2 ) {
		mv = QueryMoveInHashTableWithoutLimit ();
		if ( mv == 0 ) {
			SearchAlphaBeta ( depth / 2, alpha, beta );
			if ( TimeOut() ) { // 超时
				return bvl[0];
			}
		}
	}

	// 生成着法
	int nMoveNum = mvsort.InitMove ();
	Search.nNode ++;

	// 大搜索
	while ( (mv = mvsort.NextMove()) != 0 ) {
		pos.MakeMove ( mv );
		int newDepth = ( pos.checked || nMoveNum == 1 ) ? depth : depth - 1;
		vl = - SearchCut ( newDepth, - alpha );
		if ( vl > alpha && vl < beta ) {
			vl = - SearchAlphaBeta ( newDepth, -beta, -alpha );
		}
		pos.UndoMakeMove ();

		if ( TimeOut() ) {
			return bvl[0];
		}

		UpdateBmvBvl ( bmv, bvl, mv, vl );

		if ( bvl[0] >= beta ) {
			Search.nBeta ++;
			hash_type = HASH_TYPE_BETA;
			break;
		}
		if ( bvl[0] > alpha ) {
			alpha = bvl[0];
			hash_type = HASH_TYPE_PV;
		}
	}

	// 最后
	InsertInfoToHashTable ( depth, bmv[0], bvl[0], hash_type );
	InsertHistoryTable ( bmv[0], depth );
	CopyBmvBvl ( Search.bmv, Search.bvl, bmv, bvl );
	return bvl[0];
}
Beispiel #18
0
// 静态搜索例程
static int SearchQuiesc(PositionStruct &pos, int vlAlpha, int vlBeta) {
  int vlBest, vl, mv;
  bool bInCheck;
  MoveSortStruct MoveSort;  
  // 静态搜索例程包括以下几个步骤:
  Search2.nAllNodes ++;

  // 1. 无害裁剪;
  vl = HarmlessPruning(pos, vlBeta);
  if (vl > -MATE_VALUE) {
    return vl;
  }

#ifdef HASH_QUIESC
  // 3. 置换裁剪;
  vl = ProbeHashQ(pos, vlAlpha, vlBeta);
  if (Search.bUseHash && vl > -MATE_VALUE) {
    return vl;
  }
#endif

  // 4. 达到极限深度,直接返回评价值;
  if (pos.nDistance == LIMIT_DEPTH) {
    return Evaluate(pos, vlAlpha, vlBeta);
  }
  __ASSERT(Search.pos.nDistance < LIMIT_DEPTH);

  // 5. 初始化;
  vlBest = -MATE_VALUE;
  bInCheck = (pos.LastMove().ChkChs > 0);

  // 6. 对于被将军的局面,生成全部着法;
  if (bInCheck) {
    MoveSort.InitAll(pos);
  } else {

    // 7. 对于未被将军的局面,在生成着法前首先尝试空着(空着启发),即对局面作评价;
    vl = Evaluate(pos, vlAlpha, vlBeta);
    __ASSERT_BOUND(1 - WIN_VALUE, vl, WIN_VALUE - 1);
    __ASSERT(vl > vlBest);
    if (vl >= vlBeta) {
#ifdef HASH_QUIESC
      RecordHashQ(pos, vl, MATE_VALUE);
#endif
      return vl;
    }
    vlBest = vl;
    vlAlpha = MAX(vl, vlAlpha);

    // 8. 对于未被将军的局面,生成并排序所有吃子着法(MVV(LVA)启发);
    MoveSort.InitQuiesc(pos);
  }

  // 9. 用Alpha-Beta算法搜索这些着法;
  while ((mv = MoveSort.NextQuiesc(bInCheck)) != 0) {
    __ASSERT(bInCheck || pos.ucpcSquares[DST(mv)] > 0);
    if (pos.MakeMove(mv)) {
      vl = -SearchQuiesc(pos, -vlBeta, -vlAlpha);
      pos.UndoMakeMove();
      if (vl > vlBest) {
        if (vl >= vlBeta) {
#ifdef HASH_QUIESC
          if (vl > -WIN_VALUE && vl < WIN_VALUE) {
            RecordHashQ(pos, vl, MATE_VALUE);
          }
#endif
          return vl;
        }
        vlBest = vl;
        vlAlpha = MAX(vl, vlAlpha);
      }
    }
  }

  // 10. 返回分值。
  if (vlBest == -MATE_VALUE) {
    __ASSERT(pos.IsMate());
    return pos.nDistance - MATE_VALUE;
  } else {
#ifdef HASH_QUIESC
    if (vlBest > -WIN_VALUE && vlBest < WIN_VALUE) {
      RecordHashQ(pos, vlBest > vlAlpha ? vlBest : -MATE_VALUE, vlBest);
    }
#endif
    return vlBest;
  }
}
Beispiel #19
0
// 调整型局面评价函数
inline int Evaluate(const PositionStruct &pos, int vlAlpha, int vlBeta) {
  int vl;
  vl = Search.bKnowledge ? pos.Evaluate(vlAlpha, vlBeta) : pos.Material();
  return vl == pos.DrawValue() ? vl - 1 : vl;
}
Beispiel #20
0
// 初始化棋局
static void Startup(void) {
  pos.Startup();
  Xqwl.sqSelected = Xqwl.mvLast = 0;
}
Beispiel #21
0
// 主搜索函数
int SearchMain ( void ) {
	// 特殊情况
	MoveSortStruct mvsort;
	int nMoveNum = mvsort.InitMove ();
	if ( nMoveNum == 0 ) { // 无着法
		printf ( "bestmove a0a1 resign\n" );
		fflush ( stdout );
		return 0;
	}
	else if ( nMoveNum == 1 ) { // 唯一着法
		printf ( "bestmove %s\n", MoveIntToStr(mvsort.move[0]).c_str() );
		fflush ( stdout );
		return mvsort.move[0];
	}
	if ( pos.IsDraw() ) { // 和局
		printf ( "bestmove a0a1 draw\n" );
		fflush ( stdout );
		// 注意不要return
	}

	// 初始化
	ClearHistoryTable ();
	ClearHashTable ();
	ClearHashTableQC ();
	InitBeginTime ( SEARCH_TOTAL_TIME );

	// 迭代加深搜索
	printf("depth   time    nNode  rBeta");
	for ( int i = 0; i < 3; i ++ ) {
		printf("   bvl[%d]  bmv[%d]", i, i);
	}
	printf("\n");
	fflush ( stdout );
	int lastbvl[nBest], lastbmv[nBest];
	ClearBmvBvl ( lastbmv, lastbvl );
	for ( int depth = 1; /*depth <= ?*/; depth ++ ) {
		InitBeginTime ( THIS_SEARCH_TIME );
		InitSearchStruct ();
		SearchAlphaBeta ( depth, - MATE_VALUE, MATE_VALUE );

		if ( TimeOut() ) {
			CopyBmvBvl ( Search.bmv, Search.bvl, lastbmv, lastbvl );
			break;
		}
		else {
			CopyBmvBvl ( lastbmv, lastbvl, Search.bmv, Search.bvl );
		}

		printf( "%5d  %.2fs  %7d    %2.0f%%", depth, TimeCost(SEARCH_TOTAL_TIME), Search.nNode, 100.0*Search.nBeta/Search.nNode);
		for ( int i = 0; i < 3; i ++ ) {
			printf("   %6d    %s", Search.bvl[i], MoveIntToStr(Search.bmv[i]).c_str());
		}
		printf("\n");
		fflush ( stdout );

		if ( Search.bvl[0] <= - BAN_VALUE || Search.bvl[0] >= BAN_VALUE) {
			break;
		}
		if ( Search.bvl[1] <= - BAN_VALUE || Search.bmv[1] == 0 ) {
			break;
		}
	}
	printf ( "totaltime: %.2fs\n", TimeCost(SEARCH_TOTAL_TIME) );
	fflush ( stdout );

	// 输出最优着法
	if ( Search.bmv[0] == 0 || Search.bvl[0] <= - BAN_VALUE ) {
		printf ( "bestmove a0a1 resign\n" ); // 认输
		fflush ( stdout );
		return 0;
	}
	else {
		printf ( "bestmove %s\n", MoveIntToStr(Search.bmv[0]).c_str() );
		fflush ( stdout );
		return Search.bmv[0];
	}
}
Beispiel #22
0
// 静态搜索
int SearchQuiesc ( int alpha, int beta ) {
	int mv, vl;
	int bvl = - MATE_VALUE;
	MoveSortStruct mvsort;

	if ( TimeOut() ) { // 超时
		return bvl;
	}

	// 无害裁剪
	vl = HarmlessPruning ();
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 置换裁剪
	vl = QueryValueInHashTableQC ( alpha, beta );
	if ( vl > - MATE_VALUE ) {
		return vl;
	}

	// 生成着法
	if ( pos.checked ) {
		mvsort.InitMove ();
	}
	else {
		bvl = pos.Evaluate ();
		if ( bvl >= beta ) {
			InsertInfoToHashTableQC ( bvl, MATE_VALUE );
			return bvl;
		}
		if ( bvl > alpha ) {
			alpha = bvl;
		}
		mvsort.InitGoodCapMove ();
	}

	// 大搜索
	while ( (mv = mvsort.NextMove()) != 0 ) {
		pos.MakeMove (mv);
		vl = - SearchQuiesc ( -beta, -alpha );
		pos.UndoMakeMove ();

		if ( TimeOut() ) { // 超时
			return bvl;
		}

		if ( vl > bvl ) {
			bvl = vl;
			if ( bvl >= beta ) {
				if ( bvl > - BAN_VALUE && bvl < BAN_VALUE ) {
					InsertInfoToHashTableQC ( bvl, MATE_VALUE );
				}
				return vl;
			}
			if ( bvl > alpha ) {
				alpha = bvl;
			}
		}
	}

	// 最后
	if ( bvl > - BAN_VALUE && bvl < BAN_VALUE ) {
		InsertInfoToHashTableQC ( bvl, bvl );
	}
	return bvl;
}