#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <windows.h>

#define SIZE 15
#define HISTORY_SIZE 500

typedef enum {
    MODE_HUMAN_VS_HUMAN,
    MODE_HUMAN_VS_AI,
    MODE_EXIT
} GameMode;

typedef enum {
    EASY,
    MEDIUM,
    HARD
} Difficulty;

typedef struct {
    char board[SIZE][SIZE];
    GameMode mode;
    Difficulty difficulty;
    char currentPlayer;
    int lastMove[2];
    int history[HISTORY_SIZE][2];
    int stepCount;
} GameState;

void clearScreen() {
    system("cls");
}

void initGame(GameState* game, GameMode mode) {
    memset(game->board, '+', sizeof(game->board));
    game->mode = mode;
    game->currentPlayer = 'X';
    game->stepCount = 0;
    game->difficulty = MEDIUM;
    memset(game->history, -1, sizeof(game->history));
}

void printBoard(const GameState* game) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    printf("   ");
    for (int i = 0; i < SIZE; i++) {
        printf("%2d", i + 1);
    }
    printf("\n");

    for (int i = 0; i < SIZE; i++) {
        printf("%2d ", i + 1);
        for (int j = 0; j < SIZE; j++) {
            if (game->board[i][j] == 'X') {
                SetConsoleTextAttribute(hConsole, 12);
            }
            else if (game->board[i][j] == 'O') {
                SetConsoleTextAttribute(hConsole, 9);
            }
            printf("%2c", game->board[i][j]);
            SetConsoleTextAttribute(hConsole, 7);
        }
        printf("\n");
    }
}

bool isValidMove(const GameState* game, int x, int y) {
    return x >= 0 && x < SIZE && y >= 0 && y < SIZE && game->board[x][y] == '+';
}

bool checkWin(const GameState* game, int x, int y) {
    const int dirs[4][2] = { {0, 1}, {1, 0}, {1, 1}, {1, -1} };
    char player = game->board[x][y];

    for (int d = 0; d < 4; d++) {
        int count = 1;

        for (int step = 1; step < 5; step++) {
            int nx = x + dirs[d][0] * step;
            int ny = y + dirs[d][1] * step;
            if (nx < 0 || nx >= SIZE || ny < 0 || ny >= SIZE || game->board[nx][ny] != player) break;
            count++;
        }

        for (int step = 1; step < 5; step++) {
            int nx = x - dirs[d][0] * step;
            int ny = y - dirs[d][1] * step;
            if (nx < 0 || nx >= SIZE || ny < 0 || ny >= SIZE || game->board[nx][ny] != player) break;
            count++;
        }

        if (count >= 5) return true;
    }
    return false;
}

void showWinMessage(char winner) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    clearScreen();

    SetConsoleTextAttribute(hConsole, 14); // 黄色
    printf("================================\n");
    printf("   PLAYER %c WINS THE GAME!\n", winner);
    printf("================================\n\n");
    SetConsoleTextAttribute(hConsole, 7); // 恢复白色

    printf("Press Enter to return to main menu...");
    while (getchar() != '\n'); // 清空输入缓冲区
    getchar(); // 等待回车
}

void showDrawMessage() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    clearScreen();

    SetConsoleTextAttribute(hConsole, 11); // 浅蓝色
    printf("================================\n");
    printf("        DRAW GAME!\n");
    printf("================================\n\n");
    SetConsoleTextAttribute(hConsole, 7); // 恢复白色

    printf("Press Enter to return to main menu...");
    while (getchar() != '\n');
    getchar();
}

void aiMove(GameState* game) {
    int x, y;

    if (game->difficulty == EASY) {
        do {
            x = rand() % SIZE;
            y = rand() % SIZE;
        } while (!isValidMove(game, x, y));
    }
    else if (game->difficulty == MEDIUM) {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (isValidMove(game, i, j)) {
                    game->board[i][j] = 'O';
                    if (checkWin(game, i, j)) {
                        game->lastMove[0] = i;
                        game->lastMove[1] = j;
                        game->history[game->stepCount][0] = i;
                        game->history[game->stepCount][1] = j;
                        game->stepCount++;
                        return;
                    }
                    game->board[i][j] = '+';
                }
            }
        }

        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (isValidMove(game, i, j)) {
                    game->board[i][j] = 'X';
                    if (checkWin(game, i, j)) {
                        game->board[i][j] = 'O';
                        game->lastMove[0] = i;
                        game->lastMove[1] = j;
                        game->history[game->stepCount][0] = i;
                        game->history[game->stepCount][1] = j;
                        game->stepCount++;
                        return;
                    }
                    game->board[i][j] = '+';
                }
            }
        }

        do {
            x = rand() % SIZE;
            y = rand() % SIZE;
        } while (!isValidMove(game, x, y));
    }
    else {
        do {
            x = rand() % SIZE;
            y = rand() % SIZE;
        } while (!isValidMove(game, x, y));
    }

    game->board[x][y] = 'O';
    game->lastMove[0] = x;
    game->lastMove[1] = y;
    game->history[game->stepCount][0] = x;
    game->history[game->stepCount][1] = y;
    game->stepCount++;
}

void showMainMenu() {
    clearScreen();
    printf("=== GOMOKU GAME ===\n");
    printf("1. Player vs Player\n");
    printf("2. Player vs AI\n");
    printf("3. Set Difficulty\n");
    printf("4. Exit Game\n");
    printf("Select: ");
}

void setDifficulty(GameState* game) {
    clearScreen();
    printf("=== SET DIFFICULTY ===\n");
    printf("1. Easy\n");
    printf("2. Medium\n");
    printf("3. Hard\n");
    printf("Select: ");

    int choice;
    scanf("%d", &choice);

    switch (choice) {
    case 1: game->difficulty = EASY; break;
    case 2: game->difficulty = MEDIUM; break;
    case 3: game->difficulty = HARD; break;
    default: printf("Invalid choice, keeping current difficulty\n");
    }
}

GameMode gameLoop(GameState* game) {
    while (1) {
        clearScreen();
        printBoard(game);

        if (game->mode == MODE_HUMAN_VS_AI && game->currentPlayer == 'O') {
            printf("AI is thinking...\n");
            Sleep(800);
            aiMove(game);
            printf("AI moved to: %d %d\n", game->lastMove[0] + 1, game->lastMove[1] + 1);
        }
        else {
            printf("Player %c's turn (enter row and column, or 4 to exit): ", game->currentPlayer);

            int row, col;
            if (scanf("%d", &row) != 1) {
                printf("Invalid input format!\n");
                while (getchar() != '\n');
                continue;
            }

            if (row == 4) {
                return MODE_EXIT;
            }

            if (scanf("%d", &col) != 1) {
                printf("Invalid input format!\n");
                while (getchar() != '\n');
                continue;
            }

            row--; col--;
            if (!isValidMove(game, row, col)) {
                printf("Invalid move, try again\n");
                continue;
            }

            game->board[row][col] = game->currentPlayer;
            game->lastMove[0] = row;
            game->lastMove[1] = col;
            game->history[game->stepCount][0] = row;
            game->history[game->stepCount][1] = col;
            game->stepCount++;
        }

        if (checkWin(game, game->lastMove[0], game->lastMove[1])) {
            showWinMessage(game->currentPlayer);
            return game->mode;
        }

        if (game->stepCount == SIZE * SIZE) {
            showDrawMessage();
            return game->mode;
        }

        game->currentPlayer = (game->currentPlayer == 'X') ? 'O' : 'X';
    }
}

int main() {
    srand((unsigned int)time(NULL));
    GameState game;
    int choice;
    GameMode result;

    while (1) {
        showMainMenu();

        if (scanf("%d", &choice) != 1) {
            while (getchar() != '\n');
            continue;
        }

        switch (choice) {
        case 1:
            initGame(&game, MODE_HUMAN_VS_HUMAN);
            result = gameLoop(&game);
            if (result == MODE_EXIT) continue;
            break;
        case 2:
            initGame(&game, MODE_HUMAN_VS_AI);
            result = gameLoop(&game);
            if (result == MODE_EXIT) continue;
            break;
        case 3:
            setDifficulty(&game);
            break;
        case 4:
            return 0;
        default:
            printf("Invalid selection!\n");
        }
    }
}