File size: 4,765 Bytes
53b9b08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import chess
import random
import time
from . import evaluation

def random_move(board):
    """
    Trả về một nước đi ngẫu nhiên từ các nước đi hợp lệ.
    """
    legal_moves = list(board.legal_moves)
    if not legal_moves:
        return None
    return random.choice(legal_moves)

def find_best_move(board, weights_dict, depth):
    """
    Tìm nước đi tốt nhất sử dụng Minimax với Alpha-Beta Pruning.
    """
    legal_moves = list(board.legal_moves)
    if not legal_moves:
        return None
    
    start_time = time.time()
    print(f"AI đang tính toán với độ sâu {depth}...")
    
    best_move = None
    max_eval = -float('inf')
    alpha = -float('inf')
    beta = float('inf')
    nodes_evaluated = 0
    
    # Sắp xếp các nước đi để tối ưu alpha-beta pruning
    # Ưu tiên các nước đi ăn quân và chiếu
    def move_priority(move):
        score = 0
        # Nước đi ăn quân có ưu tiên cao
        if board.piece_at(move.to_square):
            captured_piece = board.piece_at(move.to_square)
            piece_values = {chess.PAWN: 10, chess.KNIGHT: 30, chess.BISHOP: 30, 
                          chess.ROOK: 50, chess.QUEEN: 90, chess.KING: 900}
            score += piece_values.get(captured_piece.piece_type, 0)
        
        # Kiểm tra xem có chiếu không
        board.push(move)
        if board.is_check():
            score += 50
        board.pop()
        
        return score
    
    sorted_moves = sorted(legal_moves, key=move_priority, reverse=True)
    
    for i, move in enumerate(sorted_moves):
        board.push(move)
        
        # Gọi minimax với negamax
        eval_score = -minimax_search(board, weights_dict, depth - 1, -beta, -alpha)
        nodes_evaluated += 1
        
        board.pop()
        
        if eval_score > max_eval:
            max_eval = eval_score
            best_move = move
        
        alpha = max(alpha, eval_score)
        if beta <= alpha:
            break  # Alpha-beta pruning
    
    end_time = time.time()
    elapsed_time = end_time - start_time
    
    print(f"AI chọn nước đi: {best_move.uci() if best_move else 'None'}")
    print(f"Điểm đánh giá: {max_eval:.2f}")
    print(f"Thời gian: {elapsed_time:.2f}s, Nodes: {nodes_evaluated}")
    
    return best_move

def minimax_search(board, weights_dict, depth, alpha, beta):
    """
    Hàm đệ quy Minimax với Alpha-Beta Pruning (Negamax implementation)
    """
    
    # Điều kiện dừng: game over
    if board.is_game_over():
        eval_score = evaluation.evaluate_board(board, weights_dict)
        return eval_score if board.turn == chess.WHITE else -eval_score
    
    # Khi depth = 0, sử dụng quiescence search
    if depth == 0:
        return quiescence_search(board, weights_dict, alpha, beta)
    
    max_eval = -float('inf')
    legal_moves = list(board.legal_moves)
    
    # Sắp xếp nước đi để tối ưu pruning
    def move_priority(move):
        score = 0
        if board.piece_at(move.to_square):
            captured_piece = board.piece_at(move.to_square)
            piece_values = {chess.PAWN: 10, chess.KNIGHT: 30, chess.BISHOP: 30,
                          chess.ROOK: 50, chess.QUEEN: 90, chess.KING: 900}
            score += piece_values.get(captured_piece.piece_type, 0)
        return score
    
    sorted_moves = sorted(legal_moves, key=move_priority, reverse=True)
    
    for move in sorted_moves:
        board.push(move)
        
        # Gọi đệ quy với negamax
        eval_score = -minimax_search(board, weights_dict, depth - 1, -beta, -alpha)
        
        board.pop()
        
        max_eval = max(max_eval, eval_score)
        alpha = max(alpha, eval_score)
        
        # Alpha-beta pruning
        if beta <= alpha:
            break
    
    return max_eval

def quiescence_search(board, weights_dict, alpha, beta):
    """
    Quiescence search để đánh giá tốt hơn các vị trí có capture
    """
    # Đánh giá vị trí hiện tại
    stand_pat = evaluation.evaluate_board(board, weights_dict)
    stand_pat = stand_pat if board.turn == chess.WHITE else -stand_pat
    
    if stand_pat >= beta:
        return beta
    if alpha < stand_pat:
        alpha = stand_pat
    
    # Chỉ xem xét các nước đi capture
    capture_moves = [move for move in board.legal_moves if board.piece_at(move.to_square)]
    
    for move in capture_moves:
        board.push(move)
        score = -quiescence_search(board, weights_dict, -beta, -alpha)
        board.pop()
        
        if score >= beta:
            return beta
        if score > alpha:
            alpha = score
    
    return alpha