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

// 手动定义CP_GBK(解决未定义报错)
#ifndef CP_GBK
#define CP_GBK 936
#endif

// 棋盘尺寸与评分常量
#define BOARD_SIZE 15
#define MAX_SCORE 100000
#define MIN_SCORE -100000

// 难度枚举
typedef enum {
    EASY,    // 简单:随机落子+基础封堵
    MEDIUM,  // 中等:评分落子+优先封堵
    HARD     // 困难:深度评分+攻防最优
} Difficulty;

// 棋子类型定义
typedef enum {
    EMPTY,   // 空位置
    BLACK,   // 黑棋(玩家)
    WHITE    // 白棋(AI)
} ChessType;

// 全局变量
ChessType board[BOARD_SIZE][BOARD_SIZE]; // 棋盘数组
int currentX = 0, currentY = 0;          // 玩家光标坐标
int gameOver = 0;                        // 游戏结束标记
int lastX = -1, lastY = -1;              // 上一步落子位置(悔棋用)
Difficulty gameDiff = MEDIUM;            // 默认难度:中等

// 重绘控制变量
int needRedraw = 1;                      // 标记是否需要重绘棋盘
int firstDraw = 1;                       // 控制首次清屏

// 设置控制台光标位置
void setCursorPos(int x, int y) {
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 隐藏控制台光标
void hideCursor() {
    CONSOLE_CURSOR_INFO cci;
    cci.bVisible = FALSE;
    cci.dwSize = 1;
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}

// 选择游戏难度
void selectDifficulty() {
    system("cls");
    int select = 1; // 默认选中中等难度
    printf("===================== 选择游戏难度 =====================\n");
    printf("请按 ↑/↓ 选择难度,按 空格 确认\n");
    printf("=======================================================\n");
    
    while (1) {
        setCursorPos(0, 4);
        printf(select == 0 ? "→ 简单:AI随机落子,容易获胜\n" : "  简单:AI随机落子,容易获胜\n");
        printf(select == 1 ? "→ 中等:AI智能封堵,有挑战性\n" : "  中等:AI智能封堵,有挑战性\n");
        printf(select == 2 ? "→ 困难:AI攻防最优,难度较高\n" : "  困难:AI攻防最优,难度较高\n");

        // 处理按键
        if (_kbhit()) {
            char key = _getch();
            switch (key) {
                case 'w': case 'W': case 72: // 上键(72是方向键ASCII)
                    select = (select - 1 + 3) % 3;
                    break;
                case 's': case 'S': case 80: // 下键(80是方向键ASCII)
                    select = (select + 1) % 3;
                    break;
                case ' ': // 确认选择
                    if (select == 0) gameDiff = EASY;
                    else if (select == 1) gameDiff = MEDIUM;
                    else gameDiff = HARD;
                    return;
            }
        }
        Sleep(50);
    }
}

// 初始化棋盘
void initBoard() {
    // 清空棋盘
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            board[i][j] = EMPTY;
        }
    }
    // 重置游戏状态
    currentX = BOARD_SIZE / 2;
    currentY = BOARD_SIZE / 2;
    gameOver = 0;
    lastX = lastY = -1;
    needRedraw = 1;
    firstDraw = 1;
    srand(time(0)); // 初始化随机数种子
}

// 绘制棋盘
void drawBoard() {
    if (!needRedraw) return;
    
    if (firstDraw) {
        system("cls"); 
        firstDraw = 0;
    }

    // 游戏信息(显示当前难度)
    setCursorPos(0, 0);
    printf("===================== 五子棋(人机对战) =====================");
    setCursorPos(0, 1);
    printf("操作说明:W/A/S/D 移动 | 空格落子 | U悔棋 | R重开 | Q退出");
    setCursorPos(0, 2);
    printf("难度:%s | 你:黑棋● | AI:白棋○                        ", 
           gameDiff == EASY ? "简单" : (gameDiff == MEDIUM ? "中等" : "困难"));
    setCursorPos(0, 3);
    printf("=============================================================");

    // 列坐标
    setCursorPos(0, 5);
    printf("    ");
    for (int j = 0; j < BOARD_SIZE; j++) {
        printf("%2d ", j);
    }

    // 棋盘主体
    for (int i = 0; i < BOARD_SIZE; i++) {
        setCursorPos(0, 6 + i);
        printf("%2d  ", i);
        
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (i == currentY && j == currentX) {
                printf("■ "); // 玩家光标
            } else {
                switch (board[i][j]) {
                    case EMPTY:  printf("+ "); break;
                    case BLACK:  printf("● "); break;
                    case WHITE:  printf("○ "); break;
                }
            }
        }
        printf("                          ");
    }

    needRedraw = 0;
}

// 检查是否获胜(通用函数)
int checkWin(int x, int y) {
    ChessType player = board[y][x];
    if (player == EMPTY) return 0;

    // 4个检查方向:横、纵、左对角、右对角
    int dx[] = {1, 0, 1, 1};
    int dy[] = {0, 1, 1, -1};

    for (int dir = 0; dir < 4; dir++) {
        int count = 1;
        
        // 正方向检查
        for (int step = 1; step < 5; step++) {
            int nx = x + dx[dir] * step;
            int ny = y + dy[dir] * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board[ny][nx] != player) {
                break;
            }
            count++;
        }

        // 反方向检查
        for (int step = 1; step < 5; step++) {
            int nx = x - dx[dir] * step;
            int ny = y - dy[dir] * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board[ny][nx] != player) {
                break;
            }
            count++;
        }

        if (count >= 5) {
            return 1;
        }
    }

    return 0;
}

// AI评分函数(不同难度不同权重)
int evaluatePos(int x, int y, ChessType player) {
    if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || board[y][x] != EMPTY) {
        return 0; // 非法位置评分0
    }

    // 临时落子
    board[y][x] = player;
    int score = 0;

    // 4个方向评分
    int dx[] = {1, 0, 1, 1};
    int dy[] = {0, 1, 1, -1};

    for (int dir = 0; dir < 4; dir++) {
        int emptyCount = 0; // 空位数
        int chessCount = 0; // 同色棋子数
        int blockCount = 0; // 阻挡数

        // 正方向
        for (int step = 1; step < 5; step++) {
            int nx = x + dx[dir] * step;
            int ny = y + dy[dir] * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                blockCount++;
                break;
            }
            if (board[ny][nx] == player) {
                chessCount++;
            } else if (board[ny][nx] == EMPTY) {
                emptyCount++;
                break;
            } else {
                blockCount++;
                break;
            }
        }

        // 反方向
        for (int step = 1; step < 5; step++) {
            int nx = x - dx[dir] * step;
            int ny = y - dy[dir] * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                blockCount++;
                break;
            }
            if (board[ny][nx] == player) {
                chessCount++;
            } else if (board[ny][nx] == EMPTY) {
                emptyCount++;
                break;
            } else {
                blockCount++;
                break;
            }
        }

        // 不同难度的评分权重
        if (gameDiff == EASY) {
            // 简单难度:降低评分权重,增加随机性
            if (chessCount >= 4) score += MAX_SCORE / 10;
            else if (chessCount == 3) score += 1000 / 10;
        } else if (gameDiff == MEDIUM) {
            // 中等难度:正常权重
            if (chessCount >= 4) score += MAX_SCORE;
            else if (chessCount == 3 && emptyCount >= 2) score += 10000;
            else if (chessCount == 2 && emptyCount >= 2) score += 1000;
        } else {
            // 困难难度:提高权重,优先攻防
            if (chessCount >= 4) score += MAX_SCORE * 2;
            else if (chessCount == 3 && emptyCount >= 2) score += 50000;
            else if (chessCount == 2 && emptyCount >= 2) score += 5000;
            // 额外加分:棋盘中心区域
            if (abs(x - BOARD_SIZE/2) <= 2 && abs(y - BOARD_SIZE/2) <= 2) {
                score += 500;
            }
        }

        // 封堵玩家的高分点位(困难难度加倍)
        if (player == BLACK) {
            score *= (gameDiff == HARD ? 3 : 1);
        }
    }

    // 撤销临时落子
    board[y][x] = EMPTY;
    return score;
}

// AI自动落子(按难度策略)
void aiPlaceChess() {
    int bestX = -1, bestY = -1;
    int maxScore = MIN_SCORE;

    // 简单难度:50%概率随机落子
    if (gameDiff == EASY && rand() % 2 == 0) {
        do {
            bestX = rand() % BOARD_SIZE;
            bestY = rand() % BOARD_SIZE;
        } while (board[bestY][bestX] != EMPTY);
    } else {
        // 中/困难难度:评分选点
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] != EMPTY) continue;

                // 计算AI落子(白棋)和封堵玩家(黑棋)的评分
                int aiScore = evaluatePos(j, i, WHITE);
                int blockScore = evaluatePos(j, i, BLACK);
                int totalScore = aiScore + blockScore;

                // 困难难度:优先封堵玩家
                if (gameDiff == HARD && blockScore > aiScore) {
                    totalScore = blockScore * 2;
                }

                if (totalScore > maxScore) {
                    maxScore = totalScore;
                    bestX = j;
                    bestY = i;
                }
            }
        }

        // 兜底随机落子
        if (bestX == -1 || bestY == -1) {
            do {
                bestX = rand() % BOARD_SIZE;
                bestY = rand() % BOARD_SIZE;
            } while (board[bestY][bestX] != EMPTY);
        }
    }

    // AI落子
    lastX = bestX;
    lastY = bestY;
    board[bestY][bestX] = WHITE;
    needRedraw = 1;

    // 检查AI是否获胜
    if (checkWin(bestX, bestY)) {
        drawBoard();
        setCursorPos(0, 25);
        printf("\nAI获胜!你输了??\n");
        printf("按任意键返回难度选择...");
        _getch();
        selectDifficulty(); // 获胜后返回难度选择
        initBoard();
    }
}

// 玩家落子操作
void playerPlaceChess() {
    // 检查位置合法性
    if (currentX < 0 || currentX >= BOARD_SIZE || currentY < 0 || currentY >= BOARD_SIZE) {
        return;
    }
    if (board[currentY][currentX] != EMPTY) {
        setCursorPos(0, 25);
        printf("该位置已有棋子!按任意键继续...                          ");
        _getch();
        setCursorPos(0, 25);
        printf("                                                          ");
        return;
    }

    // 玩家落子(黑棋)
    lastX = currentX;
    lastY = currentY;
    board[currentY][currentX] = BLACK;
    needRedraw = 1;

    // 检查玩家是否获胜
    if (checkWin(currentX, currentY)) {
        drawBoard();
        setCursorPos(0, 25);
        printf("\n恭喜你获胜!??\n");
        printf("按任意键返回难度选择...");
        _getch();
        selectDifficulty(); // 获胜后返回难度选择
        initBoard();
        return;
    }

    // 玩家落子后,AI自动落子
    aiPlaceChess();
}

// 悔棋操作
void regretChess() {
    if (lastX == -1 || lastY == -1) {
        setCursorPos(0, 25);
        printf("没有可悔的步数!按任意键继续...                          ");
        _getch();
        setCursorPos(0, 25);
        printf("                                                          ");
        return;
    }

    // 撤销玩家落子
    board[lastY][lastX] = EMPTY;
    needRedraw = 1;

    // 查找并撤销AI的上一步落子
    int aiLastX = -1, aiLastY = -1;
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (board[i][j] == WHITE) {
                aiLastX = j;
                aiLastY = i;
            }
        }
    }
    if (aiLastX != -1 && aiLastY != -1) {
        board[aiLastY][aiLastX] = EMPTY;
    }

    lastX = -1;
    lastY = -1;
    setCursorPos(0, 25);
    printf("悔棋成功!按任意键继续...                                ");
    _getch();
    setCursorPos(0, 25);
    printf("                                                          ");
    needRedraw = 1;
}

// 主游戏循环
void gameLoop() {
    initBoard();
    hideCursor();

    while (!gameOver) {
        drawBoard();

        // 玩家输入处理
        if (_kbhit()) {
            char key = _getch();
            switch (key) {
                case 'w': case 'W': // 上
                    if (currentY > 0) {
                        currentY--;
                        needRedraw = 1;
                    }
                    break;
                case 's': case 'S': // 下
                    if (currentY < BOARD_SIZE - 1) {
                        currentY++;
                        needRedraw = 1;
                    }
                    break;
                case 'a': case 'A': // 左
                    if (currentX > 0) {
                        currentX--;
                        needRedraw = 1;
                    }
                    break;
                case 'd': case 'D': // 右
                    if (currentX < BOARD_SIZE - 1) {
                        currentX++;
                        needRedraw = 1;
                    }
                    break;
                case ' ': // 落子
                    playerPlaceChess();
                    break;
                case 'u': case 'U': // 悔棋
                    regretChess();
                    break;
                case 'r': case 'R': // 重开(保留当前难度)
                    initBoard();
                    break;
                case 'q': case 'Q': // 退出
                    gameOver = 1;
                    setCursorPos(0, 25);
                    printf("游戏已退出!");
                    break;
            }
        }

        Sleep(80);
    }
}

// 主函数
int main() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hConsole != INVALID_HANDLE_VALUE) {
        SetConsoleOutputCP(CP_GBK);
    }
    
    // 先选择难度,再进入游戏
    selectDifficulty();
    gameLoop();
    return 0;
}