Tuyển sinh 🎓 Mình nhận đào tạo lập trình giải thuật thi đấu: thi vào lớp 10 chuyên tin · thi học sinh giỏi tin học cấp tỉnh/thành · thi vào đội tuyển quốc gia · Olympic tin học sinh viên / ICPC · phỏng vấn thuật toán. Bấm vào đây để xem thông tin khóa học → Xem khóa học
Thi thử miễn phí
🏆 Thi thử HSG Tin học tuần này trên ClueOJ
Mở công khai cho mọi người · đề do thầy Nguyễn Việt Nam Sơn biên soạn
Lịch thi, đề cũ & lời giải →

Bài 12: Máy tính chơi cờ giỏi hơn người thế nào? Minimax, cắt tỉa alpha–beta và AlphaZero

Bài 12: Máy tính chơi cờ giỏi hơn người thế nào? Minimax, cắt tỉa alpha–beta và AlphaZero

Năm 1997, máy tính Deep Blue của IBM đánh bại nhà vô địch cờ vua thế giới Garry Kasparov. Ngày nay, một ứng dụng cờ miễn phí trên điện thoại cũng mạnh hơn mọi kỳ thủ con người. Bí mật nằm ở một thuật toán tìm kiếm trên cây trò chơi: minimax và kỹ thuật cắt tỉa alpha–beta.

Máy tính chơi cờ bằng minimax và cắt tỉa alpha-beta

Bài thứ mười hai của chuyên mục "Thuật toán trong đời sống". Nếu bạn đã quen với đệ quy và duyệt cây, bạn có thể tự viết một "AI" chơi cờ ca-rô không bao giờ thua ngay sau bài này.

1. Cây trò chơi và thuật toán minimax

Mỗi thế cờ là một đỉnh, mỗi nước đi là một cạnh dẫn tới thế cờ mới. Hai người chơi luân phiên:

  • MAX (máy) muốn điểm số lớn nhất;
  • MIN (đối thủ) muốn điểm số nhỏ nhất, và ta giả sử đối thủ luôn chơi tốt nhất.

Giá trị một thế cờ được tính đệ quy: ở lượt MAX lấy max các con, ở lượt MIN lấy min các con; ở thế kết thúc, thắng = +1, hòa = 0, thua = −1. Năm 1950, Claude Shannon viết bài báo kỹ thuật đầu tiên về lập trình máy tính chơi cờ, mô tả đúng ý tưởng này.

Con số Shannon: Shannon ước tính cờ vua có khoảng 10120 biến thể từ thế ban đầu. Nếu mỗi micro giây tính một biến thể, máy tính sẽ mất hơn 1090 năm chỉ để tính nước đi đầu tiên. Vì vậy không thể duyệt hết cây – phải cắt tỉa và đánh giá.

2. Cắt tỉa alpha–beta: bỏ qua những nhánh vô ích

MAX 3min 3≤ 2352?Nhánh phải đã ≤ 2 < 3 → MAX không bao giờ chọn → khỏi xét ô "?"

Trong hình, nhánh trái cho MAX giá trị 3. Ở nhánh phải, vừa thấy con đầu tiên bằng 2, ta biết MIN sẽ chọn giá trị ≤ 2 – kém hơn 3. MAX chắc chắn không đi nhánh phải, nên không cần xét các con còn lại.

Thuật toán duy trì hai giá trị: α – điểm tốt nhất MAX chắc chắn đạt được, và β – điểm tốt nhất MIN chắc chắn đạt được. Khi α ≥ β, cắt nhánh. Kết quả giống hệt minimax, chỉ nhanh hơn. Năm 1975, Donald Knuth và Ronald Moore công bố phân tích toán học về alpha–beta, chứng minh thuật toán tối ưu theo một nghĩa nhất định.

3. Code: AI chơi cờ ca-rô 3×3 không bao giờ thua

Code C++ và Python
#include <bits/stdc++.h>
using namespace std;
// Cờ ca-rô 3x3: X = máy (tối đa điểm), O = người (tối thiểu điểm)
char b[10] = "         ";
long long nodes = 0;
int winner(){
    int L[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
    for(auto& l : L) if(b[l[0]] != ' ' && b[l[0]] == b[l[1]] && b[l[1]] == b[l[2]])
        return b[l[0]] == 'X' ? 1 : -1;
    return 0;
}
int minimax(bool xTurn, int alpha, int beta, bool prune){
    nodes++;
    int w = winner(); if(w) return w;
    bool full = true;
    int best = xTurn ? -2 : 2;
    for(int i = 0; i < 9; i++) if(b[i] == ' '){
        full = false;
        b[i] = xTurn ? 'X' : 'O';
        int v = minimax(!xTurn, alpha, beta, prune);
        b[i] = ' ';
        if(xTurn){ best = max(best, v); alpha = max(alpha, v); }
        else     { best = min(best, v); beta  = min(beta, v); }
        if(prune && alpha >= beta) break;   // cắt tỉa: nhánh này không thể tốt hơn
    }
    return full ? 0 : best;
}
int main(){
    nodes = 0; int v1 = minimax(true, -2, 2, false);
    cout << "Minimax thuan:   ket qua " << v1 << ", duyet " << nodes << " trang thai\n";
    nodes = 0; int v2 = minimax(true, -2, 2, true);
    cout << "Co alpha-beta:   ket qua " << v2 << ", duyet " << nodes << " trang thai\n";
}
LINES = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)]
board = [" "] * 9
nodes = 0

def winner():
    for a, b, c in LINES:
        if board[a] != " " and board[a] == board[b] == board[c]:
            return 1 if board[a] == "X" else -1
    return 0

def minimax(x_turn, alpha, beta, prune):
    global nodes
    nodes += 1
    w = winner()
    if w: return w
    moves = [i for i in range(9) if board[i] == " "]
    if not moves: return 0                    # hòa
    best = -2 if x_turn else 2
    for i in moves:
        board[i] = "X" if x_turn else "O"
        v = minimax(not x_turn, alpha, beta, prune)
        board[i] = " "
        if x_turn: best = max(best, v); alpha = max(alpha, v)
        else:      best = min(best, v); beta = min(beta, v)
        if prune and alpha >= beta: break     # cắt tỉa alpha–beta
    return best

for prune in (False, True):
    nodes = 0
    v = minimax(True, -2, 2, prune)
    print("alpha-beta" if prune else "minimax   ", "-> ket qua", v, "| so trang thai:", nodes)
Thuật toánKết quảSố trạng thái phải duyệt
Minimax thuần0 (hòa)549.946
Minimax + alpha–beta0 (hòa)18.297

Cả hai cho kết quả 0: nếu hai bên đều chơi hoàn hảo, cờ ca-rô 3×3 luôn hòa. Nhưng alpha–beta chỉ duyệt khoảng 1/30 số trạng thái. Với cờ vua, tỉ lệ tiết kiệm còn lớn hơn rất nhiều khi các nước tốt được xét trước.

4. Từ Deep Blue đến AlphaZero

Deep Blue (1997): sức mạnh tính toán

Theo IBM, Deep Blue dùng 32 bộ xử lý và đánh giá được 200 triệu thế cờ mỗi giây. Năm 1996, Kasparov thắng trận đấu 4–2; nhưng trận tái đấu tháng 5/1997 ở New York, Deep Blue thắng 3,5–2,5.

AlphaZero (2017–2018): tự học

Theo bài báo trên tạp chí Science (2018) của DeepMind, AlphaZero chỉ được cho biết luật chơi, rồi tự chơi với chính nó để học. Sau khoảng 9 giờ huấn luyện, trong 1.000 ván với Stockfish – chương trình cờ mạnh nhất lúc đó – AlphaZero thắng 155 ván, thua 6 ván, còn lại hòa. Điều thú vị: AlphaZero chỉ tìm kiếm khoảng 60.000 thế cờ/giây, so với 60 triệu của Stockfish – nó "nghĩ ít nhưng nghĩ đúng chỗ" nhờ mạng nơ-ron.

Stockfish ngày nay: kết hợp cả hai

Stockfish vẫn dùng tìm kiếm dựa trên alpha–beta, và từ tháng 8/2020 có thêm hàm đánh giá bằng mạng nơ-ron NNUE chạy hiệu quả trên CPU. Theo blog chính thức của Stockfish, thay đổi này giúp tăng hơn 80 điểm Elo.

5. Bạn học được gì từ đây?

  • Đệ quy + duyệt cây là nền tảng của AI chơi game.
  • Cắt tỉa giúp bỏ qua phần lớn không gian tìm kiếm mà vẫn cho kết quả đúng.
  • Thuật toán cổ điển và học máy không loại trừ nhau – chương trình mạnh nhất thường kết hợp cả hai.
  • Các bài "trò chơi hai người" (lý thuyết trò chơi, Nim, Sprague–Grundy) rất hay xuất hiện trong đề thi.

Bài tập luyện tập

Thử thách: sửa code để máy chơi với bạn – bạn nhập vị trí, máy chọn nước có giá trị minimax tốt nhất. Bạn có thắng được nó không? Chia sẻ trong phần bình luận nhé!

Nguồn tham khảo

Tự học thuật toán: khó ở đâu?
Đọc xong một bài giải là bước đầu. Phần lớn học sinh tự học sẽ gặp những trở ngại sau:
  • Không biết học gì trước, học gì sau, học lan man nên kiến thức bị hổng.
  • Bí bài không ai gỡ, ngồi cả buổi vẫn không ra rồi bỏ cuộc.
  • Code chạy được nhưng không đủ điểm, không biết sai ở đâu, chậm ở đâu.
  • Không có đề thi thử và người chấm, nên không biết mình đang ở mức nào.
  • Dễ nản giữa chừng khi không có ai theo sát.
Học cùng thầy Nam Sơn, các trở ngại đó được gỡ bỏ:
  • Lộ trình 111 buổi video sắp sẵn từ dòng code đầu tiên đến đề HSG thật của các tỉnh.
  • Thầy trực tiếp gỡ bí, chữa bài cho từng em qua nhóm Zalo riêng.
  • Hệ thống chấm bài tự động 24/7 và thi thử HSG hằng tuần để biết chính xác mình đang ở đâu.
  • Đóng học phí một lần, thầy kèm lâu dài: từ thi chuyên Tin đến HSG quốc gia và cả khi lên đại học.

Nhận xét