|
| 1 | +diff --git a/src/search.cpp b/src/search.cpp |
| 2 | +index 50197f5..eae26de 100644 |
| 3 | +--- a/src/search.cpp |
| 4 | ++++ b/src/search.cpp |
| 5 | +@@ -2599,8 +2599,11 @@ template<NodeType nodeType> |
| 6 | + Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) { |
| 7 | + |
| 8 | + static_assert(nodeType != Root); |
| 9 | ++ //by shashin definitions begin |
| 10 | + const RootShashinState& rootShashinState = shashinManager->getState(); |
| 11 | +- constexpr bool PvNode = nodeType == PV; |
| 12 | ++ const bool isFortressNode = shashinManager->isFortress(pos); |
| 13 | ++ //by shashin definitions end |
| 14 | ++ constexpr bool PvNode = nodeType == PV; |
| 15 | + |
| 16 | + assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); |
| 17 | + assert(PvNode || (alpha == beta - 1)); |
| 18 | +@@ -2659,7 +2662,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 19 | + // Accesso ottimizzato alle variabili di stato |
| 20 | + const bool isStrategical = dynamicDerived.isStrategical; |
| 21 | + const bool isAggressive = dynamicDerived.isAggressive; |
| 22 | +- |
| 23 | ++ // At non-PV nodes we check for an early TT cutoff |
| 24 | + if (!PvNode && is_valid(ttData.value) |
| 25 | + && (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER))) |
| 26 | + { |
| 27 | +@@ -2713,9 +2716,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 28 | + updatedLearning = true; |
| 29 | + return expTTValue; |
| 30 | + } |
| 31 | +- // (Logica Learning per Quiet Kings omessa per brevità, |
| 32 | +- // mantenuta identica al blocco TT se necessario, o saltare allo step successivo) |
| 33 | +- // Qui mantengo il flusso originale per coerenza col tuo file |
| 34 | ++ |
| 35 | + if (staticState.legalMoveCount < 35 && std::abs(expTTValue) > 60) |
| 36 | + { |
| 37 | + const bool areQuietKings = |
| 38 | +@@ -2749,12 +2750,14 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 39 | + |
| 40 | + if (ss->ttHit) |
| 41 | + { |
| 42 | ++ // Never assume anything about values stored in TT |
| 43 | + unadjustedStaticEval = ttData.eval; |
| 44 | + if (!is_valid(unadjustedStaticEval)) |
| 45 | + unadjustedStaticEval = evaluate(pos); |
| 46 | + ss->staticEval = bestValue = |
| 47 | + to_corrected_static_eval(unadjustedStaticEval, correctionValue); |
| 48 | + |
| 49 | ++ // ttValue can be used as a better position evaluation |
| 50 | + if (is_valid(ttData.value) && !is_decisive(ttData.value) |
| 51 | + && (ttData.bound & (ttData.value > bestValue ? BOUND_LOWER : BOUND_UPPER))) |
| 52 | + bestValue = ttData.value; |
| 53 | +@@ -2791,7 +2794,6 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 54 | + futilityBase = ss->staticEval + 351; |
| 55 | + |
| 56 | + // --- SHASHIN OPTIMIZATION 1: FUTILITY BASE (Outside Loop) --- |
| 57 | +- // Correggiamo il valore ridicolo (+3) con qualcosa di sensato. |
| 58 | + if (dynamicDerived.isHighTal) |
| 59 | + futilityBase += 30; |
| 60 | + else if (isStrategical) |
| 61 | +@@ -2802,6 +2804,9 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 62 | + const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory}; |
| 63 | + Square prevSq = ((ss - 1)->currentMove).is_ok() ? ((ss - 1)->currentMove).to_sq() : SQ_NONE; |
| 64 | + |
| 65 | ++ // Initialize a MovePicker object for the current position, and prepare to search |
| 66 | ++ // the moves. We presently use two stages of move generator in quiescence search: |
| 67 | ++ // captures, or evasions only when in check. |
| 68 | + MovePicker mp(pos, ttData.move, DEPTH_QS, &mainHistory, &lowPlyHistory, &captureHistory, |
| 69 | + contHist, &sharedHistory, ss->ply); |
| 70 | + |
| 71 | +@@ -2814,25 +2819,43 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 72 | + moveCountThreshold = 1; |
| 73 | + if (staticState.kingDanger) |
| 74 | + moveCountThreshold++; |
| 75 | +- if (MoveConfig::isFortress) |
| 76 | ++ // Use isFortressNode (defined at top) instead of MoveConfig |
| 77 | ++ if (isFortressNode) |
| 78 | + moveCountThreshold++; |
| 79 | + |
| 80 | + // B) SEE Margin |
| 81 | +- int seeMargin = -80; // Standard Stockfish |
| 82 | ++ // --- SHASHIN QSEARCH OPTIMIZATION --- |
| 83 | ++ int seeMargin = -80; // Default Stockfish |
| 84 | + if (isAggressive) |
| 85 | +- seeMargin -= 18; // Tal: -98 |
| 86 | ++ { |
| 87 | ++ // Tal: Permette sacrifici speculativi se il Re è in pericolo |
| 88 | ++ seeMargin = staticState.kingDanger ? -150 : -105; |
| 89 | ++ } |
| 90 | + else if (isStrategical) |
| 91 | +- seeMargin += 18; // Petrosian: -62 |
| 92 | ++ { |
| 93 | ++ // Petrosian: Richiede scambi solidi, non tollera perdite di materiale |
| 94 | ++ seeMargin = -35; |
| 95 | ++ } |
| 96 | ++ // Use isFortressNode (defined at top) |
| 97 | ++ else if (isFortressNode) |
| 98 | ++ { |
| 99 | ++ seeMargin = -10; |
| 100 | ++ } |
| 101 | ++ // ------------------------------------ |
| 102 | + |
| 103 | + // C) Volatility Check (Flag) |
| 104 | + const bool extremelyVolatile = dynamicDerived.isHighTal && staticState.kingDanger; |
| 105 | + // ---------------------------------------------------------------------- |
| 106 | + |
| 107 | +- // Step 5. Loop through all pseudo-legal moves |
| 108 | ++ // Step 5. Loop through all pseudo-legal moves until no moves remain or a beta |
| 109 | ++ // cutoff occurs. |
| 110 | + while ((move = mp.next_move()) != Move::none()) |
| 111 | + { |
| 112 | + assert(move.is_ok()); |
| 113 | + |
| 114 | ++ // FIX 2: Definiamo movedPiece qui perché serve per il controllo tattico Tal |
| 115 | ++ Piece movedPiece = pos.moved_piece(move); |
| 116 | ++ |
| 117 | + if (!pos.legal(move)) |
| 118 | + continue; |
| 119 | + |
| 120 | +@@ -2841,61 +2864,60 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 121 | + |
| 122 | + moveCount++; |
| 123 | + |
| 124 | +- // Step 6. Pruning (Optimized) |
| 125 | ++ // Step 6. Pruning |
| 126 | + if (!is_loss(bestValue)) |
| 127 | + { |
| 128 | + // Futility pruning and moveCount pruning |
| 129 | + if (!givesCheck && move.to_sq() != prevSq && !is_loss(futilityBase) |
| 130 | + && move.type_of() != PROMOTION) |
| 131 | + { |
| 132 | +- // Use pre-calculated threshold |
| 133 | + if (moveCount > moveCountThreshold) |
| 134 | + continue; |
| 135 | + |
| 136 | + Value futilityValue = futilityBase + PieceValue[pos.piece_on(move.to_sq())]; |
| 137 | ++ |
| 138 | ++ // If static eval + value of piece we are going to capture is |
| 139 | ++ // much lower than alpha, we can prune this move. |
| 140 | + if (futilityValue <= alpha) |
| 141 | + { |
| 142 | + bestValue = std::max(bestValue, futilityValue); |
| 143 | + continue; |
| 144 | + } |
| 145 | + |
| 146 | +- // === PATCH SHASHIN INTELLIGENTE (LOGICA INVERTITA) === |
| 147 | ++ // If static exchange evaluation is low enough |
| 148 | ++ // we can prune this move. |
| 149 | + if (!pos.see_ge(move, alpha - futilityBase)) |
| 150 | + { |
| 151 | +- // Logica tattica (vecchio comportamento) per: |
| 152 | +- // 1. Stili Tal aggressivi |
| 153 | +- // 2. Posizioni tattiche reattive |
| 154 | +- // 3. Pericolo del re (tranne in posizioni strategiche) |
| 155 | +- const bool useTacticalLogic = dynamicDerived.isHighTal |
| 156 | +- || dynamicDerived.isTacticalReactive |
| 157 | +- || (staticState.kingDanger && !isStrategical); |
| 158 | +- |
| 159 | +- if (useTacticalLogic) |
| 160 | ++ const bool riskyTactical = |
| 161 | ++ dynamicDerived.isHighTal || (staticState.kingDanger && !isStrategical); |
| 162 | ++ |
| 163 | ++ if (riskyTactical) |
| 164 | + { |
| 165 | +- // COMPORTAMENTO TATTICO (ShashChess originale) |
| 166 | +- // Permette alla valutazione di scendere per esplorare mosse apparentemente negative |
| 167 | +- // ma potenzialmente vincenti (sacrifici, combinazioni nascoste) |
| 168 | +- bestValue = std::min(alpha, futilityBase); |
| 169 | ++ // Tal: Cerca comunque se non è un disastro totale (-200) |
| 170 | ++ if (!pos.see_ge(move, -200)) |
| 171 | ++ { |
| 172 | ++ bestValue = std::max(bestValue, std::min(alpha, futilityBase)); |
| 173 | ++ continue; |
| 174 | ++ } |
| 175 | + } |
| 176 | + else |
| 177 | + { |
| 178 | +- // COMPORTAMENTO STRATEGICO (patch Stockfish) |
| 179 | +- // Mantiene la valutazione stabile, evitando crolli ingiustificati |
| 180 | +- // Ottimo per posizioni strategiche e partite lunghe |
| 181 | ++ // Strategic/Standard: Fidati della valutazione statica |
| 182 | + bestValue = std::max(bestValue, std::min(alpha, futilityBase)); |
| 183 | ++ continue; |
| 184 | + } |
| 185 | +- continue; |
| 186 | + } |
| 187 | ++ // ============================== |
| 188 | + } |
| 189 | + |
| 190 | + // --- PHASE 4: HYBRID PRUNING OPTIMIZATION --- |
| 191 | ++ // Skip non-captures |
| 192 | + if (!capture) |
| 193 | + { |
| 194 | + if (extremelyVolatile) // Use pre-calculated flag |
| 195 | + { |
| 196 | + // Accesso costoso alla sharedHistory solo qui, nel caso critico |
| 197 | +- int historyScore = |
| 198 | +- sharedHistory.pawn_entry(pos)[pos.moved_piece(move)][move.to_sq()]; |
| 199 | ++ int historyScore = sharedHistory.pawn_entry(pos)[movedPiece][move.to_sq()]; |
| 200 | + |
| 201 | + // Soglia fissa a 4000 (valore di sicurezza per mosse buone) |
| 202 | + if (historyScore < 4000) |
| 203 | +@@ -2903,16 +2925,27 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) |
| 204 | + } |
| 205 | + else |
| 206 | + { |
| 207 | +- // COMPORTAMENTO STANDARD STOCKFISH: |
| 208 | +- // Se non è una cattura e non siamo in 'extreme volatility', potiamo tutto. |
| 209 | ++ // COMPORTAMENTO STANDARD STOCKFISH |
| 210 | + continue; |
| 211 | + } |
| 212 | + } |
| 213 | + // --- END PHASE 4 --- |
| 214 | + |
| 215 | +- // SEE pruning (Use pre-calculated margin) |
| 216 | +- if (!pos.see_ge(move, seeMargin)) |
| 217 | ++ // --- SHASHIN TACTICAL EXCEPTION --- |
| 218 | ++ bool forceCheckSearch = false; |
| 219 | ++ // Se siamo Tal/Aggressive e diamo scacco, ignoriamo il SEE negativo |
| 220 | ++ // (a meno che non sia un suicidio palese della Donna) |
| 221 | ++ if (givesCheck && (isAggressive || dynamicDerived.isHighTal)) |
| 222 | ++ { |
| 223 | ++ if (type_of(movedPiece) != QUEEN || type_of(pos.piece_on(move.to_sq())) != PAWN) |
| 224 | ++ forceCheckSearch = true; |
| 225 | ++ } |
| 226 | ++ |
| 227 | ++ // SEE pruning |
| 228 | ++ // Do not search moves with bad enough SEE values |
| 229 | ++ if (!forceCheckSearch && !pos.see_ge(move, seeMargin)) |
| 230 | + continue; |
| 231 | ++ // ---------------------------------- |
| 232 | + } |
| 233 | + |
| 234 | + |
0 commit comments