Xin lỗi vì đã trả lời trễ ( 4 năm !)
NegaScout là một thuật toán rất đơn giản. Để hiểu chúng ta nên sửa đổi sâu lặp đi lặp lại .
Lặp lại sâu là một kỹ thuật cho một công cụ cờ vua để tìm kiếm độ sâu i, sau đó i + 1, sau đó i + 2, v.v ... Đây là một ví dụ về lập trình động. Trong mỗi lần lặp, chúng tôi có dự đoán tốt nhất về việc di chuyển tốt nhất sẽ là gì. Hầu hết các động cơ cờ vua sẽ giữ di chuyển này trong một bảng băm.
Hãy tưởng tượng chúng ta đang ở lần lặp i + 1 và chúng ta có động thái tốt nhất từ lần lặp cuối cùng i. Bây giờ chúng ta có 5 nút để tìm kiếm, chúng ta nên làm gì?
Nếu chúng ta giả sử chúng ta đã thực hiện công việc một cách hợp lý tốt trong quá trình lặp đi lặp lại cuối cùng, giải pháp chuyển tốt nhất từ phiên cuối cùng (mà chúng tôi nhận được từ các bảng băm) nên cũng là động thái tốt nhất cho lần lặp hiện hành.
Nếu giả định của chúng tôi là chính xác, chúng tôi sẽ có thể tiết kiệm thời gian bằng cách tìm kiếm mọi di chuyển khác với di chuyển tốt nhất (bốn di chuyển không trong bảng băm) với a null window
. Một cửa sổ null là một cái gì đó như:
score := -pvs(child, depth-1, -α-1, -α, -color)
Lưu ý -α-1
và -α
. Chúng là các giá trị alpha và beta mà chúng tôi sẽ cung cấp cho lần đệ quy tiếp theo. Vì chiều rộng của cửa sổ chỉ là 1, nên việc tìm kiếm sẽ luôn thất bại:
- Nếu nó thất bại dưới mức α, di chuyển tồi tệ hơn chúng ta đã có, vì vậy chúng ta có thể bỏ qua nó
- Nếu nó thất bại ở trên, di chuyển quá tốt để chơi, vì vậy chúng ta có thể bỏ qua nó
- Nếu không, chúng ta cần thực hiện một tìm kiếm mới đúng cách
Tất nhiên, chúng tôi vẫn sẽ tìm kiếm nước đi tốt nhất (cái chúng tôi nhận được từ bảng băm) với một cửa sổ alpha và beta thích hợp. Chúng ta cần phải làm điều này bởi vì chúng ta cần biết chính xác giá trị của nút, chúng ta không thể bỏ qua nó.
Tất cả mọi thứ tôi đã nói được thực hiện trong mã giả sau đây. Mã giả chỉ định child is not first child
nhưng đây là một cách để kiểm tra xem di chuyển cũng là di chuyển tốt nhất trong lần lặp trước. Bảng băm là cách thực hiện phổ biến nhất.
# Negasort is also termed Principal Variation Search - hence - pvs
function pvs(node, depth, α, β, color)
if node is a terminal node or depth = 0
return color x the heuristic value of node
for each child of node
if child is not the first child
# search with a null window
score := -pvs(child, depth - 1, -α - 1, -α, -color)
# if it failed high, do a full re-search
if α < score < β
score := -pvs(child, depth - 1, -β, -score, -color)
else
score := -pvs(child, depth - 1, -β, -α, -color)
α := max(α, score)
# beta cut-off
if α >= β
break
return α