//---------------------------------------------------------------------------------------- public static int Enroques(cPosicion pos, cMov[] mlist, int mPos, color us, cInfoJaque ci, enroque Cr, bool Checks, bool Chess960) { bool KingSide = (Cr==cEnroque.OO_BLANCAS||Cr==cEnroque.OO_NEGRAS); if(pos.CanNotEnroque(Cr)||0==pos.PosibleEnrocar(Cr)) return mPos; sq kfrom = pos.GetRey(us); sq rfrom = pos.CasillaTorreEnroque(Cr); sq kto = cTypes.CasillaProxima(us, KingSide ? cCasilla.G1 : cCasilla.C1); bitbrd enemies = pos.PiezasColor(cTypes.Contrario(us)); sq K = Chess960 ? kto>kfrom ? cCasilla.OESTE : cCasilla.ESTE : KingSide ? cCasilla.OESTE : cCasilla.ESTE; for(sq s = kto; s!=kfrom; s+=K) if((pos.AtaquesA(s)&enemies)!=0) return mPos; if(Chess960&&(cBitBoard.AtaquesPieza(kto, pos.Piezas()^cBitBoard.m_nCasillas[rfrom], cPieza.TORRE)&pos.PiezasColor(cTypes.Contrario(us), cPieza.TORRE, cPieza.DAMA))!=0) return mPos; mov m = cTypes.CreaMov(kfrom, rfrom, cMovType.ENROQUE, cPieza.CABALLO); if(Checks&&!pos.IsJaque(m, ci)) return mPos; mlist[mPos++].m=m; return mPos; }
public static val search(cPosicion pos, cStackMov[] ss, int ssPos, val alpha, val beta, ply depth, bool cutNode, NodeType NT, bool SpNode) { bool RootNode = (NT == cTipoNodo.RAIZ); bool PvNode = (NT == cTipoNodo.PV || NT == cTipoNodo.RAIZ); mov[] quietsSearched = new mov[64]; cPosInfo st = new cPosInfo(); cTablaHashStruct tte; cSplitPoint splitPoint = null; hash posKey = 0; mov ttMove, move, excludedMove, bestMove; ply ext, newDepth, predictedDepth; val bestValue, value, ttValue, eval, nullValue, futilityValue; bool inCheck, givesCheck, pvMove, singularExtensionNode, improving; bool captureOrPromotion, dangerous, doFullDepthSearch; int moveCount = 0, quietCount = 0; cThread thisThread = pos.ThreadActive(); inCheck = pos.Jaques() != 0; if (SpNode) { splitPoint = ss[ssPos].splitPoint; bestMove = splitPoint.bestMove; bestValue = splitPoint.bestValue; tte = null; ttMove = excludedMove = cMovType.MOV_NAN; ttValue = cValoresJuego.NAN; goto moves_loop; } moveCount = quietCount = 0; bestValue = -cValoresJuego.INFINITO; ss[ssPos].currentMove = ss[ssPos].ttMove = ss[ssPos + 1].excludedMove = bestMove = cMovType.MOV_NAN; ss[ssPos].ply = ss[ssPos - 1].ply + 1; ss[ssPos + 1].skipNullMove = 0; ss[ssPos + 1].reduction = cPly.DEPTH_ZERO; ss[ssPos + 2].killers0 = ss[ssPos + 2].killers1 = cMovType.MOV_NAN; if (PvNode && thisThread.m_nMaxPly < ss[ssPos].ply) thisThread.m_nMaxPly = ss[ssPos].ply; if (!RootNode) { if (Signals.STOP || pos.IsTablas() || ss[ssPos].ply > cSearch.MAX_PLY) return ss[ssPos].ply > cSearch.MAX_PLY && !inCheck ? cEval.Eval(pos) : DrawValue[pos.ColorMueve()]; alpha = Math.Max(cTypes.MateEnVs(ss[ssPos].ply), alpha); beta = Math.Min(cTypes.MateEn(ss[ssPos].ply + 1), beta); if (alpha >= beta) return alpha; } excludedMove = ss[ssPos].excludedMove; posKey = excludedMove != 0 ? pos.GetClaveHashExclusion() : pos.ClaveHash(); tte = cMotor.m_TablaHash.Buscar(posKey); ss[ssPos].ttMove = ttMove = RootNode ? RootMoves[PVIdx].m_PV[0] : tte != null ? tte.GetMove() : cMovType.MOV_NAN; ttValue = (tte != null) ? value_from_tt(tte.GetValue(), ss[ssPos].ply) : cValoresJuego.NAN; if (!RootNode && tte != null && tte.GetDepth() >= depth && ttValue != cValoresJuego.NAN && (PvNode ? tte.GetBound() == cBordes.BOUND_EXACT : ttValue >= beta ? (tte.GetBound() & cBordes.BOUND_LOWER) != 0 : (tte.GetBound() & cBordes.BOUND_UPPER) != 0)) { ss[ssPos].currentMove = ttMove; if (ttValue >= beta && ttMove != 0 && !pos.IsCapturaOrPromocion(ttMove) && !inCheck) update_stats(pos, ss, ssPos, ttMove, depth, null, 0); return ttValue; } if (inCheck) { ss[ssPos].staticEval = eval = cValoresJuego.NAN; goto moves_loop; } else if (tte != null) { if ((ss[ssPos].staticEval = eval = tte.GetValueEval()) == cValoresJuego.NAN) eval = ss[ssPos].staticEval = cEval.Eval(pos); if (ttValue != cValoresJuego.NAN) if ((tte.GetBound() & (ttValue > eval ? cBordes.BOUND_LOWER : cBordes.BOUND_UPPER)) != 0) eval = ttValue; } else { eval = ss[ssPos].staticEval = cEval.Eval(pos); cMotor.m_TablaHash.Save(posKey, cValoresJuego.NAN, cBordes.BOUND_NONE, cPly.DEPTH_NONE, cMovType.MOV_NAN, ss[ssPos].staticEval); } if (0 == pos.GetTipoPiezaCapturada() && ss[ssPos].staticEval != cValoresJuego.NAN && ss[ssPos - 1].staticEval != cValoresJuego.NAN && (move = ss[ssPos - 1].currentMove) != cMovType.MOV_NULO && cTypes.TipoMovimiento(move) == cMovType.NORMAL) { sq to = cTypes.GetToCasilla(move); Gains.Fill(pos.GetPieza(to), to, -ss[ssPos - 1].staticEval - ss[ssPos].staticEval); } if (!PvNode && depth < 4 * cPly.ONE_PLY && eval + razor_margin(depth) <= beta && ttMove == cMovType.MOV_NAN && Math.Abs(beta) < cValoresJuego.MATE_MAXIMO && !pos.IsPeonOn7(pos.ColorMueve()) ) { if (depth <= cPly.ONE_PLY && eval + razor_margin(3 * cPly.ONE_PLY) <= alpha) return qsearch(pos, ss, ssPos, alpha, beta, cPly.DEPTH_ZERO, cTipoNodo.NO_PV, false); val ralpha = alpha - razor_margin(depth); val v = qsearch(pos, ss, ssPos, ralpha, ralpha + 1, cPly.DEPTH_ZERO, cTipoNodo.NO_PV, false); if (v <= ralpha) return v; } if (!PvNode && 0 == ss[ssPos].skipNullMove && depth < 7 * cPly.ONE_PLY && eval - futility_margin(depth) >= beta && Math.Abs(beta) < cValoresJuego.MATE_MAXIMO && Math.Abs(eval) < cValoresJuego.GANA && pos.MaterialPieza(pos.ColorMueve()) != 0) return eval - futility_margin(depth); if (!PvNode && 0 == ss[ssPos].skipNullMove && depth >= 2 * cPly.ONE_PLY && eval >= beta && Math.Abs(beta) < cValoresJuego.MATE_MAXIMO && pos.MaterialPieza(pos.ColorMueve()) != 0) { ss[ssPos].currentMove = cMovType.MOV_NULO; ply R = 3 * cPly.ONE_PLY + depth / 4 + (eval - beta) / cValoresJuego.PEON_MJ * cPly.ONE_PLY; pos.DoNullMov(st); ss[ssPos + 1].skipNullMove = 1; nullValue = depth - R < cPly.ONE_PLY ? -qsearch(pos, ss, ssPos + 1, -beta, -beta + 1, cPly.DEPTH_ZERO, cTipoNodo.NO_PV, false) : -search(pos, ss, ssPos + 1, -beta, -beta + 1, depth - R, !cutNode, cTipoNodo.NO_PV, false); ss[ssPos + 1].skipNullMove = 0; pos.undo_null_move(); if (nullValue >= beta) { if (nullValue >= cValoresJuego.MATE_MAXIMO) nullValue = beta; if (depth < 12 * cPly.ONE_PLY) return nullValue; ss[ssPos].skipNullMove = 1; val v = depth - R < cPly.ONE_PLY ? qsearch(pos, ss, ssPos, beta - 1, beta, cPly.DEPTH_ZERO, cTipoNodo.NO_PV, false) : search(pos, ss, ssPos, beta - 1, beta, depth - R, false, cTipoNodo.NO_PV, false); ss[ssPos].skipNullMove = 0; if (v >= beta) return nullValue; } } if (!PvNode && depth >= 5 * cPly.ONE_PLY && 0 == ss[ssPos].skipNullMove && Math.Abs(beta) < cValoresJuego.MATE_MAXIMO) { val rbeta = Math.Min(beta + 200, cValoresJuego.INFINITO); ply rdepth = depth - 4 * cPly.ONE_PLY; cMovOrder mp2 = new cMovOrder(pos, ttMove, History, pos.GetTipoPiezaCapturada()); cInfoJaque ci2 = new cInfoJaque(pos); while ((move = mp2.SiguienteMovimientoEnFalso()) != cMovType.MOV_NAN) if (pos.IsLegalMov(move, ci2.m_Clavadas)) { ss[ssPos].currentMove = move; pos.DoMov(move, st, ci2, pos.IsJaque(move, ci2)); value = -search(pos, ss, ssPos + 1, -rbeta, -rbeta + 1, rdepth, !cutNode, cTipoNodo.NO_PV, false); pos.DesMov(move); if (value >= rbeta) return value; } } if (depth >= (PvNode ? 5 * cPly.ONE_PLY : 8 * cPly.ONE_PLY) && 0 == ttMove && (PvNode || (ss[ssPos].staticEval + 256 >= beta))) { ply d = depth - 2 * cPly.ONE_PLY - (PvNode ? cPly.DEPTH_ZERO : depth / 4); ss[ssPos].skipNullMove = 1; search(pos, ss, ssPos, alpha, beta, d, true, PvNode ? cTipoNodo.PV : cTipoNodo.NO_PV, false); ss[ssPos].skipNullMove = 0; tte = cMotor.m_TablaHash.Buscar(posKey); ttMove = (tte != null) ? tte.GetMove() : cMovType.MOV_NAN; } moves_loop: sq prevMoveSq = cTypes.GetToCasilla(ss[ssPos - 1].currentMove); mov[] countermoves = { Countermoves[pos.GetPieza(prevMoveSq)][prevMoveSq].m_Key1, Countermoves[pos.GetPieza(prevMoveSq)][prevMoveSq].m_Key2 }; sq prevOwnMoveSq = cTypes.GetToCasilla(ss[ssPos - 2].currentMove); mov[] followupmoves = {Followupmoves[pos.GetPieza(prevOwnMoveSq)][prevOwnMoveSq].m_Key1, Followupmoves[pos.GetPieza(prevOwnMoveSq)][prevOwnMoveSq].m_Key2 }; cMovOrder mp = new cMovOrder(pos, ttMove, depth, History, countermoves, followupmoves, ss[ssPos]); cInfoJaque ci = new cInfoJaque(pos); value = bestValue; improving = ss[ssPos].staticEval >= ss[ssPos - 2].staticEval || ss[ssPos].staticEval == cValoresJuego.NAN || ss[ssPos - 2].staticEval == cValoresJuego.NAN; singularExtensionNode = !RootNode && !SpNode && depth >= 8 * cPly.ONE_PLY && ttMove != cMovType.MOV_NAN && 0 == excludedMove && (tte.GetBound() & cBordes.BOUND_LOWER) != 0 && tte.GetDepth() >= depth - 3 * cPly.ONE_PLY; while ((move = (SpNode ? mp.SiguienteMovimiento() : mp.SiguienteMovimientoEnFalso())) != cMovType.MOV_NAN) { if (move == excludedMove) continue; if (RootNode && (Buscar(RootMoves, PVIdx, RootMoves.Count, move) == -1)) continue; if (SpNode) { if (!pos.IsLegalMov(move, ci.m_Clavadas)) continue; moveCount = ++splitPoint.moveCount; splitPoint.mutex.Liberar(); } else ++moveCount; if (RootNode) { Signals.FIRST_MOVE = (moveCount == 1); } ext = cPly.DEPTH_ZERO; captureOrPromotion = pos.IsCapturaOrPromocion(move); givesCheck = cTypes.TipoMovimiento(move) == cMovType.NORMAL && 0 == ci.m_Candidatas ? (ci.m_Jaque[cTypes.TipoPieza(pos.GetPieza(cTypes.GetFromCasilla(move)))] & cBitBoard.m_nCasillas[cTypes.GetToCasilla(move)]) != 0 : pos.IsJaque(move, ci); dangerous = givesCheck || cTypes.TipoMovimiento(move) != cMovType.NORMAL || pos.IsPeonAvanzado(move); if (givesCheck && pos.SEEReducido(move) >= cValoresJuego.CERO) ext = cPly.ONE_PLY; if (singularExtensionNode && move == ttMove && 0 == ext && pos.IsLegalMov(move, ci.m_Clavadas) && Math.Abs(ttValue) < cValoresJuego.GANA) { val rBeta = ttValue - depth; ss[ssPos].excludedMove = move; ss[ssPos].skipNullMove = 1; value = search(pos, ss, ssPos, rBeta - 1, rBeta, depth / 2, cutNode, cTipoNodo.NO_PV, false); ss[ssPos].skipNullMove = 0; ss[ssPos].excludedMove = cMovType.MOV_NAN; if (value < rBeta) ext = cPly.ONE_PLY; } newDepth = depth - cPly.ONE_PLY + ext; if (!PvNode && !captureOrPromotion && !inCheck && !dangerous && bestValue > cValoresJuego.MATE_MAXIMO_VS) { if (depth < 16 * cPly.ONE_PLY && moveCount >= FutilityMoveCounts[improving ? 1 : 0][depth]) { if (SpNode) splitPoint.mutex.Bloquear(); continue; } predictedDepth = newDepth - reduction(improving ? 1 : 0, depth, moveCount, PvNode ? 1 : 0); if (predictedDepth < 7 * cPly.ONE_PLY) { futilityValue = ss[ssPos].staticEval + futility_margin(predictedDepth) + 128 + Gains[pos.GetPiezaMovida(move)][cTypes.GetToCasilla(move)]; if (futilityValue <= alpha) { bestValue = Math.Max(bestValue, futilityValue); if (SpNode) { splitPoint.mutex.Bloquear(); if (bestValue > splitPoint.bestValue) splitPoint.bestValue = bestValue; } continue; } } if (predictedDepth < 4 * cPly.ONE_PLY && pos.SEEReducido(move) < cValoresJuego.CERO) { if (SpNode) splitPoint.mutex.Bloquear(); continue; } } if (!RootNode && !SpNode && !pos.IsLegalMov(move, ci.m_Clavadas)) { moveCount--; continue; } pvMove = PvNode && moveCount == 1; ss[ssPos].currentMove = move; if (!SpNode && !captureOrPromotion && quietCount < 64) quietsSearched[quietCount++] = move; pos.DoMov(move, st, ci, givesCheck); if (depth >= 3 * cPly.ONE_PLY && !pvMove && !captureOrPromotion && move != ttMove && move != ss[ssPos].killers0 && move != ss[ssPos].killers1) { ss[ssPos].reduction = reduction(improving ? 1 : 0, depth, moveCount, PvNode ? 1 : 0); if (!PvNode && cutNode) ss[ssPos].reduction += cPly.ONE_PLY; else if (History[pos.GetPieza(cTypes.GetToCasilla(move))][cTypes.GetToCasilla(move)] < 0) ss[ssPos].reduction += cPly.ONE_PLY / 2; if (move == countermoves[0] || move == countermoves[1]) ss[ssPos].reduction = Math.Max(cPly.DEPTH_ZERO, ss[ssPos].reduction - cPly.ONE_PLY); ply d = Math.Max(newDepth - ss[ssPos].reduction, cPly.ONE_PLY); if (SpNode) alpha = splitPoint.alpha; value = -search(pos, ss, ssPos + 1, -(alpha + 1), -alpha, d, true, cTipoNodo.NO_PV, false); if (value > alpha && ss[ssPos].reduction >= 4 * cPly.ONE_PLY) { ply d2 = Math.Max(newDepth - 2 * cPly.ONE_PLY, cPly.ONE_PLY); value = -search(pos, ss, ssPos + 1, -(alpha + 1), -alpha, d2, true, cTipoNodo.NO_PV, false); } doFullDepthSearch = (value > alpha && ss[ssPos].reduction != cPly.DEPTH_ZERO); ss[ssPos].reduction = cPly.DEPTH_ZERO; } else doFullDepthSearch = !pvMove; if (doFullDepthSearch) { if (SpNode) alpha = splitPoint.alpha; value = newDepth < cPly.ONE_PLY ? givesCheck ? -qsearch(pos, ss, ssPos + 1, -(alpha + 1), -alpha, cPly.DEPTH_ZERO, cTipoNodo.NO_PV, true) : -qsearch(pos, ss, ssPos + 1, -(alpha + 1), -alpha, cPly.DEPTH_ZERO, cTipoNodo.NO_PV, false) : -search(pos, ss, ssPos + 1, -(alpha + 1), -alpha, newDepth, !cutNode, cTipoNodo.NO_PV, false); } if (PvNode && (pvMove || (value > alpha && (RootNode || value < beta)))) value = newDepth < cPly.ONE_PLY ? givesCheck ? -qsearch(pos, ss, ssPos + 1, -beta, -alpha, cPly.DEPTH_ZERO, cTipoNodo.PV, true) : -qsearch(pos, ss, ssPos + 1, -beta, -alpha, cPly.DEPTH_ZERO, cTipoNodo.PV, false) : -search(pos, ss, ssPos + 1, -beta, -alpha, newDepth, false, cTipoNodo.PV, false); pos.DesMov(move); if (SpNode) { splitPoint.mutex.Bloquear(); bestValue = splitPoint.bestValue; alpha = splitPoint.alpha; } if (Signals.STOP || thisThread.IsCorte()) return cValoresJuego.CERO; if (RootNode) { int rmPos = Buscar(RootMoves, 0, RootMoves.Count, move); cRaizMov rm = RootMoves[rmPos]; if (pvMove || value > alpha) { rm.m_nVal = value; rm.extract_pv_from_tt(pos); if (!pvMove) ++BestMoveChanges; } else rm.m_nVal = -cValoresJuego.INFINITO; } if (value > bestValue) { bestValue = SpNode ? splitPoint.bestValue = value : value; if (value > alpha) { bestMove = SpNode ? splitPoint.bestMove = move : move; if (PvNode && value < beta) alpha = SpNode ? splitPoint.alpha = value : value; else { if (SpNode) splitPoint.m_bCorte = true; break; } } } if (!SpNode && cMotor.m_Threads.Count >= 2 && depth >= cMotor.m_Threads.minimumSplitDepth && (null == thisThread.m_SplitPointActivo || !thisThread.m_SplitPointActivo.allSlavesSearching) && thisThread.m_nSplitPointSize < cThreadBase.MAX_SPLITPOINTS_PER_THREAD) { thisThread.Split(pos, ss, ssPos, alpha, beta, ref bestValue, ref bestMove, depth, moveCount, mp, NT, cutNode); if (Signals.STOP || thisThread.IsCorte()) return cValoresJuego.CERO; if (bestValue >= beta) break; } } if (SpNode) return bestValue; if (0 == moveCount) bestValue = excludedMove != 0 ? alpha : inCheck ? cTypes.MateEnVs(ss[ssPos].ply) : DrawValue[pos.ColorMueve()]; else if (bestValue >= beta && !pos.IsCapturaOrPromocion(bestMove) && !inCheck) update_stats(pos, ss, ssPos, bestMove, depth, quietsSearched, quietCount - 1); cMotor.m_TablaHash.Save(posKey, value_to_tt(bestValue, ss[ssPos].ply), bestValue >= beta ? cBordes.BOUND_LOWER : PvNode && bestMove != 0 ? cBordes.BOUND_EXACT : cBordes.BOUND_UPPER, depth, bestMove, ss[ssPos].staticEval); return bestValue; }
public static val qsearch(cPosicion pos, cStackMov[] ss, int ssPos, val alpha, val beta, ply depth, NodeType NT, bool InCheck) { bool PvNode = (NT == cTipoNodo.PV); cPosInfo st = null; cTablaHashStruct tte; hash posKey; mov ttMove, move, bestMove; val bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha = 0; bool givesCheck, evasionPrunable; ply ttDepth; if (PvNode) oldAlpha = alpha; ss[ssPos].currentMove = bestMove = cMovType.MOV_NAN; ss[ssPos].ply = ss[ssPos - 1].ply + 1; if (pos.IsTablas() || ss[ssPos].ply > cSearch.MAX_PLY) return ss[ssPos].ply > cSearch.MAX_PLY && !InCheck ? cEval.Eval(pos) : DrawValue[pos.ColorMueve()]; ttDepth = ((InCheck || depth >= cPly.DEPTH_QS_CHECKS) ? cPly.DEPTH_QS_CHECKS : cPly.DEPTH_QS_NO_CHECKS); posKey = pos.ClaveHash(); tte = cMotor.m_TablaHash.Buscar(posKey); ttMove = (tte != null ? tte.GetMove() : cMovType.MOV_NAN); ttValue = tte != null ? value_from_tt(tte.GetValue(), ss[ssPos].ply) : cValoresJuego.NAN; if (tte != null && tte.GetDepth() >= ttDepth && ttValue != cValoresJuego.NAN && (PvNode ? tte.GetBound() == cBordes.BOUND_EXACT : (ttValue >= beta) ? (tte.GetBound() & cBordes.BOUND_LOWER) != 0 : (tte.GetBound() & cBordes.BOUND_UPPER) != 0)) { ss[ssPos].currentMove = ttMove; return ttValue; } if (InCheck) { ss[ssPos].staticEval = cValoresJuego.NAN; bestValue = futilityBase = -cValoresJuego.INFINITO; } else { if (tte != null) { if ((ss[ssPos].staticEval = bestValue = tte.GetValueEval()) == cValoresJuego.NAN) ss[ssPos].staticEval = bestValue = cEval.Eval(pos); if (ttValue != cValoresJuego.NAN) if ((tte.GetBound() & (ttValue > bestValue ? cBordes.BOUND_LOWER : cBordes.BOUND_UPPER)) != 0) bestValue = ttValue; } else ss[ssPos].staticEval = bestValue = cEval.Eval(pos); if (bestValue >= beta) { if (tte == null) cMotor.m_TablaHash.Save(pos.ClaveHash(), value_to_tt(bestValue, ss[ssPos].ply), cBordes.BOUND_LOWER, cPly.DEPTH_NONE, cMovType.MOV_NAN, ss[ssPos].staticEval); return bestValue; } if (PvNode && bestValue > alpha) alpha = bestValue; futilityBase = bestValue + 128; } cMovOrder mp = new cMovOrder(pos, ttMove, depth, History, cTypes.GetToCasilla(ss[ssPos - 1].currentMove)); cInfoJaque ci = new cInfoJaque(pos); st = new cPosInfo(); while ((move = mp.SiguienteMovimientoEnFalso()) != cMovType.MOV_NAN) { givesCheck = cTypes.TipoMovimiento(move) == cMovType.NORMAL && 0 == ci.m_Candidatas ? (ci.m_Jaque[cTypes.TipoPieza(pos.GetPieza(cTypes.GetFromCasilla(move)))] & cBitBoard.m_nCasillas[cTypes.GetToCasilla(move)]) != 0 : pos.IsJaque(move, ci); if (!PvNode && !InCheck && !givesCheck && move != ttMove && futilityBase > -cValoresJuego.GANA && !pos.IsPeonAvanzado(move)) { futilityValue = futilityBase + cPosicion.m_nValPieza[cFaseJuego.FASE_FINAL][pos.GetPieza(cTypes.GetToCasilla(move))]; if (futilityValue < beta) { bestValue = Math.Max(bestValue, futilityValue); continue; } if (futilityBase < beta && pos.SEE(move) <= cValoresJuego.CERO) { bestValue = Math.Max(bestValue, futilityBase); continue; } } evasionPrunable = InCheck && bestValue > cValoresJuego.MATE_MAXIMO_VS && !pos.IsCaptura(move) && 0 == pos.CanEnroque(pos.ColorMueve()); if (!PvNode && (!InCheck || evasionPrunable) && move != ttMove && cTypes.TipoMovimiento(move) != cMovType.PROMOCION && pos.SEEReducido(move) < cValoresJuego.CERO) continue; if (!pos.IsLegalMov(move, ci.m_Clavadas)) continue; ss[ssPos].currentMove = move; pos.DoMov(move, st, ci, givesCheck); value = givesCheck ? -qsearch(pos, ss, ssPos + 1, -beta, -alpha, depth - cPly.ONE_PLY, NT, true) : -qsearch(pos, ss, ssPos + 1, -beta, -alpha, depth - cPly.ONE_PLY, NT, false); pos.DesMov(move); if (value > bestValue) { bestValue = value; if (value > alpha) { if (PvNode && value < beta) { alpha = value; bestMove = move; } else { cMotor.m_TablaHash.Save(posKey, value_to_tt(value, ss[ssPos].ply), cBordes.BOUND_LOWER, ttDepth, move, ss[ssPos].staticEval); return value; } } } } if (InCheck && bestValue == -cValoresJuego.INFINITO) return cTypes.MateEnVs(ss[ssPos].ply); cMotor.m_TablaHash.Save(posKey, value_to_tt(bestValue, ss[ssPos].ply), PvNode && bestValue > oldAlpha ? cBordes.BOUND_EXACT : cBordes.BOUND_UPPER, ttDepth, bestMove, ss[ssPos].staticEval); return bestValue; }
//---------------------------------------------------------------------------------------- public static int ToDO(cPosicion pos, cMov[] mlist, int mPos, bitbrd target, color us, type Type, cInfoJaque ci) { bool Checks = Type==cMovType.QUIET_CHECKS; mPos=Peones(pos, mlist, mPos, target, ci, us, Type); mPos=Piezas(pos, mlist, mPos, us, target, ci, cPieza.CABALLO, Checks); mPos=Piezas(pos, mlist, mPos, us, target, ci, cPieza.ALFIL, Checks); mPos=Piezas(pos, mlist, mPos, us, target, ci, cPieza.TORRE, Checks); mPos=Piezas(pos, mlist, mPos, us, target, ci, cPieza.DAMA, Checks); if(Type!=cMovType.QUIET_CHECKS&&Type!=cMovType.EVASIONS) { sq ksq = pos.GetRey(us); bitbrd b = pos.attacks_from_square_piecetype(ksq, cPieza.REY)⌖ while(b!=0) mlist[mPos++].m=cTypes.CreaMov(ksq, cBitBoard.GetLSB(ref b)); } if(Type!=cMovType.CAPTURES&&Type!=cMovType.EVASIONS&&pos.CanEnroque(us)!=0) { if (pos.IsChess960() != false) { mPos=Enroques(pos, mlist, mPos, us, ci, (new cEnroque(us, cEnroque.LADO_REY)).m_Tipo, Checks, true); mPos=Enroques(pos, mlist, mPos, us, ci, (new cEnroque(us, cEnroque.LADO_DAMA)).m_Tipo, Checks, true); } else { mPos=Enroques(pos, mlist, mPos, us, ci, (new cEnroque(us, cEnroque.LADO_REY)).m_Tipo, Checks, false); mPos=Enroques(pos, mlist, mPos, us, ci, (new cEnroque(us, cEnroque.LADO_DAMA)).m_Tipo, Checks, false); } } return mPos; }
//---------------------------------------------------------------------------------------- public static int Promocion(cMov[] mlist, int mPos, bitbrd pawnsOn7, bitbrd target, cInfoJaque ci, type Type, sq Delta) { bitbrd b = cBitBoard.Desplazamiento(pawnsOn7, Delta)⌖ while(b!=0) { sq to = cBitBoard.GetLSB(ref b); if(Type==cMovType.CAPTURES||Type==cMovType.EVASIONS||Type==cMovType.NON_EVASIONS) mlist[mPos++].m=cTypes.CreaMov(to-Delta, to, cMovType.PROMOCION, cPieza.DAMA); if(Type==cMovType.QUIETS||Type==cMovType.EVASIONS||Type==cMovType.NON_EVASIONS) { mlist[mPos++].m=cTypes.CreaMov(to-Delta, to, cMovType.PROMOCION, cPieza.TORRE); mlist[mPos++].m=cTypes.CreaMov(to-Delta, to, cMovType.PROMOCION, cPieza.ALFIL); mlist[mPos++].m=cTypes.CreaMov(to-Delta, to, cMovType.PROMOCION, cPieza.CABALLO); } if(Type==cMovType.QUIET_CHECKS&&(cBitBoard.m_Ataques[cPieza.CABALLO_BLANCO][to]&cBitBoard.m_nCasillas[ci.m_SqRey])!=0) mlist[mPos++].m=cTypes.CreaMov(to-Delta, to, cMovType.PROMOCION, cPieza.CABALLO); } return mPos; }
//---------------------------------------------------------------------------------------- public static int Piezas(cPosicion pos, cMov[] mlist, int mPos, color us, bitbrd target, cInfoJaque ci, type Pt, bool Checks) { sq[] pieceList = pos.GetList(us, Pt); int pl = 0; for(sq from = pieceList[pl]; from!=cCasilla.NONE; from=pieceList[++pl]) { if(Checks) { if((Pt==cPieza.ALFIL||Pt==cPieza.TORRE||Pt==cPieza.DAMA) &&0==(cBitBoard.m_PseudoAtaques[Pt][from]&target&ci.m_Jaque[Pt])) continue; if(ci.m_Candidatas!=0&&(ci.m_Candidatas&cBitBoard.m_nCasillas[from])!=0) continue; } bitbrd b = pos.attacks_from_square_piecetype(from, Pt)⌖ if(Checks) b&=ci.m_Jaque[Pt]; while(b!=0) mlist[mPos++].m=cTypes.CreaMov(from, cBitBoard.GetLSB(ref b)); } return mPos; }
//---------------------------------------------------------------------------------------- public static int Peones(cPosicion pos, cMov[] mlist, int mPos, bitbrd target, cInfoJaque ci, color colr, type Type) { color colorVS = (colr==cColor.BLANCO ? cColor.NEGRO : cColor.BLANCO); bitbrd TRank8BB = (colr==cColor.BLANCO ? cBitBoard.F8 : cBitBoard.F1); bitbrd TRank7BB = (colr==cColor.BLANCO ? cBitBoard.F7 : cBitBoard.F2); bitbrd TRank3BB = (colr==cColor.BLANCO ? cBitBoard.F3 : cBitBoard.F6); sq Up = (colr==cColor.BLANCO ? cCasilla.NORTE : cCasilla.SUR); sq Right = (colr==cColor.BLANCO ? cCasilla.NORTE_ESTE : cCasilla.SUR_OESTE); sq Left = (colr==cColor.BLANCO ? cCasilla.NORTE_OESTE : cCasilla.SUR_ESTE); bitbrd b1, b2, dc1, dc2, emptySquares = 0; bitbrd pawnsOn7 = pos.PiezasColor(colr, cPieza.PEON)&TRank7BB; bitbrd pawnsNotOn7 = pos.PiezasColor(colr, cPieza.PEON)&~TRank7BB; bitbrd enemies = (Type==cMovType.EVASIONS ? pos.PiezasColor(colorVS)&target : Type==cMovType.CAPTURES ? target : pos.PiezasColor(colorVS)); if(Type!=cMovType.CAPTURES) { emptySquares=(Type==cMovType.QUIETS||Type==cMovType.QUIET_CHECKS ? target : ~pos.Piezas()); b1=cBitBoard.Desplazamiento(pawnsNotOn7, Up)&emptySquares; b2=cBitBoard.Desplazamiento(b1&TRank3BB, Up)&emptySquares; if(Type==cMovType.EVASIONS) { b1&=target; b2&=target; } if(Type==cMovType.QUIET_CHECKS) { b1&=pos.AtaquesDePeon(ci.m_SqRey, colorVS); b2&=pos.AtaquesDePeon(ci.m_SqRey, colorVS); if((pawnsNotOn7&ci.m_Candidatas)!=0) { dc1=cBitBoard.Desplazamiento(pawnsNotOn7&ci.m_Candidatas, Up)&emptySquares&~cBitBoard.GetColumnaSq(ci.m_SqRey); dc2=cBitBoard.Desplazamiento(dc1&TRank3BB, Up)&emptySquares; b1|=dc1; b2|=dc2; } } while(b1!=0) { sq to = cBitBoard.GetLSB(ref b1); mlist[mPos++].m=cTypes.CreaMov(to-Up, to); } while(b2!=0) { sq to = cBitBoard.GetLSB(ref b2); mlist[mPos++].m=cTypes.CreaMov(to-Up-Up, to); } } if(pawnsOn7!=0&&(Type!=cMovType.EVASIONS||(target&TRank8BB)!=0)) { if(Type==cMovType.CAPTURES) emptySquares=~pos.Piezas(); if(Type==cMovType.EVASIONS) emptySquares&=target; mPos=Promocion(mlist, mPos, pawnsOn7, enemies, ci, Type, Right); mPos=Promocion(mlist, mPos, pawnsOn7, enemies, ci, Type, Left); mPos=Promocion(mlist, mPos, pawnsOn7, emptySquares, ci, Type, Up); } if(Type==cMovType.CAPTURES||Type==cMovType.EVASIONS||Type==cMovType.NON_EVASIONS) { b1=cBitBoard.Desplazamiento(pawnsNotOn7, Right)&enemies; b2=cBitBoard.Desplazamiento(pawnsNotOn7, Left)&enemies; while(b1!=0) { sq to = cBitBoard.GetLSB(ref b1); mlist[mPos++].m=cTypes.CreaMov(to-Right, to); } while(b2!=0) { sq to = cBitBoard.GetLSB(ref b2); mlist[mPos++].m=cTypes.CreaMov(to-Left, to); } if(pos.CasillaEnPaso()!=cCasilla.NONE) { if(Type==cMovType.EVASIONS&&(target&cBitBoard.m_nCasillas[(pos.CasillaEnPaso()-Up)])==0) return mPos; b1=pawnsNotOn7&pos.AtaquesDePeon(pos.CasillaEnPaso(), colorVS); while(b1!=0) mlist[mPos++].m=cTypes.CreaMov(cBitBoard.GetLSB(ref b1), pos.CasillaEnPaso(), cMovType.ENPASO, cPieza.CABALLO); } } return mPos; }
//---------------------------------------------------------------------------------------- public static int Jaques(cPosicion pos, cMov[] mlist, int mPos) { color us = pos.ColorMueve(); cInfoJaque ci = new cInfoJaque(pos); bitbrd dc = ci.m_Candidatas; while(dc!=0) { sq from = cBitBoard.GetLSB(ref dc); type pt = cTypes.TipoPieza(pos.GetPieza(from)); if(pt==cPieza.PEON) continue; bitbrd b = pos.AtaquesDePieza((pieza)pt, from)&~pos.Piezas(); if(pt==cPieza.REY) b&=~cBitBoard.m_PseudoAtaques[cPieza.DAMA][ci.m_SqRey]; while(b!=0) mlist[mPos++].m=cTypes.CreaMov(from, cBitBoard.GetLSB(ref b)); } return us==cColor.BLANCO ? ToDO(pos, mlist, mPos, ~pos.Piezas(), cColor.BLANCO, cMovType.QUIET_CHECKS, ci) : ToDO(pos, mlist, mPos, ~pos.Piezas(), cColor.NEGRO, cMovType.QUIET_CHECKS, ci); }