コード例 #1
0
ファイル: TTable.cs プロジェクト: abcus/connect4_v2
        // Store entry into TTable
        public void storeTTable(UInt64 key, TTEntry entry)
        {
            int index = (int) (key % Constants.TT_SIZE);

            // If entry in bucket has same hash key, then replace
            for (int i = index; i < index + Constants.BUCKET_SIZE; i++) {
                if (this.transpositionTable[i].key == key) {
                    this.transpositionTable[i] = entry;
                    return;
                }
            }
            // If there is an empty spot in the bucket, then store it there
            for (int i = index; i < index + Constants.BUCKET_SIZE; i++) {
                if (this.transpositionTable[i].key == 0) {
                    this.transpositionTable[i] = entry;
                    return;
                }
            }
            // If all spots full, then replace entry with lowest depth
            int shallowestDepth = Constants.INF;
            int indexOfShallowestEntry = -1;
            for (int i = index; i < index + Constants.BUCKET_SIZE; i++) {
                if (this.transpositionTable[i].depth < shallowestDepth) {
                    shallowestDepth = this.transpositionTable[i].depth;
                    indexOfShallowestEntry = i;
                }
            }
            this.transpositionTable[indexOfShallowestEntry] = entry;
        }
コード例 #2
0
        // Store entry into TTable
        public void storeTTable(UInt64 key, TTEntry entry)
        {
            int index = (int)(key % Constants.TT_SIZE);

            // If entry in bucket has same hash key, then replace
            for (int i = index; i < index + Constants.BUCKET_SIZE; i++)
            {
                if (this.transpositionTable[i].key == key)
                {
                    this.transpositionTable[i] = entry;
                    return;
                }
            }
            // If there is an empty spot in the bucket, then store it there
            for (int i = index; i < index + Constants.BUCKET_SIZE; i++)
            {
                if (this.transpositionTable[i].key == 0)
                {
                    this.transpositionTable[i] = entry;
                    return;
                }
            }
            // If all spots full, then replace entry with lowest depth
            int shallowestDepth        = Constants.INF;
            int indexOfShallowestEntry = -1;

            for (int i = index; i < index + Constants.BUCKET_SIZE; i++)
            {
                if (this.transpositionTable[i].depth < shallowestDepth)
                {
                    shallowestDepth        = this.transpositionTable[i].depth;
                    indexOfShallowestEntry = i;
                }
            }
            this.transpositionTable[indexOfShallowestEntry] = entry;
        }
コード例 #3
0
        public static int solve(int nodeType, Position inputBoard, int ply, int alpha, int beta, int depth)
        {
            // return score for terminal state
            if (inputBoard.HasWon(inputBoard.arrayOfBitboard[(inputBoard.nPlies - 1) & 1]))
            {
                return(-Constants.WIN + ply);
            }
            else if (inputBoard.nPlies == 42)
            {
                Debug.Assert(depth == 0);
                return(Constants.DRAW);
            }

            // "Mate" distance pruning
            alpha = Math.Max(ply - Constants.WIN, alpha);
            beta  = Math.Min(Constants.WIN - (ply + 1), beta);
            if (alpha >= beta)
            {
                return(alpha);
            }

            // probe transposition table
            TTEntry entry = Solve.TranspositionTable.probeTTable(inputBoard.key);

            // If entry has a flag type, then key will match (probe function performs check), only empty entries will have a key that doesn't match
            if (entry.flag == Constants.EXACT ||
                entry.flag == Constants.L_BOUND && entry.evaluationScore >= beta ||
                entry.flag == Constants.U_BOUND && entry.evaluationScore <= alpha)
            {
                Debug.Assert(entry.key == inputBoard.key && entry.depth == depth);

                // Only exact and lower bound entries can satisfy this condition and they all have valid moves stored, so don't have to check if move == -1 (only the case with upper bound entries)
                if (entry.evaluationScore >= beta)
                {
                    Debug.Assert(entry.move != Constants.NO_MOVE);
                    updateKillers(entry.move, ply);
                }
                return(entry.evaluationScore);
            }

            // hash move, if entry is exact then code will not be reached and if entry is an upper bound then it will have no move
            int  hashMove = (entry.flag == Constants.L_BOUND && entry.evaluationScore < beta) ? entry.move : Constants.NO_MOVE;
            int  bestScore = -Constants.INF;
            int  movesMade = 0;
            int  numberOfMoves = 0, moveIndex = 0;
            bool raisedAlpha = false;

            Move[] moveList = moveGenerator(ply, hashMove, ref numberOfMoves, inputBoard);
            int    bestMove = Constants.NO_MOVE;

            // loop through all moves
            while (true)
            {
                int move = getNextMove(numberOfMoves, ref moveIndex, moveList);

                if (move == Constants.NO_MOVE)
                {
                    break;
                }

                inputBoard.MakeMove(move);
                int score = -solve(Constants.NON_ROOT, inputBoard, ply + 1, -beta, -alpha, depth - 1);
                inputBoard.UnmakeMove();
                nodesVisited++;
                movesMade++;

                if (score >= beta)
                {
                    TTEntry newEntry = new TTEntry(inputBoard.key, Constants.L_BOUND, depth, score, move);
                    Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry);
                    updateKillers(move, ply);
                    updateHistory(depth, ply, move);

                    if (movesMade == 1)
                    {
                        fh1++;
                    }
                    else
                    {
                        fh++;
                    }
                    return(score);
                }
                else if (score > bestScore)
                {
                    bestScore = score;
                    bestMove  = move;
                    if (score > alpha)
                    {
                        alpha       = score;
                        raisedAlpha = true;
                    }
                }
            }
            // Store in transposition table
            if (raisedAlpha)
            {
                TTEntry newEntry = new TTEntry(inputBoard.key, Constants.EXACT, depth, alpha, bestMove);
                Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry);
            }
            else
            {
                TTEntry newEntry = new TTEntry(inputBoard.key, Constants.U_BOUND, depth, bestScore, Constants.NO_MOVE); // no best move
                Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry);
            }
            return(bestScore);
        }
コード例 #4
0
ファイル: Solve.cs プロジェクト: abcus/connect4_v2
        public static int solve(int nodeType, Position inputBoard, int ply, int alpha, int beta, int depth)
        {
            // return score for terminal state
            if (inputBoard.HasWon(inputBoard.arrayOfBitboard[(inputBoard.nPlies - 1) & 1])) {
                return -Constants.WIN + ply;
            } else if (inputBoard.nPlies == 42) {
                Debug.Assert(depth == 0);
                return Constants.DRAW;
            }

            // "Mate" distance pruning
            //if (nodeType != Constants.ROOT) {
                alpha = Math.Max(ply-Constants.WIN, alpha);
                beta = Math.Min(Constants.WIN - (ply + 1), beta);
                if (alpha >= beta) {
                    return alpha;
                }
            //}

            // probe transposition table
            TTEntry entry = Solve.TranspositionTable.probeTTable(inputBoard.key);

            // If entry has a flag type, then key will match (probe function performs check), only empty entries will have a key that doesn't match
            if (entry.flag == Constants.EXACT
                || entry.flag == Constants.L_BOUND && entry.evaluationScore >= beta
                || entry.flag == Constants.U_BOUND && entry.evaluationScore <= alpha) {
                Debug.Assert(entry.key == inputBoard.key && entry.depth == depth);

                // Only exact and lower bound entries can satisfy this condition and they all have valid moves stored, so don't have to check if move == -1 (only the case with upper bound entries)
                if (entry.evaluationScore >= beta) {
                    Debug.Assert(entry.move != Constants.NO_MOVE);
                    updateKillers(entry.move, ply);
                }
                return entry.evaluationScore;
            }

            // hash move, if entry is exact then code will not be reached and if entry is an upper bound then it will have no move
            int hashMove = (entry.flag == Constants.L_BOUND && entry.evaluationScore < beta) ? entry.move : Constants.NO_MOVE;
            int bestScore = -Constants.INF;
            int movesMade = 0;
            bool raisedAlpha = false;
            movePicker mPicker = new movePicker(inputBoard, ply, hashMove);
            int bestMove = Constants.NO_MOVE;

            // loop through all moves
            while (true) {
                int move = mPicker.getNextMove();

                if (move == Constants.NO_MOVE) {
                    break;
                }

                inputBoard.MakeMove(move);
                int score = -solve(Constants.NON_ROOT, inputBoard, ply + 1, -beta, -alpha, depth - 1);
                inputBoard.UnmakeMove();
                nodesVisited++;
                movesMade++;

                if (score >= beta) {
                    TTEntry newEntry = new TTEntry(inputBoard.key, Constants.L_BOUND, depth, score, move);
                    Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry);
                    updateKillers(move, ply);
                    updateHistory(depth, ply, move);

                    if (movesMade == 1) {
                        fh1++;
                    } else {
                        fh++;
                    }
                    return score;
                } else if (score > bestScore) {
                    bestScore = score;
                    bestMove = move;
                    if (score > alpha) {
                        alpha = score;
                        raisedAlpha = true;
                    }
                }
            }
            // Store in transposition table
            if (raisedAlpha) {
                TTEntry newEntry = new TTEntry(inputBoard.key, Constants.EXACT, depth, alpha, bestMove);
                Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry);
            } else {
                TTEntry newEntry = new TTEntry(inputBoard.key, Constants.U_BOUND, depth, bestScore, Constants.NO_MOVE); // no best move
                Solve.TranspositionTable.storeTTable(inputBoard.key, newEntry);
            }
            return bestScore;
        }