int AlphaBeta(board_t *brd, int alpha, int beta, int depth, searchinfo_t *sinfo, int null) { if(depth == 0){ //return Eval(brd); return Quiece(brd, alpha, beta, sinfo); } if(!(sinfo->nodes & 0xfff)) CheckUp(sinfo); sinfo->nodes++; ASSERT(CheckBrd(brd)); // if we are not the root of the tree and we have a repetition // or we exceeded the fifty move rule, then we have a draw and return 0 if((IsRep(brd) || brd->fifty >= 100) && brd->ply) return 0; if(brd->ply >= MAXDEPTH-1) return Eval(brd); // if we are too deep, we return // test if we are in check int check = SqAttacked(brd, LOCATEBIT(brd->bb[brd->side][King]), brd->side^1); if(check) depth++; int score = -INFINITE; int pvMain = NO_MOVE; // check the transposition table if we have searched the current position before // if so, return what we found if(TestHashTable(brd, &pvMain, &score, alpha, beta, depth)) return score; // Before we search, we try how we do if we don't make a move // i.e. make a null move if( null && !check && brd->ply && depth >= 4 && (brd->all[brd->side]^brd->bb[brd->side][Pawn]^brd->bb[brd->side][King]) ) { MakeMoveNull(brd); // We cannot do two null moves in a row so we set the null argument here to false score = -AlphaBeta(brd, -beta, -beta + 1, depth-4, sinfo, false); TakeBackNull(brd); if(sinfo->stop){ return 0; } if(score >= beta){ return beta; } } mlist_t list; int i; int legal = 0; int bestMove = NO_MOVE; int bestScore = -INFINITE; int oldAlpha = alpha; score = -INFINITE; GenMoves(brd, &list); // we tested our transposition table for the best move 'pvMain' // if it exists we will set this move as the first move to be searched if(pvMain != NO_MOVE){ if(MakeMove(brd, pvMain)){ score = -AlphaBeta(brd, -beta, -alpha, depth-1, sinfo, true); TakeBack(brd); bestScore = score; if(score > alpha){ if(score >= beta){ if(!(pvMain & FLAGCAP)){ brd->betaMoves[1][brd->ply] = brd->betaMoves[0][brd->ply]; brd->betaMoves[0][brd->ply] = pvMain; } return beta; } alpha = score; bestMove = pvMain; } } /*/ for(i = 0; i < list.len; i++){ if(list.move[i].move == pvMain){ list.move[i].score = 5000000; break; } }//*/ } for(i = 0; i < list.len; i++) // Loop through all moves { if(sinfo->stop) return 0; SelectNextMove(&list, i); if(!MakeMove(brd, list.move[i].move)) continue; legal++; // we have found a legal move so we need not check for mate afterwards // call AlphaBeta in a negamax fashion score = -AlphaBeta(brd, -beta, -alpha, depth-1, sinfo, true); TakeBack(brd); if(score > bestScore){ bestScore = score; if(score > alpha){ if(score >= beta){ if(legal==1) sinfo->fhf++; // count the number of beta cutoffs searched first sinfo->fh++; // compared to all beta cutoffs (measure of efficiency) if(!(list.move[i].move & FLAGCAP)){ brd->betaMoves[1][brd->ply] = brd->betaMoves[0][brd->ply]; brd->betaMoves[0][brd->ply] = list.move[i].move; } // Store the move in the transposition table as a beta (killer) move StorePvMove(brd, bestMove, depth, beta, HFBETA); return beta; } alpha = score; bestMove = list.move[i].move; } } } if(legal == 0){ // We havn't found a legal move if(check){ // if we are in check it is mate; but we want the shortest path // to it so we'll subtract the path length return -MATE + brd->ply; } return 0; // Stalemate } if(oldAlpha != alpha){ // Store exact (normal) transposition entry StorePvMove(brd, bestMove, depth, bestScore, HFEXACT); } else { // Store alpha cutoff transposition entry StorePvMove(brd, bestMove, depth, alpha, HFALPHA); } return alpha; }
void SelectMove(short side, SelectMove_mode iop) { static short i, tempb, tempc, tempsf, tempst, xside, rpt; static short alpha, beta, score; static struct GameRec *g; short sqking, in_check, blockable; #ifdef BOOKTEST printf("hashbd = %ld (hashkey >> 16)|side = %d\n", hashbd, (hashkey >> 16)|side); #endif flag.timeout = false; flag.back = false; flag.musttimeout = false; xside = side ^ 1; #if ttblsz recycle = (GameCnt % rehash) - rehash; #endif ExaminePosition(side); /* if background mode set to infinite */ if (iop == BACKGROUND_MODE) { background = true; /* if background mode set response time to infinite */ ResponseTime = 9999999; } else { player = side; SetResponseTime(side); } #ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ ShowResponseTime(); ExtraTime = 0; score = ScorePosition(side); #ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ ShowSidetoMove(); #ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ SearchStartStuff(side); #ifdef HISTORY array_zero(history, sizeof_history); #endif FROMsquare = TOsquare = -1; PV = 0; if (iop == FOREGROUND_MODE) hint = 0; /* * If the last move was the hint, select the computed answer to the * hint as first move to examine. */ #if MAXDEPTH > 3 if (GameCnt > 0) { SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0; } else #endif SwagHt = 0; for (i = 0; i < MAXDEPTH; i++) PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0; /* set initial window for search */ if (flag.tsume) { alpha = -(SCORE_LIMIT + 999); beta = SCORE_LIMIT + 999; } else { alpha = score - ((computer == white) ? BAwindow : WAwindow); beta = score + ((computer == white) ? BBwindow : WBwindow); } rpt = 0; TrPnt[1] = 0; root = &Tree[0]; sqking = PieceList[side][0]; in_check = (board[sqking] == king) ? SqAttacked(sqking, side^1, &blockable) : false; MoveList(side, 1, in_check, blockable); for (i = TrPnt[1]; i < TrPnt[2]; i++) { if (!pick(i, TrPnt[2] - 1)) break; } /* Can I get a book move? */ if (flag.regularstart && Book) { flag.timeout = bookflag = OpeningBook(&hint, side); if (TCflag) ResponseTime += ResponseTime; } /* Zero stats for hash table. */ reminus = replus = 0; GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0; globalscore = plyscore = score; Jscore = 0; zwndw = 20; /********************* main loop ********************************/ Sdepth = (MaxSearchDepth < (MINDEPTH - 1)) ? MaxSearchDepth : (MINDEPTH - 1); while (!flag.timeout) { /* go down a level at a time */ Sdepth++; #ifdef NULLMOVE null = 0; PVari = 1; #endif /* terminate search at DepthBeyond ply past goal depth */ if (flag.tsume) DepthBeyond = Sdepth; else #if defined SLOW_CPU DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5); #else DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11); #endif # ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ ShowDepth(' '); /* search at this level returns score of PV */ score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt); /* save PV as killer */ for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i]; /* low search failure re-search with (-inf, score) limits */ if (score < alpha) { reminus++; #ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ ShowDepth('-'); if (TCflag && TCcount < MAXTCCOUNTR) { if (hard_time_limit) ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft; else ExtraTime += (8 * TCleft); TCcount = MAXTCCOUNTR - 1; } score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999), (SCORE_LIMIT + 999), PrVar, &rpt); } /* high search failure re-search with (score, +inf) limits */ else if (score > beta && !(root->flags & exact)) { replus++; #ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ ShowDepth('+'); score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999), (SCORE_LIMIT + 999), PrVar, &rpt); } /**************** out of search ***********************************/ CheckForTimeout(score, globalscore, Jscore, zwndw); /************************ time control ****************************/ /* save PV as killer */ for (i = 1; i <= Sdepth + 1; i++) killr0[i] = PrVar[i]; if (!flag.timeout) Tscore[0] = score; /* if (!flag.timeout) */ /* for (i = TrPnt[1] + 1; i < TrPnt[2]; i++) if (!pick (i, TrPnt[2] - 1)) break; */ /* if done or nothing good to look at quit */ if ((root->flags & exact) || (score < -SCORE_LIMIT)) flag.timeout = true; /* find the next best move put below root */ if (!flag.timeout) { #if !defined NODYNALPHA Jscore = (plyscore + score) >> 1; #endif zwndw = 20 + abs(Jscore / 12); plyscore = score; /* recompute search window */ beta = score + ((computer == white) ? BBwindow : WBwindow); #if !defined NODYNALPHA alpha = ((Jscore < score) ? Jscore : score) - ((computer == white) ? BAwindow : WAwindow) - zwndw; #else alpha = score - ((computer == white) ? BAwindow : WAwindow); #endif } #ifdef QUIETBACKGROUND if (!background) #endif /* QUIETBACKGROUND */ ShowResults(score, PrVar, '.'); }
void GenerateAllMoves(const CHESS_BOARD *pos, MOVELIST *list) { ASSERT(CheckBoard(pos)); list->count = 0; int pce = EMPTY; int side = pos->side; int sq = 0; int t_sq = 0; int pceNum = 0; int dir = 0; int index = 0; int pceIndex = 0; if (side == WHITE) { for (pceNum = 0; pceNum < pos->pieceNum[wP]; ++pceNum) { sq = pos->pList[wP][pceNum]; ASSERT(SqOnBoard(sq)); if (pos->pieces[sq + 10] == EMPTY) { AddWhitePawnMove(pos, sq, sq + 10, list); if (RanksBrd[sq] == RANK_2 && pos->pieces[sq + 20] == EMPTY) { AddQuietMove(pos, MOVE(sq, (sq + 20), EMPTY, EMPTY, MFLAGPS), list); } } if (!SQOFFBOARD(sq + 9) && PieceCol[pos->pieces[sq + 9]] == BLACK) { AddWhitePawnCapMove(pos, sq, sq + 9, pos->pieces[sq + 9], list); } if (!SQOFFBOARD(sq + 11) && PieceCol[pos->pieces[sq + 11]] == BLACK) { AddWhitePawnCapMove(pos, sq, sq + 11, pos->pieces[sq + 11], list); } if (pos->enPas != NO_SQ) { if (sq + 9 == pos->enPas) { AddEnPassantMove(pos, MOVE(sq, sq + 9, EMPTY, EMPTY, MFLAGEP), list); } if (sq + 11 == pos->enPas) { AddEnPassantMove(pos, MOVE(sq, sq + 11, EMPTY, EMPTY, MFLAGEP), list); } } } if (pos->castlePerm & WKCA) { if (pos->pieces[F1] == EMPTY && pos->pieces[G1] == EMPTY) { if (!SqAttacked(E1, BLACK, pos) && !SqAttacked(F1, BLACK, pos)) { AddQuietMove(pos, MOVE(E1, G1, EMPTY, EMPTY, MFLAGCA), list); } } } if (pos->castlePerm & WQCA) { if (pos->pieces[D1] == EMPTY && pos->pieces[C1] == EMPTY && pos->pieces[B1] == EMPTY) { if (!SqAttacked(E1, BLACK, pos) && !SqAttacked(D1, BLACK, pos)) { AddQuietMove(pos, MOVE(E1, C1, EMPTY, EMPTY, MFLAGCA), list); } } } } else { for (pceNum = 0; pceNum < pos->pieceNum[bP]; ++pceNum) { sq = pos->pList[bP][pceNum]; ASSERT(SqOnBoard(sq)); if (pos->pieces[sq - 10] == EMPTY) { AddBlackPawnMove(pos, sq, sq - 10, list); if (RanksBrd[sq] == RANK_7 && pos->pieces[sq - 20] == EMPTY) { AddQuietMove(pos, MOVE(sq, (sq - 20), EMPTY, EMPTY, MFLAGPS), list); } } if (!SQOFFBOARD(sq - 9) && PieceCol[pos->pieces[sq - 9]] == WHITE) { AddBlackPawnCapMove(pos, sq, sq - 9, pos->pieces[sq - 9], list); } if (!SQOFFBOARD(sq - 11) && PieceCol[pos->pieces[sq - 11]] == WHITE) { AddBlackPawnCapMove(pos, sq, sq - 11, pos->pieces[sq - 11], list); } if (pos->enPas != NO_SQ) { if (sq - 9 == pos->enPas) { AddEnPassantMove(pos, MOVE(sq, sq - 9, EMPTY, EMPTY, MFLAGEP), list); } if (sq - 11 == pos->enPas) { AddEnPassantMove(pos, MOVE(sq, sq - 11, EMPTY, EMPTY, MFLAGEP), list); } } } // castling if (pos->castlePerm & BKCA) { if (pos->pieces[F8] == EMPTY && pos->pieces[G8] == EMPTY) { if (!SqAttacked(E8, WHITE, pos) && !SqAttacked(F8, WHITE, pos)) { AddQuietMove(pos, MOVE(E8, G8, EMPTY, EMPTY, MFLAGCA), list); } } } if (pos->castlePerm & BQCA) { if (pos->pieces[D8] == EMPTY && pos->pieces[C8] == EMPTY && pos->pieces[B8] == EMPTY) { if (!SqAttacked(E8, WHITE, pos) && !SqAttacked(D8, WHITE, pos)) { AddQuietMove(pos, MOVE(E8, C8, EMPTY, EMPTY, MFLAGCA), list); } } } } /* Loop for slide pieces */ pceIndex = LoopSlideIndex[side]; pce = LoopSlidePce[pceIndex++]; while (pce != 0) { ASSERT(PieceValid(pce)); for (pceNum = 0; pceNum < pos->pieceNum[pce]; ++pceNum) { sq = pos->pList[pce][pceNum]; ASSERT(SqOnBoard(sq)); for (index = 0; index < NumDir[pce]; ++index) { dir = PceDir[pce][index]; t_sq = sq + dir; while (!SQOFFBOARD(t_sq)) { // BLACK ^ 1 == WHITE WHITE ^ 1 == BLACK if (pos->pieces[t_sq] != EMPTY) { if (PieceCol[pos->pieces[t_sq]] == (side ^ 1)) { AddCaptureMove(pos, MOVE(sq, t_sq, pos->pieces[t_sq], EMPTY, 0), list); } break; } AddQuietMove(pos, MOVE(sq, t_sq, EMPTY, EMPTY, 0), list); t_sq += dir; } } } pce = LoopSlidePce[pceIndex++]; } /* Loop for non slide */ pceIndex = LoopNonSlideIndex[side]; pce = LoopNonSlidePce[pceIndex++]; while (pce != 0) { ASSERT(PieceValid(pce)); for (pceNum = 0; pceNum < pos->pieceNum[pce]; ++pceNum) { sq = pos->pList[pce][pceNum]; ASSERT(SqOnBoard(sq)); for (index = 0; index < NumDir[pce]; ++index) { dir = PceDir[pce][index]; t_sq = sq + dir; if (SQOFFBOARD(t_sq)) { continue; } // BLACK ^ 1 == WHITE WHITE ^ 1 == BLACK if (pos->pieces[t_sq] != EMPTY) { if (PieceCol[pos->pieces[t_sq]] == (side ^ 1)) { AddCaptureMove(pos, MOVE(sq, t_sq, pos->pieces[t_sq], EMPTY, 0), list); } continue; } AddQuietMove(pos, MOVE(sq, t_sq, EMPTY, EMPTY, 0), list); } } pce = LoopNonSlidePce[pceIndex++]; } //ASSERT(MoveListOk(list, pos)); }