棋类人机对战

· · 休闲·娱乐

黑白棋

:::info[普通版]

:::

:::info[普通可悔棋版]

#include <windows.h>
#include <stdio.h>

#define SCREENWIDTH 640
#define SCREENHALFWIDTH 320
#define SCREENHEIGHT 640
#define SCREENHALFHEIGHT 320
#define WIDTH 70
#define HEIGHT 70
#define HALFSIZE 30
#define MAPLEFT (SCREENHALFWIDTH - (WIDTH << 2))
#define MAPRIGHT (SCREENHALFWIDTH + (WIDTH << 2))
#define MAPTOP (SCREENHALFHEIGHT - (HEIGHT << 2))
#define MAPBOTTOM (SCREENHALFHEIGHT + (HEIGHT << 2))

// 8个方向的增量
const int dir[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};

// 位置权重表
const int weights[8][8] = {
    { 500, -25,  10,   5,   5,  10, -25, 500},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    { 500, -25,  10,   5,   5,  10, -25, 500}
};

const RECT screen = {0, 0, SCREENWIDTH, SCREENHEIGHT};

// --- 全局变量 ---
int board[8][8];
// 悔棋堆栈:黑白棋最多60步,64足够
int history[64][8][8]; 
int step_count = 0;

int clickx, clicky;
int turn; // 1=黑(玩家), 2=白(电脑)
int winner; // 0=无, 1=黑, 2=白, 3=平局

// 函数声明
void computerMove(HWND hwnd);
BOOL hasValidMove(int player);
void checkGameOver();

ATOM registerWindow(HINSTANCE hInstance, WNDPROC WndProc, LPCSTR className){
    WNDCLASSEXA wc;
    memset(&wc, 0, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEXA);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = className;
    wc.hIcon = LoadIconA(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIconA(NULL, IDI_APPLICATION);
    return RegisterClassExA(&wc);
}

BOOL createWindow(HINSTANCE hInstance, LPCSTR className, LPCSTR title, DWORD style, int x, int y, int width, int height){
    return CreateWindowExA(WS_EX_CLIENTEDGE, className, title, style, x, y, width, height, NULL, NULL, hInstance, NULL) == NULL;
}

WPARAM mainloop(){
    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)){
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    return msg.wParam;
}

void maptoscreen(int *const x, int *const y, int clx, int cly){
    *x = MAPLEFT + clx * WIDTH + (WIDTH >> 1);
    *y = MAPTOP + cly * HEIGHT + (HEIGHT >> 1);
}

void paintmap(HDC hdc){
    int i;
    HBRUSH bgBrush = CreateSolidBrush(0x008000); // 深绿色背景
    RECT mapRect = {MAPLEFT, MAPTOP, MAPRIGHT, MAPBOTTOM};
    FillRect(hdc, &mapRect, bgBrush);
    DeleteObject(bgBrush);

    for (i = MAPLEFT; i <= MAPRIGHT; i += WIDTH){
        MoveToEx(hdc, i, MAPTOP, NULL);
        LineTo(hdc, i, MAPBOTTOM);
    }
    for (i = MAPTOP; i <= MAPBOTTOM; i += HEIGHT){
        MoveToEx(hdc, MAPLEFT, i, NULL);
        LineTo(hdc, MAPRIGHT, i);
    }
}

void paintpieces(HDC hdc){
    HBRUSH oldbrush, blackBrush, whiteBrush;
    HPEN oldpen, nullPen;
    int i, j, x, y;

    blackBrush = CreateSolidBrush(0x000000);
    whiteBrush = CreateSolidBrush(0xFFFFFF);
    nullPen = CreatePen(PS_NULL, 0, 0);
    oldpen = (HPEN)SelectObject(hdc, nullPen);

    for (i = 0; i < 8; ++i){
        for (j = 0; j < 8; ++j){
            if (board[i][j] != 0) {
                maptoscreen(&x, &y, i, j);
                oldbrush = (HBRUSH)SelectObject(hdc, (board[i][j] == 1) ? blackBrush : whiteBrush);
                Ellipse(hdc, x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE);
                SelectObject(hdc, oldbrush);
            }
        }
    }
    SelectObject(hdc, oldpen);
    DeleteObject(blackBrush);
    DeleteObject(whiteBrush);
    DeleteObject(nullPen);
}

void paintinfo(HDC hdc){
    SetTextAlign(hdc, TA_CENTER);
    SetBkMode(hdc, TRANSPARENT);
    char buf[128];
    if (winner) {
        if (winner == 1) lstrcpyA(buf, "Black Wins! (Press 'Z' to Undo)");
        else if (winner == 2) lstrcpyA(buf, "White Wins! (Press 'Z' to Undo)");
        else lstrcpyA(buf, "Draw! (Press 'Z' to Undo)");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    } else {
        if (turn == 1) lstrcpyA(buf, "Your Turn (Black) - Press 'Z' to Undo");
        else lstrcpyA(buf, "AI Thinking...");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    }
}

void mainpaint(HDC hdc){
    paintmap(hdc);
    paintpieces(hdc);
    paintinfo(hdc);
}

// 悔棋相关函数
void saveState() {
    if (step_count < 64) {
        memcpy(history[step_count], board, sizeof(board));
        step_count++;
    }
}

void undo() {
    if (step_count > 0) {
        step_count--;
        memcpy(board, history[step_count], sizeof(board));
        turn = 1;   // 悔棋后强制回到玩家回合
        winner = 0; // 重置胜负状态
    }
}

BOOL isInside(int x, int y) {
    return x >= 0 && x < 8 && y >= 0 && y < 8;
}

int executeMoveLogic(int tempBoard[8][8], int x, int y, int player, BOOL dryRun) {
    if (tempBoard[x][y] != 0) return 0;

    int opponent = 3 - player;
    int totalFlipped = 0;

    for (int k = 0; k < 8; k++) {
        int dx = dir[k][0];
        int dy = dir[k][1];
        int nx = x + dx;
        int ny = y + dy;
        int flipped = 0;

        while (isInside(nx, ny) && tempBoard[nx][ny] == opponent) {
            nx += dx;
            ny += dy;
            flipped++;
        }

        if (flipped > 0 && isInside(nx, ny) && tempBoard[nx][ny] == player) {
            totalFlipped += flipped;
            if (!dryRun) {
                int cx = x + dx;
                int cy = y + dy;
                while (cx != nx || cy != ny) {
                    tempBoard[cx][cy] = player;
                    cx += dx;
                    cy += dy;
                }
            }
        }
    }
    if (!dryRun && totalFlipped > 0) {
        tempBoard[x][y] = player;
    }
    return totalFlipped;
}

BOOL cango(int x, int y) {
    return executeMoveLogic(board, x, y, turn, TRUE) > 0;
}

void makeMove(int x, int y, int player) {
    executeMoveLogic(board, x, y, player, FALSE);
}

int getmouse(HWND hwnd, int *const x, int *const y){
    *x = (*x - MAPLEFT) / WIDTH - (*x < MAPLEFT ? 1 : 0);
    *y = (*y - MAPTOP) / HEIGHT - (*y < MAPTOP ? 1 : 0);
    if (*x < 0 || *x >= 8 || *y < 0 || *y >= 8){
        return 256;
    }
    if (!cango(*x, *y)){
        return 16;
    }
    return 0;
}

// --- AI 部分 ---
int evaluateBoard(int b[8][8], int player) {
    int score = 0;
    int opponent = 3 - player;
    for(int i=0; i<8; i++) {
        for(int j=0; j<8; j++) {
            if(b[i][j] == player) score += weights[i][j];
            else if(b[i][j] == opponent) score -= weights[i][j];
        }
    }
    return score;
}

int minimax(int b[8][8], int depth, int alpha, int beta, int currentPlayer) {
    if (depth == 0) return evaluateBoard(b, 2);

    int validMoves[64][2];
    int moveCount = 0;

    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(b, i, j, currentPlayer, TRUE) > 0) {
                validMoves[moveCount][0] = i;
                validMoves[moveCount][1] = j;
                moveCount++;
            }
        }
    }

    if (moveCount == 0) {
        int opponent = 3 - currentPlayer;
        BOOL opponentCanMove = FALSE;
        for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) 
            if (executeMoveLogic(b, i, j, opponent, TRUE) > 0) opponentCanMove = TRUE;

        if (!opponentCanMove) {
            int score = 0;
            for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
                if(b[i][j] == 2) score++; else if(b[i][j] == 1) score--;
            }
            return score > 0 ? 10000 : (score < 0 ? -10000 : 0); 
        }
        return minimax(b, depth, alpha, beta, 3 - currentPlayer);
    }

    int bestVal, tempBoard[8][8];
    if (currentPlayer == 2) {
        bestVal = -99999;
        for (int k = 0; k < moveCount; k++) {
            memcpy(tempBoard, b, sizeof(int)*64);
            executeMoveLogic(tempBoard, validMoves[k][0], validMoves[k][1], currentPlayer, FALSE);
            int val = minimax(tempBoard, depth - 1, alpha, beta, 1);
            if (val > bestVal) bestVal = val;
            if (val > alpha) alpha = val;
            if (beta <= alpha) break;
        }
    } else {
        bestVal = 99999;
        for (int k = 0; k < moveCount; k++) {
            memcpy(tempBoard, b, sizeof(int)*64);
            executeMoveLogic(tempBoard, validMoves[k][0], validMoves[k][1], currentPlayer, FALSE);
            int val = minimax(tempBoard, depth - 1, alpha, beta, 2);
            if (val < bestVal) bestVal = val;
            if (val < beta) beta = val;
            if (beta <= alpha) break;
        }
    }
    return bestVal;
}

void computerMove(HWND hwnd) {
    int bestScore = -99999;
    int bestMove[2] = {-1, -1};
    int alpha = -99999;
    int beta = 99999;
    int depth = 6; 

    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(board, i, j, 2, TRUE) > 0) {
                int tempBoard[8][8];
                memcpy(tempBoard, board, sizeof(board));
                executeMoveLogic(tempBoard, i, j, 2, FALSE);
                int score = minimax(tempBoard, depth - 1, alpha, beta, 1);
                if (score > bestScore) {
                    bestScore = score;
                    bestMove[0] = i;
                    bestMove[1] = j;
                }
                if (score > alpha) alpha = score;
            }
        }
    }

    if (bestMove[0] != -1) {
        makeMove(bestMove[0], bestMove[1], 2);
        RECT xrect = {0,0,SCREENWIDTH, SCREENHEIGHT};
        InvalidateRect(hwnd, &xrect, FALSE);
        UpdateWindow(hwnd); 
    }
}

BOOL hasValidMove(int player) {
    for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) 
        if (executeMoveLogic(board, i, j, player, TRUE) > 0) return TRUE;
    return FALSE;
}

void checkGameOver() {
    int blackCount = 0, whiteCount = 0;
    BOOL blackCanMove = hasValidMove(1);
    BOOL whiteCanMove = hasValidMove(2);

    if (!blackCanMove && !whiteCanMove) {
        for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
            if(board[i][j] == 1) blackCount++;
            else if(board[i][j] == 2) whiteCount++;
        }
        if (blackCount > whiteCount) winner = 1;
        else if (whiteCount > blackCount) winner = 2;
        else winner = 3;
    }
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
    switch (Message){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            HDC hdcMem = CreateCompatibleDC(hdc);
            HBITMAP hbmMem = CreateCompatibleBitmap(hdc, SCREENWIDTH, SCREENHEIGHT);
            HBITMAP hbm = (HBITMAP)SelectObject(hdcMem, hbmMem);
            HBRUSH background = CreateSolidBrush(0xbfbfbf);
            FillRect(hdcMem, &screen, background);
            mainpaint(hdcMem);
            BitBlt(hdc, 0, 0, SCREENWIDTH, SCREENHEIGHT, hdcMem, 0, 0, SRCCOPY);
            SelectObject(hdcMem, hbm);
            DeleteObject(hbmMem);
            DeleteDC(hdcMem);
            DeleteObject(background);
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_CREATE:
            turn = 1;
            winner = 0;
            step_count = 0; // 重置步数
            memset(board, 0, sizeof(board));
            board[3][3] = board[4][4] = 2; 
            board[3][4] = board[4][3] = 1; 
            break;

        case WM_KEYDOWN: // 处理按键消息
            if (wParam == 'Z') { // 按下 'Z' 键
                // 只有在已走过步数且当前不是电脑思考中(虽然单线程卡住时也按不动)时撤回
                if (step_count > 0 && turn == 1 || winner) {
                    undo();
                    RECT r = {0,0,SCREENWIDTH, SCREENHEIGHT};
                    InvalidateRect(hwnd, &r, FALSE);
                }
            }
            break;

        case WM_LBUTTONDOWN:
            if (turn != 1 || winner) break;

            clickx = LOWORD(lParam);
            clicky = HIWORD(lParam);

            if (getmouse(hwnd, &clickx, &clicky) == 0){
                // 1. 在落子前保存当前状态
                saveState();

                makeMove(clickx, clicky, 1);

                RECT updrect = {0, 0, SCREENWIDTH, SCREENHEIGHT};
                InvalidateRect(hwnd, &updrect, FALSE);
                UpdateWindow(hwnd); 

                turn = 2; 
                if (hasValidMove(2)) {
                    Sleep(100); 
                    computerMove(hwnd);

                    if (!hasValidMove(1)) {
                        if (!hasValidMove(2)) {
                            checkGameOver(); 
                        } else {
                            while (hasValidMove(2) && !hasValidMove(1)) {
                                Sleep(500);
                                computerMove(hwnd);
                                checkGameOver();
                                if (winner) break;
                            }
                            if (!winner && hasValidMove(1)) turn = 1;
                        }
                    } else {
                        turn = 1;
                    }
                } else {
                    MessageBoxA(hwnd, "AI Pass! (No valid moves)", "Info", MB_OK);
                    if (!hasValidMove(1)) checkGameOver();
                    else turn = 1;
                }

                checkGameOver();
                InvalidateRect(hwnd, &updrect, FALSE);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE _0, HINSTANCE _1, LPSTR _2, int _3){
    RECT rcClient = {0, 0, SCREENWIDTH, SCREENHEIGHT};
    const DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
    WPARAM wParam;
    int realwidth, realheight;
    if (!registerWindow(_0, WndProc, "Reversi")){
        MessageBoxA(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    AdjustWindowRect(&rcClient, style, FALSE);
    realwidth = rcClient.right - rcClient.left;
    realheight = rcClient.bottom - rcClient.top;
    if (createWindow(_0, "Reversi", "Reversi (Press Z to Undo)", style,
        GetSystemMetrics(SM_CXSCREEN) - realwidth >> 1,
        GetSystemMetrics(SM_CYSCREEN) - realheight >> 1,
        realwidth, realheight)){
        MessageBoxA(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    wParam = mainloop();
    return wParam;
}

:::

:::info[加强可悔棋版]

#include <windows.h>
#include <stdio.h>

#define SCREENWIDTH 640
#define SCREENHALFWIDTH 320
#define SCREENHEIGHT 640
#define SCREENHALFHEIGHT 320
#define WIDTH 70
#define HEIGHT 70
#define HALFSIZE 30
#define MAPLEFT (SCREENHALFWIDTH - (WIDTH << 2))
#define MAPRIGHT (SCREENHALFWIDTH + (WIDTH << 2))
#define MAPTOP (SCREENHALFHEIGHT - (HEIGHT << 2))
#define MAPBOTTOM (SCREENHALFHEIGHT + (HEIGHT << 2))

// 8个方向的增量
const int dir[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};

// 位置权重表
const int weights[8][8] = {
    { 500, -25,  10,   5,   5,  10, -25, 500},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    { 500, -25,  10,   5,   5,  10, -25, 500}
};

const RECT screen = {0, 0, SCREENWIDTH, SCREENHEIGHT};

// --- 全局变量 ---
int board[8][8];
// 悔棋堆栈:黑白棋最多60步,64足够
int history[64][8][8]; 
int step_count = 0;

int clickx, clicky;
int turn; // 1=黑(玩家), 2=白(电脑)
int winner; // 0=无, 1=黑, 2=白, 3=平局

// 函数声明
void computerMove(HWND hwnd);
BOOL hasValidMove(int player);
void checkGameOver();

ATOM registerWindow(HINSTANCE hInstance, WNDPROC WndProc, LPCSTR className){
    WNDCLASSEXA wc;
    memset(&wc, 0, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEXA);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = className;
    wc.hIcon = LoadIconA(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIconA(NULL, IDI_APPLICATION);
    return RegisterClassExA(&wc);
}

BOOL createWindow(HINSTANCE hInstance, LPCSTR className, LPCSTR title, DWORD style, int x, int y, int width, int height){
    return CreateWindowExA(WS_EX_CLIENTEDGE, className, title, style, x, y, width, height, NULL, NULL, hInstance, NULL) == NULL;
}

WPARAM mainloop(){
    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)){
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    return msg.wParam;
}

void maptoscreen(int *const x, int *const y, int clx, int cly){
    *x = MAPLEFT + clx * WIDTH + (WIDTH >> 1);
    *y = MAPTOP + cly * HEIGHT + (HEIGHT >> 1);
}

void paintmap(HDC hdc){
    int i;
    HBRUSH bgBrush = CreateSolidBrush(0x008000); // 深绿色背景
    RECT mapRect = {MAPLEFT, MAPTOP, MAPRIGHT, MAPBOTTOM};
    FillRect(hdc, &mapRect, bgBrush);
    DeleteObject(bgBrush);

    for (i = MAPLEFT; i <= MAPRIGHT; i += WIDTH){
        MoveToEx(hdc, i, MAPTOP, NULL);
        LineTo(hdc, i, MAPBOTTOM);
    }
    for (i = MAPTOP; i <= MAPBOTTOM; i += HEIGHT){
        MoveToEx(hdc, MAPLEFT, i, NULL);
        LineTo(hdc, MAPRIGHT, i);
    }
}

void paintpieces(HDC hdc){
    HBRUSH oldbrush, blackBrush, whiteBrush;
    HPEN oldpen, nullPen;
    int i, j, x, y;

    blackBrush = CreateSolidBrush(0x000000);
    whiteBrush = CreateSolidBrush(0xFFFFFF);
    nullPen = CreatePen(PS_NULL, 0, 0);
    oldpen = (HPEN)SelectObject(hdc, nullPen);

    for (i = 0; i < 8; ++i){
        for (j = 0; j < 8; ++j){
            if (board[i][j] != 0) {
                maptoscreen(&x, &y, i, j);
                oldbrush = (HBRUSH)SelectObject(hdc, (board[i][j] == 1) ? blackBrush : whiteBrush);
                Ellipse(hdc, x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE);
                SelectObject(hdc, oldbrush);
            }
        }
    }
    SelectObject(hdc, oldpen);
    DeleteObject(blackBrush);
    DeleteObject(whiteBrush);
    DeleteObject(nullPen);
}

void paintinfo(HDC hdc){
    SetTextAlign(hdc, TA_CENTER);
    SetBkMode(hdc, TRANSPARENT);
    char buf[128];
    if (winner) {
        if (winner == 1) lstrcpyA(buf, "Black Wins! (Press 'Z' to Undo)");
        else if (winner == 2) lstrcpyA(buf, "White Wins! (Press 'Z' to Undo)");
        else lstrcpyA(buf, "Draw! (Press 'Z' to Undo)");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    } else {
        if (turn == 1) lstrcpyA(buf, "Your Turn (Black) - Press 'Z' to Undo");
        else lstrcpyA(buf, "AI Thinking...");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    }
}

void mainpaint(HDC hdc){
    paintmap(hdc);
    paintpieces(hdc);
    paintinfo(hdc);
}

// 悔棋相关函数
void saveState() {
    if (step_count < 64) {
        memcpy(history[step_count], board, sizeof(board));
        step_count++;
    }
}

void undo() {
    if (step_count > 0) {
        step_count--;
        memcpy(board, history[step_count], sizeof(board));
        turn = 1;   // 悔棋后强制回到玩家回合
        winner = 0; // 重置胜负状态
    }
}

BOOL isInside(int x, int y) {
    return x >= 0 && x < 8 && y >= 0 && y < 8;
}

int executeMoveLogic(int tempBoard[8][8], int x, int y, int player, BOOL dryRun) {
    if (tempBoard[x][y] != 0) return 0;

    int opponent = 3 - player;
    int totalFlipped = 0;

    for (int k = 0; k < 8; k++) {
        int dx = dir[k][0];
        int dy = dir[k][1];
        int nx = x + dx;
        int ny = y + dy;
        int flipped = 0;

        while (isInside(nx, ny) && tempBoard[nx][ny] == opponent) {
            nx += dx;
            ny += dy;
            flipped++;
        }

        if (flipped > 0 && isInside(nx, ny) && tempBoard[nx][ny] == player) {
            totalFlipped += flipped;
            if (!dryRun) {
                int cx = x + dx;
                int cy = y + dy;
                while (cx != nx || cy != ny) {
                    tempBoard[cx][cy] = player;
                    cx += dx;
                    cy += dy;
                }
            }
        }
    }
    if (!dryRun && totalFlipped > 0) {
        tempBoard[x][y] = player;
    }
    return totalFlipped;
}

BOOL cango(int x, int y) {
    return executeMoveLogic(board, x, y, turn, TRUE) > 0;
}

void makeMove(int x, int y, int player) {
    executeMoveLogic(board, x, y, player, FALSE);
}

int getmouse(HWND hwnd, int *const x, int *const y){
    *x = (*x - MAPLEFT) / WIDTH - (*x < MAPLEFT ? 1 : 0);
    *y = (*y - MAPTOP) / HEIGHT - (*y < MAPTOP ? 1 : 0);
    if (*x < 0 || *x >= 8 || *y < 0 || *y >= 8){
        return 256;
    }
    if (!cango(*x, *y)){
        return 16;
    }
    return 0;
}

// --- 强化版 AI 部分 ---

// 辅助函数:计算某一方当前的合法走步数量(行动力)
int countValidMoves(int b[8][8], int player) {
    int count = 0;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(b, i, j, player, TRUE) > 0) {
                count++;
            }
        }
    }
    return count;
}

// 辅助函数:计算棋子总数
int countDiscs(int b[8][8]) {
    int count = 0;
    for(int i=0; i<8; i++) 
        for(int j=0; j<8; j++) 
            if(b[i][j] != 0) count++;
    return count;
}

// 核心评估函数:比原版更聪明
// 策略:开局中局注重行动力和角,终局注重棋子数
int evaluateBoardStrong(int b[8][8], int player) {
    int opponent = 3 - player;
    int myTiles = 0, oppTiles = 0;
    int myFrontier = 0, oppFrontier = 0;
    int p, q, x, y, k;
    int score = 0;

    // 1. 基础权值分(沿用原来的位置权重,但降低比重)
    for(int i=0; i<8; i++) {
        for(int j=0; j<8; j++) {
            if(b[i][j] == player)  {
                score += weights[i][j];
                myTiles++;
            } else if(b[i][j] == opponent) {
                score -= weights[i][j];
                oppTiles++;
            }

            // 计算边界子(Frontier Discs):如果棋子周围有空位,它是不稳定的
            if (b[i][j] != 0) {
                int isFrontier = 0;
                for (k = 0; k < 8; k++) {
                    int nx = i + dir[k][0];
                    int ny = j + dir[k][1];
                    if (nx >= 0 && nx < 8 && ny >= 0 && ny < 8 && b[nx][ny] == 0) {
                        isFrontier = 1;
                        break;
                    }
                }
                if (isFrontier) {
                    if (b[i][j] == player) myFrontier++;
                    else oppFrontier++;
                }
            }
        }
    }

    // 2. 阶段判断
    int totalDiscs = myTiles + oppTiles;

    // --- 终局逻辑 (64格占满前10步) ---
    // 如果快结束了,直接算谁的棋子多,这就是“完美杀手”
    if (totalDiscs > 54) {
        return (myTiles - oppTiles) * 1000; 
    }

    // --- 中盘逻辑 ---

    // A. 行动力 (Mobility) - 最关键的改进点
    // 你的对手如果只有很少的走法,他就很容易被迫走到坏位置(如C位或X位)
    int myMoves = countValidMoves(b, player);
    int oppMoves = countValidMoves(b, opponent);
    // 权重大大增加,压制对手的行动力
    score += (myMoves - oppMoves) * 300; 

    // B. 边界子惩罚
    // 边界子越少越好,意味着你的棋子被包裹在内部,很难被翻转
    score -= (myFrontier - oppFrontier) * 50;

    // C. 角的安全性 (Corner Stability)
    // 如果占了角,分数极高;如果没占角但占了角旁边的点(星位/X位),惩罚极高
    // 原有的 weights 数组已经包含了一部分,这里额外加强对角的控制逻辑
    int corners[4][2] = {{0,0}, {0,7}, {7,0}, {7,7}};
    for(int i=0; i<4; i++) {
        x = corners[i][0];
        y = corners[i][1];
        if (b[x][y] == player) {
            score += 600; // 只要占了角,就给予巨额奖励
        } else if (b[x][y] == opponent) {
            score -= 600;
        }
    }

    return score;
}

// 增强版 Minimax:带 Alpha-Beta 剪枝
int minimaxStrong(int b[8][8], int depth, int alpha, int beta, int currentPlayer, int maximizingPlayer) {
    // 如果深度为0 或 游戏结束
    if (depth == 0) {
        return evaluateBoardStrong(b, maximizingPlayer);
    }

    // 1. 获取所有合法走步
    int validMoves[64][2];
    int moveCount = 0;

    // 简单的移动排序优化:优先搜索角,这样能更快触发剪枝
    // 检查角
    int corners[4][2] = {{0,0}, {0,7}, {7,0}, {7,7}};
    for (int k=0; k<4; k++) {
         if (executeMoveLogic(b, corners[k][0], corners[k][1], currentPlayer, TRUE) > 0) {
             validMoves[moveCount][0] = corners[k][0];
             validMoves[moveCount][1] = corners[k][1];
             moveCount++;
         }
    }
    // 检查其他位置
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            // 避免重复添加角
            if ((i==0||i==7) && (j==0||j==7)) continue;

            if (executeMoveLogic(b, i, j, currentPlayer, TRUE) > 0) {
                validMoves[moveCount][0] = i;
                validMoves[moveCount][1] = j;
                moveCount++;
            }
        }
    }

    // 2. 如果没有合法走步 (Pass)
    if (moveCount == 0) {
        int opponent = 3 - currentPlayer;
        // 检查对手是否能走
        if (countValidMoves(b, opponent) == 0) {
            // 双方都不能走,游戏结束,计算最终分数
            int finalScore = 0;
            for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
                if(b[i][j] == maximizingPlayer) finalScore++; 
                else if(b[i][j] != 0) finalScore--;
            }
            if (finalScore > 0) return 100000 + finalScore; // 赢
            if (finalScore < 0) return -100000 + finalScore; // 输
            return 0; // 平
        }
        // 对手走,深度不减(为了防止深度耗尽看不到结局)
        return minimaxStrong(b, depth, alpha, beta, opponent, maximizingPlayer);
    }

    int tempBoard[8][8];
    int bestVal;

    // 3. 递归搜索
    if (currentPlayer == maximizingPlayer) { // 我方回合(找最大值)
        bestVal = -999999;
        for (int k = 0; k < moveCount; k++) {
            memcpy(tempBoard, b, sizeof(int)*64);
            executeMoveLogic(tempBoard, validMoves[k][0], validMoves[k][1], currentPlayer, FALSE);

            int val = minimaxStrong(tempBoard, depth - 1, alpha, beta, 3 - currentPlayer, maximizingPlayer);

            if (val > bestVal) bestVal = val;
            if (val > alpha) alpha = val;
            if (beta <= alpha) break; // 剪枝
        }
    } else { // 敌方回合(找最小值)
        bestVal = 999999;
        for (int k = 0; k < moveCount; k++) {
            memcpy(tempBoard, b, sizeof(int)*64);
            executeMoveLogic(tempBoard, validMoves[k][0], validMoves[k][1], currentPlayer, FALSE);

            int val = minimaxStrong(tempBoard, depth - 1, alpha, beta, 3 - currentPlayer, maximizingPlayer);

            if (val < bestVal) bestVal = val;
            if (val < beta) beta = val;
            if (beta <= alpha) break; // 剪枝
        }
    }
    return bestVal;
}

void computerMove(HWND hwnd) {
    int bestScore = -999999;
    int bestMove[2] = {-1, -1};
    int alpha = -999999;
    int beta = 999999;

    // 动态深度:开局简单点,中局深一点,终局更深
    int discs = countDiscs(board);
    int depth = 6; 
    if (discs > 48) depth = 10; // 终局搜索加深

    // 为了提高效率,这里也可以做一次简单的Move Ordering
    int validMoves[64][2];
    int moveCount = 0;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(board, i, j, 2, TRUE) > 0) {
                validMoves[moveCount][0] = i;
                validMoves[moveCount][1] = j;
                moveCount++;
            }
        }
    }

    for (int k = 0; k < moveCount; k++) {
        int i = validMoves[k][0];
        int j = validMoves[k][1];

        int tempBoard[8][8];
        memcpy(tempBoard, board, sizeof(board));
        executeMoveLogic(tempBoard, i, j, 2, FALSE);

        // 调用增强版 minimax,当前是白棋(2),maximizingPlayer也是2
        int score = minimaxStrong(tempBoard, depth - 1, alpha, beta, 1, 2);

        // 增加一点随机性打破平局(仅在分数相同时),让AI走棋稍微多样化一点
        if (score > bestScore) {
            bestScore = score;
            bestMove[0] = i;
            bestMove[1] = j;
        }
        if (score > alpha) alpha = score;
    }

    if (bestMove[0] != -1) {
        makeMove(bestMove[0], bestMove[1], 2);
        RECT xrect = {0,0,SCREENWIDTH, SCREENHEIGHT};
        InvalidateRect(hwnd, &xrect, FALSE);
        UpdateWindow(hwnd); 
    }
}

BOOL hasValidMove(int player) {
    for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) 
        if (executeMoveLogic(board, i, j, player, TRUE) > 0) return TRUE;
    return FALSE;
}

void checkGameOver() {
    int blackCount = 0, whiteCount = 0;
    BOOL blackCanMove = hasValidMove(1);
    BOOL whiteCanMove = hasValidMove(2);

    if (!blackCanMove && !whiteCanMove) {
        for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
            if(board[i][j] == 1) blackCount++;
            else if(board[i][j] == 2) whiteCount++;
        }
        if (blackCount > whiteCount) winner = 1;
        else if (whiteCount > blackCount) winner = 2;
        else winner = 3;
    }
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
    switch (Message){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            HDC hdcMem = CreateCompatibleDC(hdc);
            HBITMAP hbmMem = CreateCompatibleBitmap(hdc, SCREENWIDTH, SCREENHEIGHT);
            HBITMAP hbm = (HBITMAP)SelectObject(hdcMem, hbmMem);
            HBRUSH background = CreateSolidBrush(0xbfbfbf);
            FillRect(hdcMem, &screen, background);
            mainpaint(hdcMem);
            BitBlt(hdc, 0, 0, SCREENWIDTH, SCREENHEIGHT, hdcMem, 0, 0, SRCCOPY);
            SelectObject(hdcMem, hbm);
            DeleteObject(hbmMem);
            DeleteDC(hdcMem);
            DeleteObject(background);
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_CREATE:
            turn = 1;
            winner = 0;
            step_count = 0; // 重置步数
            memset(board, 0, sizeof(board));
            board[3][3] = board[4][4] = 2; 
            board[3][4] = board[4][3] = 1; 
            break;

        case WM_KEYDOWN: // 处理按键消息
            if (wParam == 'Z') { // 按下 'Z' 键
                // 只有在已走过步数且当前不是电脑思考中(虽然单线程卡住时也按不动)时撤回
                if (step_count > 0 && turn == 1 || winner) {
                    undo();
                    RECT r = {0,0,SCREENWIDTH, SCREENHEIGHT};
                    InvalidateRect(hwnd, &r, FALSE);
                }
            }
            break;

        case WM_LBUTTONDOWN:
            if (turn != 1 || winner) break;

            clickx = LOWORD(lParam);
            clicky = HIWORD(lParam);

            if (getmouse(hwnd, &clickx, &clicky) == 0){
                // 1. 在落子前保存当前状态
                saveState();

                makeMove(clickx, clicky, 1);

                RECT updrect = {0, 0, SCREENWIDTH, SCREENHEIGHT};
                InvalidateRect(hwnd, &updrect, FALSE);
                UpdateWindow(hwnd); 

                turn = 2; 
                if (hasValidMove(2)) {
                    Sleep(100); 
                    computerMove(hwnd);

                    if (!hasValidMove(1)) {
                        if (!hasValidMove(2)) {
                            checkGameOver(); 
                        } else {
                            while (hasValidMove(2) && !hasValidMove(1)) {
                                Sleep(500);
                                computerMove(hwnd);
                                checkGameOver();
                                if (winner) break;
                            }
                            if (!winner && hasValidMove(1)) turn = 1;
                        }
                    } else {
                        turn = 1;
                    }
                } else {
                    MessageBoxA(hwnd, "AI Pass! (No valid moves)", "Info", MB_OK);
                    if (!hasValidMove(1)) checkGameOver();
                    else turn = 1;
                }

                checkGameOver();
                InvalidateRect(hwnd, &updrect, FALSE);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE _0, HINSTANCE _1, LPSTR _2, int _3){
    RECT rcClient = {0, 0, SCREENWIDTH, SCREENHEIGHT};
    const DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
    WPARAM wParam;
    int realwidth, realheight;
    if (!registerWindow(_0, WndProc, "Reversi")){
        MessageBoxA(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    AdjustWindowRect(&rcClient, style, FALSE);
    realwidth = rcClient.right - rcClient.left;
    realheight = rcClient.bottom - rcClient.top;
    if (createWindow(_0, "Reversi", "Reversi (Press Z to Undo)", style,
        GetSystemMetrics(SM_CXSCREEN) - realwidth >> 1,
        GetSystemMetrics(SM_CYSCREEN) - realheight >> 1,
        realwidth, realheight)){
        MessageBoxA(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    wParam = mainloop();
    return wParam;
}

:::

:::info[加强加强版与加强版对战演示]

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#define SCREENWIDTH 640
#define SCREENHALFWIDTH 320
#define SCREENHEIGHT 640
#define SCREENHALFHEIGHT 320
#define WIDTH 70
#define HEIGHT 70
#define HALFSIZE 30
#define MAPLEFT (SCREENHALFWIDTH - (WIDTH << 2))
#define MAPRIGHT (SCREENHALFWIDTH + (WIDTH << 2))
#define MAPTOP (SCREENHALFHEIGHT - (HEIGHT << 2))
#define MAPBOTTOM (SCREENHALFHEIGHT + (HEIGHT << 2))

// 8个方向的增量
const int dir[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};

// 基础位置权重表 (White AI uses this)
const int weights[8][8] = {
    { 500, -25,  10,   5,   5,  10, -25, 500},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    { 500, -25,  10,   5,   5,  10, -25, 500}
};

const RECT screen = {0, 0, SCREENWIDTH, SCREENHEIGHT};

// --- 全局变量 ---
int board[8][8];
int history[64][8][8]; 
int step_count = 0;
int turn; // 1=黑(超级AI), 2=白(原版AI)
int winner; // 0=无, 1=黑, 2=白, 3=平局

// 函数声明
void computerMove_White(HWND hwnd); // 原版后手算法
void computerMove_Black(HWND hwnd); // 新版先手算法
BOOL hasValidMove(int player);
void checkGameOver();

ATOM registerWindow(HINSTANCE hInstance, WNDPROC WndProc, LPCSTR className){
    WNDCLASSEXA wc;
    memset(&wc, 0, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEXA);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = className;
    wc.hIcon = LoadIconA(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIconA(NULL, IDI_APPLICATION);
    return RegisterClassExA(&wc);
}

BOOL createWindow(HINSTANCE hInstance, LPCSTR className, LPCSTR title, DWORD style, int x, int y, int width, int height){
    return CreateWindowExA(WS_EX_CLIENTEDGE, className, title, style, x, y, width, height, NULL, NULL, hInstance, NULL) == NULL;
}

WPARAM mainloop(){
    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)){
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    return msg.wParam;
}

void maptoscreen(int *const x, int *const y, int clx, int cly){
    *x = MAPLEFT + clx * WIDTH + (WIDTH >> 1);
    *y = MAPTOP + cly * HEIGHT + (HEIGHT >> 1);
}

void paintmap(HDC hdc){
    int i;
    HBRUSH bgBrush = CreateSolidBrush(0x008000); 
    RECT mapRect = {MAPLEFT, MAPTOP, MAPRIGHT, MAPBOTTOM};
    FillRect(hdc, &mapRect, bgBrush);
    DeleteObject(bgBrush);
    for (i = MAPLEFT; i <= MAPRIGHT; i += WIDTH){
        MoveToEx(hdc, i, MAPTOP, NULL);
        LineTo(hdc, i, MAPBOTTOM);
    }
    for (i = MAPTOP; i <= MAPBOTTOM; i += HEIGHT){
        MoveToEx(hdc, MAPLEFT, i, NULL);
        LineTo(hdc, MAPRIGHT, i);
    }
}

void paintpieces(HDC hdc){
    HBRUSH oldbrush, blackBrush, whiteBrush;
    HPEN oldpen, nullPen;
    int i, j, x, y;

    blackBrush = CreateSolidBrush(0x000000);
    whiteBrush = CreateSolidBrush(0xFFFFFF);
    nullPen = CreatePen(PS_NULL, 0, 0);
    oldpen = (HPEN)SelectObject(hdc, nullPen);
    for (i = 0; i < 8; ++i){
        for (j = 0; j < 8; ++j){
            if (board[i][j] != 0) {
                maptoscreen(&x, &y, i, j);
                oldbrush = (HBRUSH)SelectObject(hdc, (board[i][j] == 1) ? blackBrush : whiteBrush);
                Ellipse(hdc, x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE);
                SelectObject(hdc, oldbrush);
            }
        }
    }
    SelectObject(hdc, oldpen);
    DeleteObject(blackBrush);
    DeleteObject(whiteBrush);
    DeleteObject(nullPen);
}

void paintinfo(HDC hdc){
    SetTextAlign(hdc, TA_CENTER);
    SetBkMode(hdc, TRANSPARENT);
    char buf[128];
    if (winner) {
        if (winner == 1) lstrcpyA(buf, "Black (Super AI) Wins!");
        else if (winner == 2) lstrcpyA(buf, "White (Original AI) Wins!");
        else lstrcpyA(buf, "Draw!");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    } else {
        if (turn == 1) lstrcpyA(buf, "Black (Super AI) Thinking...");
        else lstrcpyA(buf, "White (Original AI) Thinking...");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    }
}

void mainpaint(HDC hdc){
    paintmap(hdc);
    paintpieces(hdc);
    paintinfo(hdc);
}

BOOL isInside(int x, int y) {
    return x >= 0 && x < 8 && y >= 0 && y < 8;
}

int executeMoveLogic(int tempBoard[8][8], int x, int y, int player, BOOL dryRun) {
    if (tempBoard[x][y] != 0) return 0;

    int opponent = 3 - player;
    int totalFlipped = 0;
    for (int k = 0; k < 8; k++) {
        int dx = dir[k][0];
        int dy = dir[k][1];
        int nx = x + dx;
        int ny = y + dy;
        int flipped = 0;
        while (isInside(nx, ny) && tempBoard[nx][ny] == opponent) {
            nx += dx;
            ny += dy;
            flipped++;
        }
        if (flipped > 0 && isInside(nx, ny) && tempBoard[nx][ny] == player) {
            totalFlipped += flipped;
            if (!dryRun) {
                int cx = x + dx;
                int cy = y + dy;
                while (cx != nx || cy != ny) {
                    tempBoard[cx][cy] = player;
                    cx += dx;
                    cy += dy;
                }
            }
        }
    }
    if (!dryRun && totalFlipped > 0) {
        tempBoard[x][y] = player;
    }
    return totalFlipped;
}

void makeMove(int x, int y, int player) {
    executeMoveLogic(board, x, y, player, FALSE);
}

int countValidMoves(int b[8][8], int player) {
    int count = 0;
    for (int i = 0; i < 8; i++) 
        for (int j = 0; j < 8; j++) 
            if (executeMoveLogic(b, i, j, player, TRUE) > 0) count++;
    return count;
}

int countDiscs(int b[8][8]) {
    int count = 0;
    for(int i=0; i<8; i++) 
        for(int j=0; j<8; j++) 
            if(b[i][j] != 0) count++;
    return count;
}

// -------------------------------------------------------------
// 原版白棋 AI (保持不变)
// -------------------------------------------------------------
int evaluateBoardOriginal(int b[8][8], int player) {
    int opponent = 3 - player;
    int myTiles = 0, oppTiles = 0, myFrontier = 0, oppFrontier = 0, score = 0;

    for(int i=0; i<8; i++) {
        for(int j=0; j<8; j++) {
            if(b[i][j] == player)  { score += weights[i][j]; myTiles++; } 
            else if(b[i][j] == opponent) { score -= weights[i][j]; oppTiles++; }

            if (b[i][j] != 0) {
                int isFrontier = 0;
                for (int k = 0; k < 8; k++) {
                    int nx = i + dir[k][0];
                    int ny = j + dir[k][1];
                    if (nx >= 0 && nx < 8 && ny >= 0 && ny < 8 && b[nx][ny] == 0) {
                        isFrontier = 1; break;
                    }
                }
                if (isFrontier) { if (b[i][j] == player) myFrontier++; else oppFrontier++; }
            }
        }
    }
    int totalDiscs = myTiles + oppTiles;
    if (totalDiscs > 54) return (myTiles - oppTiles) * 1000; 

    int myMoves = countValidMoves(b, player);
    int oppMoves = countValidMoves(b, opponent);
    score += (myMoves - oppMoves) * 300; 
    score -= (myFrontier - oppFrontier) * 50;

    int corners[4][2] = {{0,0}, {0,7}, {7,0}, {7,7}};
    for(int i=0; i<4; i++) {
        if (b[corners[i][0]][corners[i][1]] == player) score += 600; 
        else if (b[corners[i][0]][corners[i][1]] == opponent) score -= 600;
    }
    return score;
}

int minimaxOriginal(int b[8][8], int depth, int alpha, int beta, int currentPlayer, int maximizingPlayer) {
    if (depth == 0) return evaluateBoardOriginal(b, maximizingPlayer);

    int validMoves[64][2];
    int moveCount = 0;
    int corners[4][2] = {{0,0}, {0,7}, {7,0}, {7,7}};
    for (int k=0; k<4; k++) {
         if (executeMoveLogic(b, corners[k][0], corners[k][1], currentPlayer, TRUE) > 0) {
             validMoves[moveCount][0] = corners[k][0]; validMoves[moveCount][1] = corners[k][1]; moveCount++;
         }
    }
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if ((i==0||i==7) && (j==0||j==7)) continue;
            if (executeMoveLogic(b, i, j, currentPlayer, TRUE) > 0) {
                validMoves[moveCount][0] = i; validMoves[moveCount][1] = j; moveCount++;
            }
        }
    }

    if (moveCount == 0) {
        if (countValidMoves(b, 3 - currentPlayer) == 0) {
             int finalScore = 0;
             for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
                 if(b[i][j] == maximizingPlayer) finalScore++; else if(b[i][j] != 0) finalScore--;
             }
             if (finalScore > 0) return 100000 + finalScore;
             if (finalScore < 0) return -100000 + finalScore;
             return 0;
        }
        return minimaxOriginal(b, depth, alpha, beta, 3 - currentPlayer, maximizingPlayer);
    }

    int tempBoard[8][8];
    int bestVal = (currentPlayer == maximizingPlayer) ? -999999 : 999999;

    for (int k = 0; k < moveCount; k++) {
        memcpy(tempBoard, b, sizeof(int)*64);
        executeMoveLogic(tempBoard, validMoves[k][0], validMoves[k][1], currentPlayer, FALSE);
        int val = minimaxOriginal(tempBoard, depth - 1, alpha, beta, 3 - currentPlayer, maximizingPlayer);

        if (currentPlayer == maximizingPlayer) {
            if (val > bestVal) bestVal = val;
            if (val > alpha) alpha = val;
        } else {
            if (val < bestVal) bestVal = val;
            if (val < beta) beta = val;
        }
        if (beta <= alpha) break;
    }
    return bestVal;
}

void computerMove_White(HWND hwnd) {
    int bestScore = -999999;
    int bestMove[2] = {-1, -1};
    int alpha = -999999;
    int beta = 999999;
    int discs = countDiscs(board);
    int depth = 6; 
    if (discs > 48) depth = 10;

    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(board, i, j, 2, TRUE) > 0) {
                int tempBoard[8][8];
                memcpy(tempBoard, board, sizeof(board));
                executeMoveLogic(tempBoard, i, j, 2, FALSE);
                int score = minimaxOriginal(tempBoard, depth - 1, alpha, beta, 1, 2);
                if (score > bestScore) {
                    bestScore = score; bestMove[0] = i; bestMove[1] = j;
                }
                if (score > alpha) alpha = score;
            }
        }
    }
    if (bestMove[0] != -1) {
        makeMove(bestMove[0], bestMove[1], 2);
        RECT xrect = {0,0,SCREENWIDTH, SCREENHEIGHT};
        InvalidateRect(hwnd, &xrect, FALSE);
        UpdateWindow(hwnd); 
    }
}

// -------------------------------------------------------------
// 升级版黑棋 AI (先手) - 设计用于击败白棋
// -------------------------------------------------------------

// 1. 动态位置估值:如果角被占据,周围的坏点就会变成好点
int getDynamicWeight(int b[8][8], int x, int y) {
    int w = weights[x][y];
    // 左上角逻辑
    if (x <= 1 && y <= 1) {
        if (b[0][0] != 0) return 50; // 角被占,临近点不再是-25/-45,而是正分
    }
    // 右上角
    else if (x >= 6 && y <= 1) {
        if (b[7][0] != 0) return 50;
    }
    // 左下角
    else if (x <= 1 && y >= 6) {
        if (b[0][7] != 0) return 50;
    }
    // 右下角
    else if (x >= 6 && y >= 6) {
        if (b[7][7] != 0) return 50;
    }
    return w;
}

// 2. 超级估值函数
int evaluateBoardBlack(int b[8][8], int player) {
    int opponent = 3 - player;
    int myTiles = 0, oppTiles = 0;
    int myFrontier = 0, oppFrontier = 0;
    int score = 0;

    // 基础计数
    for(int i=0; i<8; i++) {
        for(int j=0; j<8; j++) {
            if (b[i][j] == 0) continue;

            // 动态位置分
            int w = getDynamicWeight(b, i, j);
            if(b[i][j] == player) { score += w; myTiles++; } 
            else { score -= w; oppTiles++; }

            // 边界子判定
            int isFrontier = 0;
            for (int k = 0; k < 8; k++) {
                int nx = i + dir[k][0]; int ny = j + dir[k][1];
                if (nx >= 0 && nx < 8 && ny >= 0 && ny < 8 && b[nx][ny] == 0) {
                    isFrontier = 1; break;
                }
            }
            if (isFrontier) { if (b[i][j] == player) myFrontier++; else oppFrontier++; }
        }
    }

    int totalDiscs = myTiles + oppTiles;

    // --- 终局:完美算子 ---
    if (totalDiscs > 58) return (myTiles - oppTiles) * 10000;

    // --- 行动力压制 ---
    int myMoves = countValidMoves(b, player);
    int oppMoves = countValidMoves(b, opponent);

    // 关键策略:Evaporation(蒸发)。前期尽量让对方子多,自己子少,但要是安全子
    // 黑棋 AI 极度看重“相对行动力”
    // 在中局,让对手无路可走比自己得分更重要
    score += (myMoves - oppMoves) * 500; 

    // 边界惩罚加强,迫使黑棋下在内部
    score -= (myFrontier - oppFrontier) * 100;

    // --- 奇偶性 Parity ---
    // 剩余空位为偶数时,作为当前行动方(黑棋),如果能抢占最后一个区域的先手是劣势,
    // 但通常我们希望控制Parity。这里简化为:如果在最后几个空位能保持主动
    if (totalDiscs > 45) {
        score += (myTiles - oppTiles) * 10; // 后期逐渐转为重视子数
    } else {
        // 前期不要太多子
        score -= (myTiles - oppTiles) * 5; 
    }

    // --- 角的绝对控制 ---
    int corners[4][2] = {{0,0}, {0,7}, {7,0}, {7,7}};
    for(int i=0; i<4; i++) {
        if (b[corners[i][0]][corners[i][1]] == player) score += 1000; // 比白棋更重视角
        else if (b[corners[i][0]][corners[i][1]] == opponent) score -= 1000;
    }

    return score;
}

// 结构体用于移动排序
typedef struct {
    int x, y;
    int score;
} MoveScore;

int compareMoves(const void *a, const void *b) {
    return ((MoveScore*)b)->score - ((MoveScore*)a)->score; // 降序
}

// 升级版 Minimax:带移动排序和更深搜索
int minimaxBlack(int b[8][8], int depth, int alpha, int beta, int currentPlayer, int maximizingPlayer) {
    if (depth == 0) return evaluateBoardBlack(b, maximizingPlayer);

    int opponent = 3 - currentPlayer;
    MoveScore moves[64];
    int moveCount = 0;

    // 1. 生成走法并进行启发式评分(为了排序)
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(b, i, j, currentPlayer, TRUE) > 0) {
                moves[moveCount].x = i;
                moves[moveCount].y = j;

                // 启发式评分:角最高,C/X位最低,减少对方行动力最高
                int score = getDynamicWeight(b, i, j);
                // 简单的静态预判:如果这步棋让对方无路可走,加分
                // (为了性能,这里不进行完整的递归模拟,只用静态表辅助)
                moves[moveCount].score = score;
                moveCount++;
            }
        }
    }

    if (moveCount == 0) {
        if (countValidMoves(b, opponent) == 0) {
            int finalScore = 0;
             for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
                 if(b[i][j] == maximizingPlayer) finalScore++; else if(b[i][j] != 0) finalScore--;
             }
             if (finalScore > 0) return 200000 + finalScore;
             if (finalScore < 0) return -200000 + finalScore;
             return 0;
        }
        return minimaxBlack(b, depth, alpha, beta, opponent, maximizingPlayer);
    }

    // 2. 对走法排序:好的走法先搜,极大提高剪枝效率
    qsort(moves, moveCount, sizeof(MoveScore), compareMoves);

    int tempBoard[8][8];
    int bestVal = (currentPlayer == maximizingPlayer) ? -9999999 : 9999999;

    for (int k = 0; k < moveCount; k++) {
        memcpy(tempBoard, b, sizeof(int)*64);
        executeMoveLogic(tempBoard, moves[k].x, moves[k].y, currentPlayer, FALSE);

        int val = minimaxBlack(tempBoard, depth - 1, alpha, beta, opponent, maximizingPlayer);

        if (currentPlayer == maximizingPlayer) {
            if (val > bestVal) bestVal = val;
            if (val > alpha) alpha = val;
        } else {
            if (val < bestVal) bestVal = val;
            if (val < beta) beta = val;
        }
        if (beta <= alpha) break;
    }
    return bestVal;
}

void computerMove_Black(HWND hwnd) {
    int bestScore = -9999999;
    int bestMove[2] = {-1, -1};
    int alpha = -9999999;
    int beta = 9999999;

    int discs = countDiscs(board);
    // 黑棋搜索深度更深:中局8层,终局12层 (原版只有6和10)
    // 得益于移动排序,这通常是可行的
    int depth = 8; 
    if (discs > 50) depth = 12;

    // 同样应用移动排序到第一层
    MoveScore moves[64];
    int moveCount = 0;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(board, i, j, 1, TRUE) > 0) {
                moves[moveCount].x = i;
                moves[moveCount].y = j;
                moves[moveCount].score = getDynamicWeight(board, i, j);
                moveCount++;
            }
        }
    }
    qsort(moves, moveCount, sizeof(MoveScore), compareMoves);

    for (int k = 0; k < moveCount; k++) {
        int i = moves[k].x;
        int j = moves[k].y;

        int tempBoard[8][8];
        memcpy(tempBoard, board, sizeof(board));
        executeMoveLogic(tempBoard, i, j, 1, FALSE);

        // 黑棋是1,maximizingPlayer也是1
        int score = minimaxBlack(tempBoard, depth - 1, alpha, beta, 2, 1);

        if (score > bestScore) {
            bestScore = score;
            bestMove[0] = i;
            bestMove[1] = j;
        }
        if (score > alpha) alpha = score;

        // 稍微更新界面以免卡死感
        if (k==0) {
            RECT r = {0,0,10,10}; InvalidateRect(hwnd, &r, FALSE); UpdateWindow(hwnd);
        }
    }

    if (bestMove[0] != -1) {
        makeMove(bestMove[0], bestMove[1], 1);
        RECT xrect = {0,0,SCREENWIDTH, SCREENHEIGHT};
        InvalidateRect(hwnd, &xrect, FALSE);
        UpdateWindow(hwnd); 
    }
}

// -------------------------------------------------------------
// 游戏主逻辑
// -------------------------------------------------------------

BOOL hasValidMove(int player) {
    for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) 
        if (executeMoveLogic(board, i, j, player, TRUE) > 0) return TRUE;
    return FALSE;
}

void checkGameOver() {
    if (!hasValidMove(1) && !hasValidMove(2)) {
        int blackCount = 0, whiteCount = 0;
        for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
            if(board[i][j] == 1) blackCount++;
            else if(board[i][j] == 2) whiteCount++;
        }
        if (blackCount > whiteCount) winner = 1;
        else if (whiteCount > blackCount) winner = 2;
        else winner = 3;
    }
}

// 处理回合逻辑
void processTurns(HWND hwnd) {
    if (winner) return;

    // 黑棋(AI)回合
    if (turn == 1) {
        if (hasValidMove(1)) {
            Sleep(200); // 稍微停顿一下
            computerMove_Black(hwnd);
            turn = 2;
        } else {
            // 黑棋无棋可走
            if (hasValidMove(2)) turn = 2;
            else checkGameOver();
        }
    }

    // 检查游戏是否结束,如果没结束则继续白棋
    checkGameOver();
    if (winner) { InvalidateRect(hwnd, NULL, FALSE); return; }

    // 白棋(原版AI)回合
    if (turn == 2) {
        if (hasValidMove(2)) {
            Sleep(200);
            computerMove_White(hwnd);
            turn = 1;
        } else {
            // 白棋无棋可走
            if (hasValidMove(1)) turn = 1;
            else checkGameOver();
        }
    }
    checkGameOver();
    InvalidateRect(hwnd, NULL, FALSE);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
    switch (Message){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            HDC hdcMem = CreateCompatibleDC(hdc);
            HBITMAP hbmMem = CreateCompatibleBitmap(hdc, SCREENWIDTH, SCREENHEIGHT);
            HBITMAP hbm = (HBITMAP)SelectObject(hdcMem, hbmMem);
            HBRUSH background = CreateSolidBrush(0xbfbfbf);
            FillRect(hdcMem, &screen, background);
            mainpaint(hdcMem);
            BitBlt(hdc, 0, 0, SCREENWIDTH, SCREENHEIGHT, hdcMem, 0, 0, SRCCOPY);
            SelectObject(hdcMem, hbm);
            DeleteObject(hbmMem);
            DeleteDC(hdcMem);
            DeleteObject(background);
            EndPaint(hwnd, &ps);
            // 触发自动对弈
            if (!winner) {
                 // 通过发送自定义消息或Timer来驱动AI,避免阻塞UI太久
                 // 这里简单处理:如果不是重绘导致的循环,可以延迟执行
                 // 但为了简单,我们在 Timer 里处理
            }
            break;
        }
        case WM_CREATE:
            turn = 1; // 黑棋先走
            winner = 0;
            step_count = 0;
            memset(board, 0, sizeof(board));
            board[3][3] = board[4][4] = 2; 
            board[3][4] = board[4][3] = 1; 
            SetTimer(hwnd, 1, 500, NULL); // 设置定时器驱动AI
            break;

        case WM_TIMER:
            if (!winner) {
                processTurns(hwnd);
            }
            break;

        case WM_KEYDOWN: 
            if (wParam == 'R') { // Press R to reset
                turn = 1; winner = 0; step_count = 0;
                memset(board, 0, sizeof(board));
                board[3][3] = board[4][4] = 2; 
                board[3][4] = board[4][3] = 1; 
                InvalidateRect(hwnd, NULL, FALSE);
            }
            break;

        case WM_DESTROY:
            KillTimer(hwnd, 1);
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE _0, HINSTANCE _1, LPSTR _2, int _3){
    RECT rcClient = {0, 0, SCREENWIDTH, SCREENHEIGHT};
    const DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
    if (!registerWindow(_0, WndProc, "ReversiAI")) return 0;
    AdjustWindowRect(&rcClient, style, FALSE);
    int w = rcClient.right - rcClient.left;
    int h = rcClient.bottom - rcClient.top;
    if (createWindow(_0, "ReversiAI", "Black (Super) vs White (Old)", style,
        GetSystemMetrics(SM_CXSCREEN)/2 - w/2, GetSystemMetrics(SM_CYSCREEN)/2 - h/2, w, h)) return 0;
    return mainloop();
}

:::

:::info[加强加强可悔棋重开版]

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#define SCREENWIDTH 640
#define SCREENHALFWIDTH 320
#define SCREENHEIGHT 640
#define SCREENHALFHEIGHT 320
#define WIDTH 70
#define HEIGHT 70
#define HALFSIZE 30
#define MAPLEFT (SCREENHALFWIDTH - (WIDTH << 2))
#define MAPRIGHT (SCREENHALFWIDTH + (WIDTH << 2))
#define MAPTOP (SCREENHALFHEIGHT - (HEIGHT << 2))
#define MAPBOTTOM (SCREENHALFHEIGHT + (HEIGHT << 2))

// 8个方向
const int dir[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};

// 基础权重表
const int weights[8][8] = {
    { 500, -25,  10,   5,   5,  10, -25, 500},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {   5,   1,   2,   1,   1,   2,   1,   5},
    {  10,   1,   3,   2,   2,   3,   1,  10},
    { -25, -45,   1,   1,   1,   1, -45, -25},
    { 500, -25,  10,   5,   5,  10, -25, 500}
};

const RECT screen = {0, 0, SCREENWIDTH, SCREENHEIGHT};

// --- 全局变量 ---
int board[8][8];
// 悔棋堆栈
int history[64][8][8]; 
int step_count = 0;

int clickx, clicky;
int turn; // 1=黑(人类), 2=白(Super AI)
int winner; // 0=无, 1=黑, 2=白, 3=平局

// 函数声明
void computerMove_Super(HWND hwnd);
BOOL hasValidMove(int player);
void checkGameOver();

ATOM registerWindow(HINSTANCE hInstance, WNDPROC WndProc, LPCSTR className){
    WNDCLASSEXA wc;
    memset(&wc, 0, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEXA);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = className;
    wc.hIcon = LoadIconA(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIconA(NULL, IDI_APPLICATION);
    return RegisterClassExA(&wc);
}

BOOL createWindow(HINSTANCE hInstance, LPCSTR className, LPCSTR title, DWORD style, int x, int y, int width, int height){
    return CreateWindowExA(WS_EX_CLIENTEDGE, className, title, style, x, y, width, height, NULL, NULL, hInstance, NULL) == NULL;
}

WPARAM mainloop(){
    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)){
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    return msg.wParam;
}

void maptoscreen(int *const x, int *const y, int clx, int cly){
    *x = MAPLEFT + clx * WIDTH + (WIDTH >> 1);
    *y = MAPTOP + cly * HEIGHT + (HEIGHT >> 1);
}

void paintmap(HDC hdc){
    int i;
    HBRUSH bgBrush = CreateSolidBrush(0x008000); 
    RECT mapRect = {MAPLEFT, MAPTOP, MAPRIGHT, MAPBOTTOM};
    FillRect(hdc, &mapRect, bgBrush);
    DeleteObject(bgBrush);
    for (i = MAPLEFT; i <= MAPRIGHT; i += WIDTH){
        MoveToEx(hdc, i, MAPTOP, NULL);
        LineTo(hdc, i, MAPBOTTOM);
    }
    for (i = MAPTOP; i <= MAPBOTTOM; i += HEIGHT){
        MoveToEx(hdc, MAPLEFT, i, NULL);
        LineTo(hdc, MAPRIGHT, i);
    }
}

void paintpieces(HDC hdc){
    HBRUSH oldbrush, blackBrush, whiteBrush;
    HPEN oldpen, nullPen;
    int i, j, x, y;

    blackBrush = CreateSolidBrush(0x000000);
    whiteBrush = CreateSolidBrush(0xFFFFFF);
    nullPen = CreatePen(PS_NULL, 0, 0);
    oldpen = (HPEN)SelectObject(hdc, nullPen);
    for (i = 0; i < 8; ++i){
        for (j = 0; j < 8; ++j){
            if (board[i][j] != 0) {
                maptoscreen(&x, &y, i, j);
                oldbrush = (HBRUSH)SelectObject(hdc, (board[i][j] == 1) ? blackBrush : whiteBrush);
                Ellipse(hdc, x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE);
                SelectObject(hdc, oldbrush);
            }
        }
    }
    SelectObject(hdc, oldpen);
    DeleteObject(blackBrush);
    DeleteObject(whiteBrush);
    DeleteObject(nullPen);
}

void paintinfo(HDC hdc){
    SetTextAlign(hdc, TA_CENTER);
    SetBkMode(hdc, TRANSPARENT);
    char buf[128];
    if (winner) {
        if (winner == 1) lstrcpyA(buf, "Black (Human) Wins! (Press 'R' to Reset)");
        else if (winner == 2) lstrcpyA(buf, "White (Super AI) Wins! (Press 'R' to Reset)");
        else lstrcpyA(buf, "Draw! (Press 'R' to Reset)");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    } else {
        if (turn == 1) lstrcpyA(buf, "Your Turn (Black) - Press 'Z' to Undo");
        else lstrcpyA(buf, "Super AI (White) Thinking...");
        TextOutA(hdc, SCREENHALFWIDTH, 10, buf, lstrlenA(buf));
    }
}

void mainpaint(HDC hdc){
    paintmap(hdc);
    paintpieces(hdc);
    paintinfo(hdc);
}

// --- 游戏逻辑 ---

BOOL isInside(int x, int y) {
    return x >= 0 && x < 8 && y >= 0 && y < 8;
}

// 悔棋保存
void saveState() {
    if (step_count < 64) {
        memcpy(history[step_count], board, sizeof(board));
        step_count++;
    }
}

// 悔棋执行
void undo() {
    // 因为是人机对战,悔棋通常意味着悔两步(回到玩家上一步),或者一步(如果轮到电脑下但还没下)
    // 简单起见,我们假设必须回到玩家的回合。
    // 如果现在是玩家回合(turn=1),我们要撤销 电脑的一步 + 玩家的一步 = 2步
    if (step_count >= 2 && turn == 1 && winner == 0) {
        step_count -= 2;
        memcpy(board, history[step_count], sizeof(board));
        turn = 1;
    } 
    // 如果游戏结束了,可能也只要撤销1步或2步
    else if (winner != 0 && step_count > 0) {
        step_count--; // 简单回退一步看看
        memcpy(board, history[step_count], sizeof(board));
        winner = 0;
        turn = 1; // 强制回玩家
    }
}

int executeMoveLogic(int tempBoard[8][8], int x, int y, int player, BOOL dryRun) {
    if (tempBoard[x][y] != 0) return 0;

    int opponent = 3 - player;
    int totalFlipped = 0;
    for (int k = 0; k < 8; k++) {
        int dx = dir[k][0];
        int dy = dir[k][1];
        int nx = x + dx;
        int ny = y + dy;
        int flipped = 0;
        while (isInside(nx, ny) && tempBoard[nx][ny] == opponent) {
            nx += dx;
            ny += dy;
            flipped++;
        }
        if (flipped > 0 && isInside(nx, ny) && tempBoard[nx][ny] == player) {
            totalFlipped += flipped;
            if (!dryRun) {
                int cx = x + dx;
                int cy = y + dy;
                while (cx != nx || cy != ny) {
                    tempBoard[cx][cy] = player;
                    cx += dx;
                    cy += dy;
                }
            }
        }
    }
    if (!dryRun && totalFlipped > 0) {
        tempBoard[x][y] = player;
    }
    return totalFlipped;
}

BOOL cango(int x, int y) {
    return executeMoveLogic(board, x, y, turn, TRUE) > 0;
}

void makeMove(int x, int y, int player) {
    executeMoveLogic(board, x, y, player, FALSE);
}

int getmouse(HWND hwnd, int *const x, int *const y){
    *x = (*x - MAPLEFT) / WIDTH - (*x < MAPLEFT ? 1 : 0);
    *y = (*y - MAPTOP) / HEIGHT - (*y < MAPTOP ? 1 : 0);
    if (*x < 0 || *x >= 8 || *y < 0 || *y >= 8){
        return 256;
    }
    if (!cango(*x, *y)){
        return 16;
    }
    return 0;
}

int countValidMoves(int b[8][8], int player) {
    int count = 0;
    for (int i = 0; i < 8; i++) 
        for (int j = 0; j < 8; j++) 
            if (executeMoveLogic(b, i, j, player, TRUE) > 0) count++;
    return count;
}

int countDiscs(int b[8][8]) {
    int count = 0;
    for(int i=0; i<8; i++) 
        for(int j=0; j<8; j++) 
            if(b[i][j] != 0) count++;
    return count;
}

// -------------------------------------------------------------
// Super AI (White / Player 2) Implementation
// -------------------------------------------------------------

// 动态权重:如果角被占,旁边就变安全
int getDynamicWeight(int b[8][8], int x, int y) {
    int w = weights[x][y];
    if (x <= 1 && y <= 1 && b[0][0] != 0) return 50;
    else if (x >= 6 && y <= 1 && b[7][0] != 0) return 50;
    else if (x <= 1 && y >= 6 && b[0][7] != 0) return 50;
    else if (x >= 6 && y >= 6 && b[7][7] != 0) return 50;
    return w;
}

int evaluateBoardSuper(int b[8][8], int player) {
    int opponent = 3 - player;
    int myTiles = 0, oppTiles = 0;
    int myFrontier = 0, oppFrontier = 0;
    int score = 0;

    for(int i=0; i<8; i++) {
        for(int j=0; j<8; j++) {
            if (b[i][j] == 0) continue;

            int w = getDynamicWeight(b, i, j);
            if(b[i][j] == player) { score += w; myTiles++; } 
            else { score -= w; oppTiles++; }

            // Frontier Discs
            int isFrontier = 0;
            for (int k = 0; k < 8; k++) {
                int nx = i + dir[k][0]; int ny = j + dir[k][1];
                if (nx >= 0 && nx < 8 && ny >= 0 && ny < 8 && b[nx][ny] == 0) {
                    isFrontier = 1; break;
                }
            }
            if (isFrontier) { if (b[i][j] == player) myFrontier++; else oppFrontier++; }
        }
    }

    int totalDiscs = myTiles + oppTiles;

    // 终局:完全计算棋子数
    if (totalDiscs > 58) return (myTiles - oppTiles) * 10000;

    // 行动力压制
    int myMoves = countValidMoves(b, player);
    int oppMoves = countValidMoves(b, opponent);
    score += (myMoves - oppMoves) * 500; 

    // 边界子惩罚
    score -= (myFrontier - oppFrontier) * 100;

    // 蒸发策略 (Evaporation): 前期棋子越少越好
    if (totalDiscs <= 45) {
        score -= (myTiles - oppTiles) * 5; 
    } else {
        score += (myTiles - oppTiles) * 10;
    }

    // 角的控制
    int corners[4][2] = {{0,0}, {0,7}, {7,0}, {7,7}};
    for(int i=0; i<4; i++) {
        if (b[corners[i][0]][corners[i][1]] == player) score += 1000; 
        else if (b[corners[i][0]][corners[i][1]] == opponent) score -= 1000;
    }
    return score;
}

typedef struct { int x, y, score; } MoveScore;

int compareMoves(const void *a, const void *b) {
    return ((MoveScore*)b)->score - ((MoveScore*)a)->score;
}

// 增强版 Minimax
int minimaxSuper(int b[8][8], int depth, int alpha, int beta, int currentPlayer, int maximizingPlayer) {
    if (depth == 0) return evaluateBoardSuper(b, maximizingPlayer);

    int opponent = 3 - currentPlayer;
    MoveScore moves[64];
    int moveCount = 0;

    // 生成走法并预估分
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(b, i, j, currentPlayer, TRUE) > 0) {
                moves[moveCount].x = i;
                moves[moveCount].y = j;
                moves[moveCount].score = getDynamicWeight(b, i, j);
                moveCount++;
            }
        }
    }

    if (moveCount == 0) {
        if (countValidMoves(b, opponent) == 0) {
            int finalScore = 0;
             for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
                 if(b[i][j] == maximizingPlayer) finalScore++; else if(b[i][j] != 0) finalScore--;
             }
             if (finalScore > 0) return 200000 + finalScore;
             if (finalScore < 0) return -200000 + finalScore;
             return 0;
        }
        return minimaxSuper(b, depth, alpha, beta, opponent, maximizingPlayer);
    }

    // 移动排序
    qsort(moves, moveCount, sizeof(MoveScore), compareMoves);

    int tempBoard[8][8];
    int bestVal = (currentPlayer == maximizingPlayer) ? -9999999 : 9999999;

    for (int k = 0; k < moveCount; k++) {
        memcpy(tempBoard, b, sizeof(int)*64);
        executeMoveLogic(tempBoard, moves[k].x, moves[k].y, currentPlayer, FALSE);

        int val = minimaxSuper(tempBoard, depth - 1, alpha, beta, opponent, maximizingPlayer);

        if (currentPlayer == maximizingPlayer) {
            if (val > bestVal) bestVal = val;
            if (val > alpha) alpha = val;
        } else {
            if (val < bestVal) bestVal = val;
            if (val < beta) beta = val;
        }
        if (beta <= alpha) break;
    }
    return bestVal;
}

void computerMove_Super(HWND hwnd) {
    int bestScore = -9999999;
    int bestMove[2] = {-1, -1};
    int alpha = -9999999;
    int beta = 9999999;

    int discs = countDiscs(board);
    // 动态深度:中局 8,终局 12
    int depth = 8; 
    if (discs > 50) depth = 12;

    int aiPlayer = 2; // 白棋

    MoveScore moves[64];
    int moveCount = 0;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (executeMoveLogic(board, i, j, aiPlayer, TRUE) > 0) {
                moves[moveCount].x = i;
                moves[moveCount].y = j;
                moves[moveCount].score = getDynamicWeight(board, i, j);
                moveCount++;
            }
        }
    }
    qsort(moves, moveCount, sizeof(MoveScore), compareMoves);

    for (int k = 0; k < moveCount; k++) {
        int i = moves[k].x;
        int j = moves[k].y;

        int tempBoard[8][8];
        memcpy(tempBoard, board, sizeof(board));
        executeMoveLogic(tempBoard, i, j, aiPlayer, FALSE);

        // AI 是白棋(2),maximizingPlayer = 2
        int score = minimaxSuper(tempBoard, depth - 1, alpha, beta, 1, aiPlayer);

        if (score > bestScore) {
            bestScore = score;
            bestMove[0] = i;
            bestMove[1] = j;
        }
        if (score > alpha) alpha = score;
    }

    if (bestMove[0] != -1) {
        makeMove(bestMove[0], bestMove[1], aiPlayer);
        RECT xrect = {0,0,SCREENWIDTH, SCREENHEIGHT};
        InvalidateRect(hwnd, &xrect, FALSE);
        UpdateWindow(hwnd); 
    }
}

// -------------------------------------------------------------
// 主流程控制
// -------------------------------------------------------------

BOOL hasValidMove(int player) {
    for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) 
        if (executeMoveLogic(board, i, j, player, TRUE) > 0) return TRUE;
    return FALSE;
}

void checkGameOver() {
    if (!hasValidMove(1) && !hasValidMove(2)) {
        int blackCount = 0, whiteCount = 0;
        for(int i=0; i<8; i++) for(int j=0; j<8; j++) {
            if(board[i][j] == 1) blackCount++;
            else if(board[i][j] == 2) whiteCount++;
        }
        if (blackCount > whiteCount) winner = 1;
        else if (whiteCount > blackCount) winner = 2;
        else winner = 3;
    }
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
    switch (Message){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            HDC hdcMem = CreateCompatibleDC(hdc);
            HBITMAP hbmMem = CreateCompatibleBitmap(hdc, SCREENWIDTH, SCREENHEIGHT);
            HBITMAP hbm = (HBITMAP)SelectObject(hdcMem, hbmMem);
            HBRUSH background = CreateSolidBrush(0xbfbfbf);
            FillRect(hdcMem, &screen, background);
            mainpaint(hdcMem);
            BitBlt(hdc, 0, 0, SCREENWIDTH, SCREENHEIGHT, hdcMem, 0, 0, SRCCOPY);
            SelectObject(hdcMem, hbm);
            DeleteObject(hbmMem);
            DeleteDC(hdcMem);
            DeleteObject(background);
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_CREATE:
            turn = 1;
            winner = 0;
            step_count = 0; 
            memset(board, 0, sizeof(board));
            board[3][3] = board[4][4] = 2; 
            board[3][4] = board[4][3] = 1; 
            break;

        case WM_KEYDOWN: 
            if (wParam == 'Z') { // Undo
                if (step_count > 0 && turn == 1 && !winner) {
                    undo();
                    InvalidateRect(hwnd, NULL, FALSE);
                }
            } else if (wParam == 'R') { // Reset
                turn = 1; winner = 0; step_count = 0;
                memset(board, 0, sizeof(board));
                board[3][3] = board[4][4] = 2; 
                board[3][4] = board[4][3] = 1; 
                InvalidateRect(hwnd, NULL, FALSE);
            }
            break;

        case WM_LBUTTONDOWN:
            if (turn != 1 || winner) break; // 只能在玩家回合(黑)点击

            clickx = LOWORD(lParam);
            clicky = HIWORD(lParam);

            if (getmouse(hwnd, &clickx, &clicky) == 0){
                // 1. 玩家下棋
                saveState(); // 存一步玩家
                makeMove(clickx, clicky, 1);

                RECT updrect = {0, 0, SCREENWIDTH, SCREENHEIGHT};
                InvalidateRect(hwnd, &updrect, FALSE);
                UpdateWindow(hwnd); 

                checkGameOver();
                if (winner) break;

                // 2. 轮到 AI
                turn = 2; 
                if (hasValidMove(2)) {
                    // 存一步电脑前的状态(为了undo能回退2步回到这里)
                    saveState(); 

                    // 稍微延迟一下,体验更好
                    Sleep(100); 

                    computerMove_Super(hwnd); // 执行白棋 Super AI

                    checkGameOver();
                    if (winner) break;

                    // AI 走完,交还给玩家
                    if (hasValidMove(1)) {
                        turn = 1;
                    } else {
                        // 如果玩家无路可走,AI 继续
                        while (hasValidMove(2) && !hasValidMove(1)) {
                             MessageBoxA(hwnd, "Black Passes! (No valid moves)", "Info", MB_OK);
                             saveState();
                             Sleep(500);
                             computerMove_Super(hwnd);
                             checkGameOver();
                             if (winner) break;
                        }
                        if (!winner) turn = 1;
                    }
                } else {
                    // AI 无路可走
                    MessageBoxA(hwnd, "White Passes! (No valid moves)", "Info", MB_OK);
                    if (hasValidMove(1)) turn = 1;
                    else checkGameOver();
                }
                InvalidateRect(hwnd, &updrect, FALSE);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE _0, HINSTANCE _1, LPSTR _2, int _3){
    RECT rcClient = {0, 0, SCREENWIDTH, SCREENHEIGHT};
    const DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
    if (!registerWindow(_0, WndProc, "ReversiHumanVsSuperAI")) return 0;
    AdjustWindowRect(&rcClient, style, FALSE);
    int w = rcClient.right - rcClient.left;
    int h = rcClient.bottom - rcClient.top;
    if (createWindow(_0, "ReversiHumanVsSuperAI", "Human (Black) vs Super AI (White)", style,
        GetSystemMetrics(SM_CXSCREEN)/2 - w/2, GetSystemMetrics(SM_CYSCREEN)/2 - h/2, w, h)) return 0;
    return mainloop();
}

:::

五子棋

:::info[普通版]

#include <windows.h>
#include <stdlib.h>
#include <time.h>

#ifdef UNICODE
#define TSTR(quote) L##quote
#else
#define TSTR(quote) quote
#endif

#define SCREENWIDTH 640
#define SCREENHALFWIDTH 320
#define SCREENHEIGHT 640
#define SCREENHALFHEIGHT 320
#define WIDTH 36
#define HEIGHT 38
#define HALFSIZE 15
#define LINELEFT (SCREENHALFWIDTH - WIDTH * 7)
#define LINERIGHT (SCREENHALFWIDTH + WIDTH * 7)
#define LINETOP (SCREENHALFHEIGHT - HEIGHT * 7)
#define LINEBOTTOM (SCREENHALFHEIGHT + HEIGHT * 7)
#define MAPLEFT (LINELEFT - (WIDTH >> 1))
#define MAPTOP (LINETOP - (HEIGHT >> 1))

const RECT screen = {0, 0, SCREENWIDTH, SCREENHEIGHT};
int mapcolor[15][15]; // 0:空, 1:黑(玩家), 2:白(电脑)
int clickx, clicky;
int turn, winner; // turn=1(玩家回合), turn=2(电脑回合)

// 注册窗口类
ATOM registerWindow(HINSTANCE hInstance, WNDPROC WndProc, LPSTR className){
    WNDCLASSEX wc;
    memset(&wc, 0, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = className;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    return RegisterClassEx(&wc);
}

// 创建窗口
BOOL createWindow(HINSTANCE hInstance, LPSTR className, LPSTR title, DWORD style, int x, int y, int width, int height){
    return CreateWindowEx(WS_EX_CLIENTEDGE, className, title, style,
        x, y, width, height,
        NULL, NULL, hInstance, NULL) == NULL;
}

// 消息循环
WPARAM mainloop(){
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

// 坐标转换:棋盘格 -> 屏幕像素
void maptoscreen(int *const x, int *const y, int clx, int cly){
    *x = LINELEFT + clx * WIDTH;
    *y = LINETOP + cly * HEIGHT;
}

// 绘制棋盘
void paintmap(HDC hdc){
    int i, x, y;
    HBRUSH oldbrush, dotbrush, background = CreateSolidBrush(0x268cd8);
    const RECT back = {MAPLEFT, MAPTOP,
        LINERIGHT + WIDTH - (WIDTH >> 1),
        LINEBOTTOM + HEIGHT - (HEIGHT >> 1)};
    FillRect(hdc, &back, background);
    DeleteObject(background);
    for (i = LINELEFT; i <= LINERIGHT; i += WIDTH){
        MoveToEx(hdc, i, LINETOP, NULL);
        LineTo(hdc, i, LINEBOTTOM);
    }
    for (i = LINETOP; i <= LINEBOTTOM; i += HEIGHT){
        MoveToEx(hdc, LINELEFT, i, NULL);
        LineTo(hdc, LINERIGHT, i);
    }
    // 绘制五个星位
    dotbrush = CreateSolidBrush(0);
    oldbrush = (HBRUSH)SelectObject(hdc, dotbrush);
    int stars[5][2] = {{3,3}, {3,11}, {7,7}, {11,3}, {11,11}};
    for(int k=0; k<5; k++){
        maptoscreen(&x, &y, stars[k][0], stars[k][1]);
        Ellipse(hdc, x - 4, y - 4, x + 4, y + 4);
    }
    SelectObject(hdc, oldbrush);
    DeleteObject(dotbrush);
}

// 绘制棋子
void paintdot(HDC hdc){
    HBRUSH oldbrush, dotbrush;
    int i, j, x, y;

    // 画黑棋
    dotbrush = CreateSolidBrush(0);
    oldbrush = (HBRUSH)SelectObject(hdc, dotbrush);
    for (i = 0; i <= 14; ++i){
        for (j = 0; j <= 14; ++j){
            if (mapcolor[i][j] == 1){
                maptoscreen(&x, &y, i, j);
                Ellipse(hdc, x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE);
            }
        }
    }
    SelectObject(hdc, oldbrush);
    DeleteObject(dotbrush);

    // 画白棋
    dotbrush = CreateSolidBrush(0xffffff);
    oldbrush = (HBRUSH)SelectObject(hdc, dotbrush);
    for (i = 0; i <= 14; ++i){
        for (j = 0; j <= 14; ++j){
            if (mapcolor[i][j] == 2){
                maptoscreen(&x, &y, i, j);
                Ellipse(hdc, x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE);
            }
        }
    }
    SelectObject(hdc, oldbrush);
    DeleteObject(dotbrush);
}

// 绘制胜负信息
void paintinfo(HDC hdc){
    SetTextAlign(hdc, TA_CENTER);
    SetBkMode(hdc, TRANSPARENT);
    switch (winner){
        case 1:
            TextOutA(hdc, SCREENHALFWIDTH, 10, "Black (Player) Wins!", 20);
            break;
        case 2:
            TextOutA(hdc, SCREENHALFWIDTH, 10, "White (Computer) Wins!", 22);
            break;
    }
}

void mainpaint(HDC hdc){
    paintmap(hdc);
    paintdot(hdc);
    paintinfo(hdc);
}

// 获取鼠标点击的棋盘坐标
int getmouse(HWND hwnd, int *const x, int *const y){
    *x = (*x - MAPLEFT) / WIDTH - (*x < MAPLEFT ? 1 : 0);
    *y = (*y - MAPTOP) / HEIGHT - (*y < MAPTOP ? 1 : 0);
    if (*x < 0 || *x >= 15 || *y < 0 || *y >= 15){
        return 256;
    }
    if (mapcolor[*x][*y]){
        return 16;
    }
    return 0;
}

// 检查特定方向是否有5连
int checklinemode(int x, int y, int mode){
    if (x < 0 || y < 0 || x > 18 || y > 18) return 0;
    // 原有的胜负判定逻辑保留
    switch (mode){
        case 1: // 纵向
            return y <= 14 ? mapcolor[x][y] & mapcolor[x][y + 1] & mapcolor[x][y + 2] & mapcolor[x][y + 3] & mapcolor[x][y + 4] : 0;
        case 2: // 横向
            return x <= 14 ? mapcolor[x][y] & mapcolor[x + 1][y] & mapcolor[x + 2][y] & mapcolor[x + 3][y] & mapcolor[x + 4][y] : 0;
        case 3: // 左上到右下
            return x <= 14 && y <= 14 ? mapcolor[x][y] & mapcolor[x + 1][y + 1] & mapcolor[x + 2][y + 2] & mapcolor[x + 3][y + 3] & mapcolor[x + 4][y + 4] : 0;
        case 4: // 右上到左下
            return x >= 4 && y <= 14 ? mapcolor[x][y] & mapcolor[x - 1][y + 1] & mapcolor[x - 2][y + 2] & mapcolor[x - 3][y + 3] & mapcolor[x - 4][y + 4] : 0;
    }
    return 0;
}

// 检查胜负
void checkline(int lx, int ly){
    int x, y;
    for (y = ly - 4; y <= ly; ++y) if (winner = checklinemode(lx, y, 1)) return;
    for (x = lx - 4; x <= lx; ++x) if (winner = checklinemode(x, ly, 2)) return;
    for (x = lx - 4, y = ly - 4; x <= lx; ++x, ++y) if (winner = checklinemode(x, y, 3)) return;
    for (x = lx + 4, y = ly - 4; y <= ly; --x, ++y) if (winner = checklinemode(x, y, 4)) return;
}

// ==========================================
// AI 核心逻辑开始
// ==========================================

// 评估某个方向上的连子情况
// return: 该方向的得分
int evaluateLine(int x, int y, int dx, int dy, int color) {
    int count = 1; // 包含当前位置
    int block = 0; // 被封堵的端点数
    int empty = -1; // 空位位置(暂未完全利用,可用于更高级AI)

    // 正向搜索
    int i, tempX, tempY;
    for (i = 1; i <= 4; i++) {
        tempX = x + dx * i;
        tempY = y + dy * i;
        if (tempX < 0 || tempX >= 15 || tempY < 0 || tempY >= 15) {
            block++;
            break;
        }
        if (mapcolor[tempX][tempY] == color) {
            count++;
        } else if (mapcolor[tempX][tempY] == 0) {
            empty = i; // 记录第一个空位
            break;
        } else {
            block++;
            break;
        }
    }

    // 反向搜索
    for (i = 1; i <= 4; i++) {
        tempX = x - dx * i;
        tempY = y - dy * i;
        if (tempX < 0 || tempX >= 15 || tempY < 0 || tempY >= 15) {
            block++;
            break;
        }
        if (mapcolor[tempX][tempY] == color) {
            count++;
        } else if (mapcolor[tempX][tempY] == 0) {
            break;
        } else {
            block++;
            break;
        }
    }

    // 评分规则 (权重可调整)
    if (count >= 5) return 200000; // 成5 (必胜)
    if (block == 0) {
        if (count == 4) return 50000; // 活4
        if (count == 3) return 3000;  // 活3
        if (count == 2) return 400;   // 活2
        if (count == 1) return 10;
    } else if (block == 1) {
        if (count == 4) return 2500;  // 冲4 (死4)
        if (count == 3) return 50;    // 死3
        if (count == 2) return 5;     // 死2
    }
    return 0; // 两头堵死或无子
}

// 获取某点对于某颜色的总评分
int getPointScore(int x, int y, int color) {
    int score = 0;
    // 四个方向:横、纵、左斜、右斜
    score += evaluateLine(x, y, 1, 0, color);
    score += evaluateLine(x, y, 0, 1, color);
    score += evaluateLine(x, y, 1, 1, color);
    score += evaluateLine(x, y, 1, -1, color);
    return score;
}

// 电脑执行落子
void computerMove(HWND hwnd) {
    int x, y;
    int maxScore = -1;
    int bestX = 7, bestY = 7; // 默认中心
    int myScore, enemyScore, totalScore;

    // 如果棋盘全满(平局处理,简单判断)
    int full = 1;

    for (x = 0; x < 15; x++) {
        for (y = 0; y < 15; y++) {
            if (mapcolor[x][y] == 0) {
                full = 0;

                // 1. 进攻分:如果电脑下这,对电脑多有利
                myScore = getPointScore(x, y, 2); 

                // 2. 防守分:如果黑棋下这,对黑棋多有利(电脑必须拦截)
                enemyScore = getPointScore(x, y, 1);

                // 综合评分:进攻 + 防守
                // 可以在这里调整攻防权重。通常防守稍微重要一点,但如果自己能赢(myScore极高)则优先
                if (myScore >= 200000) {
                    // 如果自己能赢,直接下,不用管防守
                    totalScore = 2000000;
                } else if (enemyScore >= 200000) {
                     // 对手要赢了,必须堵,且优先级仅次于自己赢
                     totalScore = 1000000;
                } else {
                    // 普通情况,权衡攻守。略微偏重防守以稳健为主
                    totalScore = myScore + enemyScore;
                }

                // 增加一点随机性避免走法完全固定(可选)
                // totalScore += (rand() % 10); 

                if (totalScore > maxScore) {
                    maxScore = totalScore;
                    bestX = x;
                    bestY = y;
                }
            }
        }
    }

    if (full) return; // 棋盘满了

    // 执行落子
    mapcolor[bestX][bestY] = 2; // 电脑是2(白)

    // 检查胜负
    checkline(bestX, bestY);

    // 刷新界面
    RECT updrect;
    int sx, sy;
    maptoscreen(&sx, &sy, bestX, bestY);
    SetRect(&updrect, sx - HALFSIZE, sy - HALFSIZE, sx + HALFSIZE, sy + HALFSIZE);
    InvalidateRect(hwnd, &updrect, FALSE); // 局部刷新

    if (winner) {
         RECT allrect = {0, 0, SCREENWIDTH, 100};
         InvalidateRect(hwnd, &allrect, FALSE); // 刷新顶部文字
    }

    turn = 1; // 轮到玩家
}

// ==========================================
// AI 逻辑结束
// ==========================================

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
    switch (Message){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            HDC hdcMem = CreateCompatibleDC(hdc);
            HBITMAP hbmMem = CreateCompatibleBitmap(hdc, SCREENWIDTH, SCREENHEIGHT);
            HBITMAP hbm = (HBITMAP)SelectObject(hdcMem, hbmMem);
            HBRUSH background = CreateSolidBrush(0xffffff);
            FillRect(hdcMem, &screen, background);
            mainpaint(hdcMem);
            BitBlt(hdc, 0, 0, SCREENWIDTH, SCREENHEIGHT, hdcMem, 0, 0, SRCCOPY);
            SelectObject(hdcMem, hbm);
            DeleteObject(hbmMem);
            DeleteDC(hdcMem);
            DeleteObject(background);
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_CREATE:
            srand((unsigned)time(NULL)); // 初始化随机种子
            turn = 1;
            winner = 0;
            break;
        case WM_LBUTTONDOWN:
            // 如果已分胜负或不是玩家回合,忽略点击
            if (winner || turn != 1) break;

            clickx = LOWORD(lParam);
            clicky = HIWORD(lParam);

            // 玩家落子验证
            if (getmouse(hwnd, &clickx, &clicky)){
                break;
            }

            // 玩家(黑)落子
            mapcolor[clickx][clicky] = 1; 
            checkline(clickx, clicky);

            // 刷新玩家落子区域
            {
                int x, y;
                maptoscreen(&x, &y, clickx, clicky);
                RECT updrect = {x - HALFSIZE, y - HALFSIZE, x + HALFSIZE, y + HALFSIZE};
                InvalidateRect(hwnd, &updrect, FALSE);
            }

            if (winner){
                RECT updrect = {0, 0, SCREENWIDTH, 100};
                InvalidateRect(hwnd, &updrect, FALSE);
            } else {
                // 玩家没赢,且棋盘未满,轮到电脑下
                turn = 2;
                // 为了让玩家看到落子过程,强制立即重绘一次玩家的棋子
                UpdateWindow(hwnd); 
                // 电脑思考并落子
                computerMove(hwnd);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE _0, HINSTANCE _1, LPSTR _2, int _3){
    RECT rcClient = {0, 0, SCREENWIDTH, SCREENHEIGHT};
    const DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
    WPARAM wParam;
    int realwidth, realheight;
    if (!registerWindow(_0, WndProc, TSTR("Gomoku"))){
        MessageBox(NULL, TSTR("Window Registration Failed!"), TSTR("Error!"), MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    AdjustWindowRect(&rcClient, style, FALSE);
    realwidth = rcClient.right - rcClient.left;
    realheight = rcClient.bottom - rcClient.top;
    if (createWindow(_0, TSTR("Gomoku"), TSTR("五子棋 (人机对战)"), style,
        GetSystemMetrics(SM_CXSCREEN) - realwidth >> 1,
        GetSystemMetrics(SM_CYSCREEN) - realheight >> 1,
        realwidth, realheight)){
        MessageBox(NULL, TSTR("Window Creation Failed!"), TSTR("Error!"), MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    wParam = mainloop();
    return wParam;
}

:::