void Checkers::play() {
	currentPlayer = 1;
	std::vector<int> MoveStart;
	std::vector<int> MoveEnd;
	std::vector<int> AIMove;
	currentState.Display();
	while (terminalStatus != true) {
		//currentState.Display();
		switch (currentPlayer) {
		case 1:
			MoveStart = player1.getmoveStart();
			MoveEnd = player1.getmoveEnd(MoveStart);
			while (!LegalMove(MoveStart, MoveEnd, currentState) && getPiece(MoveStart) == 1 && !checkEmpty(MoveEnd)) {
				MoveStart = player1.getmoveStart();
				//swap values to match how table is laid out
				std::swap(MoveStart[0], MoveStart[1]);
				MoveEnd = player1.getmoveEnd(MoveStart);
				std::swap(MoveEnd[0], MoveEnd[1]);
			}
			currentState.FullMove(MoveStart, MoveEnd);
			//std::cout << MoveStart[0] << " " << MoveStart[1] << " to " << MoveEnd[0] << " " << MoveEnd[1] << std::endl;
			currentPlayer = 2;
			break;
		case 2:
			AIMove = player2.getmove(currentState);
			//swap locations when moving, due to way Move is written to work with human inputs.
			MoveStart = { AIMove[1],AIMove[0] };
			MoveEnd = { AIMove[3],AIMove[2] };
			currentState.FullMove(MoveStart, MoveEnd);
			currentPlayer = 1;
			break; 		
		}
		//std::cout << MoveStart[0] << " " << MoveStart[1] << " to " << MoveEnd[0] << " " << MoveEnd[1] << std::endl;
		//currentState.FullMove(MoveStart, MoveEnd);
	}

}
Beispiel #2
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;
}
Beispiel #3
0
// 吃子着法生成器,按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;
}
Beispiel #4
0
static int negascout(struct SearchData *sd,
                     int alpha,
                     int beta,
                     const int depth,
                     int node_type
#if MP
                     ,int exclusiveP
#endif /* MP  */
                    ) {
    struct Position *p = sd->position;
    struct SearchStatus *st;
    int best = -INF;
    int bestm = M_NONE;
    int tmp;
    int talpha;
    int incheck;
    int lmove;
    int move;
    int extend = 0;
    int threat = FALSE;
    int reduce_extensions;
    int next_type;
    int was_futile = FALSE;
#if FUTILITY
    int is_futile;
    int optimistic = 0;
#endif

#if MP
    int deferred_cnt = 0;
    int deferred_list[MAX_DEFERRED];
    int deferred_depth[MAX_DEFERRED];
#endif

    EnterNode(sd);

    Nodes++;

    /* check for search termination */
    if (sd->master && TerminateSearch(sd)) {
        AbortSearch = TRUE;
        goto EXIT;
    }

    /* max search depth reached */
    if (sd->ply >= MaxDepth) goto EXIT;

    /*
     * Check for insufficent material or theoretical draw.
     */

    if ( /* InsufMat(p) || CheckDraw(p) || */  Repeated(p, FALSE)) {
        best = 0;
        goto EXIT;
    }

    /*
     * check extension
     */

    incheck = InCheck(p, p->turn);
    if (incheck && p->material[p->turn] > 0) {
        extend += CheckExtend(p);
        ChkExt++;
    }

    /*
     * Check the hashtable
     */

    st = sd->current;

    HTry++;
#if MP
    switch (ProbeHT(p->hkey, &tmp, depth, &(st->st_hashmove), &threat, sd->ply,
                    exclusiveP, sd->localHashTable))
#else
    switch (ProbeHT(p->hkey, &tmp, depth, &(st->st_hashmove), &threat, sd->ply))
#endif /* MP */
    {
    case ExactScore:
        HHit++;
        best = tmp;
        goto EXIT;
    case UpperBound:
        if (tmp <= alpha) {
            HHit++;
            best = tmp;
            goto EXIT;
        }
        break;
    case LowerBound:
        if (tmp >= beta) {
            HHit++;
            best = tmp;
            goto EXIT;
        }
        break;
    case Useless:
        threat = !incheck && MateThreat(p, OPP(p->turn));
        break;
#if MP
    case OnEvaluation:
        best = -ON_EVALUATION;
        goto EXIT;
#endif
    }

    /*
     * Probe EGTB
     */

    if (depth > EGTBDepth && ProbeEGTB(p, &tmp, sd->ply)) {
        best = tmp;
        goto EXIT;
    }

    /*
     * Probe recognizers
     */

    switch (ProbeRecognizer(p, &tmp)) {
    case ExactScore:
        best = tmp;
        goto EXIT;
    case LowerBound:
        if (tmp >= beta) {
            best = tmp;
            goto EXIT;
        }
        break;
    case UpperBound:
        if (tmp <= alpha) {
            best = tmp;
            goto EXIT;
        }
        break;
    }

#if NULLMOVE

    /*
     * Null move search.
     * See Christian Donninger, "Null Move and Deep Search"
     * ICCA Journal Volume 16, No. 3, pp. 137-143
     */

    if (!incheck && node_type == CutNode && !threat) {
        int next_depth;
        int nms;

        next_depth = depth - ReduceNullMove;

        if (next_depth > 0) {
            next_depth = depth - ReduceNullMoveDeep;
        }

        DoNull(p);
        if (next_depth < 0) {
            nms = -quies(sd, -beta, -beta+1, 0);
        } else {
#if MP
            nms = -negascout(sd, -beta, -beta+1, next_depth, AllNode, 0);
#else
            nms = -negascout(sd, -beta, -beta+1, next_depth, AllNode);
#endif
        }
        UndoNull(p);

        if (AbortSearch) goto EXIT;
        if (nms >= beta) {
            if (p->nonPawn[p->turn] >= Value[Queen]) {
                best = nms;
                goto EXIT;
            } else {
                if (next_depth < 0) {
                    nms = quies(sd, beta-1, beta, 0);
                } else {
#if MP
                    nms = negascout(sd, beta-1, beta, next_depth, CutNodeNoNull,
                                    0);
#else
                    nms = negascout(sd, beta-1, beta, next_depth,
                                    CutNodeNoNull);
#endif
                }

                if (nms >= beta) {
                    best = nms;
                    goto EXIT;
                } else {
                    extend += ExtendZugzwang;
                    ZZExt++;
                }
            }
        } else if (nms <= -CMLIMIT) {
            threat = TRUE;
        }
    }
#endif /* NULLMOVE */

    lmove = (p->actLog-1)->gl_Move;
    reduce_extensions = (sd->ply > 2*sd->depth);
    talpha = alpha;

    switch (node_type) {
    case AllNode:
        next_type = CutNode;
        break;
    case CutNode:
    case CutNodeNoNull:
        next_type = AllNode;
        break;
    default:
        next_type = PVNode;
        break;
    }

#if FUTILITY
    is_futile = !incheck && !threat && alpha < CMLIMIT && alpha > -CMLIMIT;
    if (is_futile) {
        if (p->turn == White) {
            optimistic = MaterialBalance(p) + MaxPos;
        } else {
            optimistic = -MaterialBalance(p) + MaxPos;
        }
    }
#endif /* FUTILITY */

    /*
     * Internal iterative deepening. If we do not have a move, we try
     * a shallow search to find a good candidate.
     */

    if (depth > 2*OnePly && ((alpha + 1) != beta) && !LegalMove(p, st->st_hashmove)) {
        int useless;
#if MP
        useless = negascout(sd, alpha, beta, depth-2*OnePly, PVNode, 0);
#else
        useless = negascout(sd, alpha, beta, depth-2*OnePly, PVNode);
#endif
        st->st_hashmove = sd->pv_save[sd->ply+1];
    }

    /*
     * Search all legal moves
     */

    while ((move = incheck ? NextEvasion(sd) : NextMove(sd)) != M_NONE) {
        int next_depth = extend;

        if (move & M_CANY && !MayCastle(p, move)) continue;

        /*
         * recapture extension
         */

        if ((move & M_CAPTURE) && (lmove & M_CAPTURE) &&
                M_TO(move) == M_TO(lmove) &&
                IsRecapture(p->piece[M_TO(move)], (p->actLog-1)->gl_Piece)) {
            RCExt += 1;
            next_depth += ExtendRecapture[TYPE(p->piece[M_TO(move)])];
        }

        /*
         * passed pawn push extension
         */

        if (TYPE(p->piece[M_FROM(move)]) == Pawn &&
                p->nonPawn[OPP(p->turn)] <= Value[Queen]) {

            int to = M_TO(move);

            if (((p->turn == White && to >= a7)
                    || (p->turn == Black && to <= h2))
                    && IsPassed(p, to, p->turn) && SwapOff(p, move) >= 0) {
                next_depth += ExtendPassedPawn;
                PPExt += 1;
            }
        }

        /*
         * limit extensions to sensible range.
         */

        if (reduce_extensions) next_depth /= 2;

        next_depth += depth - OnePly;

#if FUTILITY

        /*
         * Futility cutoffs
         */

        if (is_futile) {
            if (next_depth < 0 && !IsCheckingMove(p, move)) {
                tmp = optimistic + ScoreMove(p, move);
                if (tmp <= alpha) {
                    if (tmp > best) {
                        best = tmp;
                        bestm = move;
                        was_futile = TRUE;
                    }
                    continue;
                }
            }
#if EXTENDED_FUTILITY

            /*
             * Extended futility cutoffs and limited razoring.
             * See Ernst A. Heinz, "Extended Futility Pruning"
             * ICCA Journal Volume 21, No. 2, pp 75-83
             */

            else if (next_depth >= 0 && next_depth < OnePly
                     && !IsCheckingMove(p, move)) {
                tmp = optimistic + ScoreMove(p, move) + (3*Value[Pawn]);
                if (tmp <= alpha) {
                    if (tmp > best) {
                        best = tmp;
                        bestm = move;
                        was_futile = TRUE;
                    }
                    continue;
                }
            }
#if RAZORING
            else if (next_depth >= OnePly && next_depth < 2*OnePly
                     && !IsCheckingMove(p, move)) {
                tmp = optimistic + ScoreMove(p, move) + (6*Value[Pawn]);
                if (tmp <= alpha) {
                    next_depth -= OnePly;
                }
            }
#endif /* RAZORING */
#endif /* EXTENDED_FUTILITY */
        }

#endif /* FUTILITY */

        DoMove(p, move);
        if (InCheck(p, OPP(p->turn))) {
            UndoMove(p, move);
        } else {
            /*
             * Check extension
             */

            if (p->material[p->turn] > 0 && InCheck(p, p->turn)) {
                next_depth += (reduce_extensions) ?
                              ExtendInCheck>>1 : ExtendInCheck;
            }

            /*
             * Recursively search this position. If depth is exhausted, use
             * quies, otherwise use negascout.
             */

            if (next_depth < 0) {
                tmp = -quies(sd, -beta, -talpha, 0);
            } else if (bestm != M_NONE && !was_futile) {
#if MP
                tmp = -negascout(sd, -talpha-1, -talpha, next_depth, next_type,
                                 bestm != M_NONE);
                if (tmp != ON_EVALUATION && tmp > talpha && tmp < beta) {
                    tmp = -negascout(sd, -beta, -tmp, next_depth,
                                     node_type == PVNode ? PVNode : AllNode,
                                     bestm != M_NONE);
                }
#else
                tmp = -negascout(sd, -talpha-1, -talpha, next_depth, next_type);
                if (tmp > talpha && tmp < beta) {
                    tmp = -negascout(sd, -beta, -tmp, next_depth,
                                     node_type == PVNode ? PVNode : AllNode);
                }
#endif /* MP */
            } else {
#if MP
                tmp = -negascout(sd, -beta, -talpha, next_depth, next_type,
                                 bestm != M_NONE);
#else
                tmp = -negascout(sd, -beta, -talpha, next_depth, next_type);
#endif /* MP */
            }

            UndoMove(p, move);

            if (AbortSearch) goto EXIT;

#if MP
            if (tmp == ON_EVALUATION) {

                /*
                 * This child is ON_EVALUATION. Remember move and
                 * depth.
                 */

                deferred_list[deferred_cnt] = move;
                deferred_depth[deferred_cnt] = next_depth;
                deferred_cnt++;

            } else {
#endif /* MP */

                /*
                 * beta cutoff, enter move in Killer/Countermove table
                 */

                if (tmp >= beta) {
                    if (!(move & M_TACTICAL)) {
                        PutKiller(sd, move);
                        sd->counterTab[p->turn][lmove & 4095] = move;
                    }
                    StoreResult(sd, tmp, alpha, beta, move, depth, threat);
                    best = tmp;
                    goto EXIT;
                }

                /*
                 * Improvement on best move to date
                 */

                if (tmp > best) {
                    best = tmp;
                    bestm = move;
                    was_futile = FALSE;

                    if (best > talpha) {
                        talpha = best;
                    }
                }

                next_type = CutNode;
#if MP
            }
#endif /* MP */
        }
    }