#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <conio.h>
#include <utility>
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#define CLEAR_SCREEN "cls"
#define SLEEP_MS(x) Sleep(x)
#else
#define CLEAR_SCREEN "clear"
#define SLEEP_MS(x) usleep(x * 1000)
#endif
using namespace std;

enum Direction { UP, DOWN, LEFT, RIGHT };

struct Bullet {
    int x, y;
    Direction dir;
    bool alive;
    Bullet(int x_, int y_, Direction dir_) : x(x_), y(y_), dir(dir_), alive(true) {}
};

class Tank {
public:
    int x, y;
    Direction dir;
    bool alive;
    char symbol;
    Tank(int x_, int y_, char sym) : x(x_), y(y_), dir(UP), alive(true), symbol(sym) {}
    bool move(Direction newDir, int mapWidth, int mapHeight, const vector<pair<int, int> >& obstacles);
};

const int MAP_WIDTH = 60;
const int MAP_HEIGHT = 26;
const int AUTO_REFRESH_MS = 600;
const int DIR[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
const int ENEMY_COUNT = 5;
const int ENEMY_DETECT_RANGE = 8;

Tank player(1, 1, 'P');
vector<Tank> enemies;
vector<Bullet> bullets;
vector<pair<int, int> > obstacles;
bool gameOver = false;
string winner = "";
bool visited[MAP_HEIGHT][MAP_WIDTH];

bool isObstacle(int x, int y) {
    if (x <= 0 || x >= MAP_HEIGHT-1 || y <= 0 || y >= MAP_WIDTH-1)
        return true;
    for (vector<pair<int, int> >::const_iterator it = obstacles.begin(); it != obstacles.end(); ++it) {
        if (it->first == x && it->second == y) {
            return true;
        }
    }
    return false;
}

bool hasTankAt(int x, int y) {
    if (player.alive && player.x == x && player.y == y)
        return true;
    for (size_t i = 0; i < enemies.size(); ++i) {
        if (enemies[i].alive && enemies[i].x == x && enemies[i].y == y)
            return true;
    }
    return false;
}

bool Tank::move(Direction newDir, int mapWidth, int mapHeight, const vector<pair<int, int> >& obstacles) {
    dir = newDir;
    int newX = x, newY = y;
    switch (newDir) {
        case UP:    newX--; break;
        case DOWN:  newX++; break;
        case LEFT:  newY--; break;
        case RIGHT: newY++; break;
    }
    if (newX >= 1 && newX <= mapHeight-2
     && newY >= 1 && newY <= mapWidth-2
     && !isObstacle(newX, newY)
     && !hasTankAt(newX, newY)) {
        x = newX;
        y = newY;
        return true;
    }
    return false;
}

void dfs(int x, int y, int endX, int endY, bool& reachable) {
    if (x == endX && y == endY) {
        reachable = true;
        return;
    }
    if (x < 1 || x >= MAP_HEIGHT-1 || y < 1 || y >= MAP_WIDTH-1 || visited[x][y] || isObstacle(x, y)) {
        return;
    }
    visited[x][y] = true;
    for (int i = 0; i < 4 && !reachable; i++) {
        dfs(x + DIR[i][0], y + DIR[i][1], endX, endY, reachable);
    }
}

bool isMapConnected(int playerX, int playerY, const vector<Tank>& enemies) {
    for (size_t i = 0; i < enemies.size(); ++i) {
        if (!enemies[i].alive) continue;
        memset(visited, false, sizeof(visited));
        bool reachable = false;
        dfs(playerX, playerY, enemies[i].x, enemies[i].y, reachable);
        if (!reachable) return false;
    }
    return true;
}

pair<int, int> generateSuperSafePos() {
    int x, y;
    bool safe = false;
    while (!safe) {
        x = rand() % (MAP_HEIGHT - 2) + 1;
        y = rand() % (MAP_WIDTH - 2) + 1;
        if (isObstacle(x, y)) continue;
        int freeDir = 0;
        for (int i = 0; i < 4; i++) {
            int nx = x + DIR[i][0];
            int ny = y + DIR[i][1];
            if (nx >= 1 && nx <= MAP_HEIGHT-2 && ny >= 1 && ny <= MAP_WIDTH-2 && !isObstacle(nx, ny)) {
                freeDir++;
            }
        }
        if (freeDir >= 3) safe = true;
    }
    return make_pair(x, y);
}

void generateOpenMap() {
    obstacles.clear();
    bool connected = false;
    while (!connected) {
        obstacles.clear();
        const int WALL_SEGMENTS = 25;
        const int MIN_WALL_LEN = 2;
        const int MAX_WALL_LEN = 4;
        for (int i = 0; i < WALL_SEGMENTS; i++) {
            Direction dir = (Direction)(rand() % 2);
            int len = MIN_WALL_LEN + rand() % (MAX_WALL_LEN - MIN_WALL_LEN + 1);
            int x, y;
            do {
                x = rand() % (MAP_HEIGHT - 2) + 1;
                y = rand() % (MAP_WIDTH - 2) + 1;
            } while (isObstacle(x, y));
            for (int j = 0; j < len; j++) {
                int nx = x, ny = y;
                if (dir == 0) ny += j;
                else nx += j;
                if (nx < 1 || nx >= MAP_HEIGHT-1 || ny < 1 || ny >= MAP_WIDTH-1 || isObstacle(nx, ny)) break;
                obstacles.push_back(make_pair(nx, ny));
            }
        }
        pair<int, int> playerPos = generateSuperSafePos();
        player.x = playerPos.first;
        player.y = playerPos.second;
        player.alive = true;
        enemies.clear();
        for (int i = 0; i < ENEMY_COUNT; ++i) {
            pair<int, int> enemyPos = generateSuperSafePos();
            enemies.push_back(Tank(enemyPos.first, enemyPos.second, 'E'));
        }
        connected = isMapConnected(player.x, player.y, enemies);
    }
}

bool hasLineOfSight(int enemyX, int enemyY, int playerX, int playerY) {
    int dx = abs(playerX - enemyX);
    int dy = abs(playerY - enemyY);
    if (dx > 0 && dy > 0) return false;
    if (dx == 0) {
        int startY = min(enemyY, playerY) + 1;
        int endY = max(enemyY, playerY);
        for (int y = startY; y < endY; y++) {
            if (isObstacle(enemyX, y)) return false;
        }
    } else if (dy == 0) {
        int startX = min(enemyX, playerX) + 1;
        int endX = max(enemyX, playerX);
        for (int x = startX; x < endX; x++) {
            if (isObstacle(x, enemyY)) return false;
        }
    }
    return true;
}

bool canAttackPlayer(int enemyX, int enemyY) {
    if (!player.alive) return false;
    int dx = abs(player.x - enemyX);
    int dy = abs(player.y - enemyY);
    int distance = dx + dy;
    if (distance > ENEMY_DETECT_RANGE) return false;
    return hasLineOfSight(enemyX, enemyY, player.x, player.y);
}

void clearScreen() {
    system(CLEAR_SCREEN);
}

void setColor(int color) {
#ifdef _WIN32
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, BACKGROUND_GREEN | color);
#else
    (void)color;
#endif
}

void drawMap() {
    clearScreen();
    for (int i = 0; i < MAP_HEIGHT; i++) {
        for (int j = 0; j < MAP_WIDTH; j++) {
            if (i == 0 || i == MAP_HEIGHT-1 || j == 0 || j == MAP_WIDTH-1) {
                setColor(6); cout << "■";
            } else if (isObstacle(i, j)) {
                setColor(6); cout << "■";
            } else if (player.alive && i == player.x && j == player.y) {
                setColor(1); cout << player.symbol << " ";
            } else {
                bool isEnemy = false;
                for (size_t k = 0; k < enemies.size(); ++k) {
                    if (enemies[k].alive && i == enemies[k].x && j == enemies[k].y) {
                        setColor(4); cout << enemies[k].symbol << " ";
                        isEnemy = true; break;
                    }
                }
                if (isEnemy) continue;
                bool isBullet = false;
                for (vector<Bullet>::iterator it = bullets.begin(); it != bullets.end(); ++it) {
                    if (it->alive && it->x == i && it->y == j) {
                        setColor(14); cout << "* ";
                        isBullet = true; break;
                    }
                }
                if (!isBullet) {
                    setColor(7); cout << "  ";
                }
            }
        }
        cout << endl;
    }
    setColor(7);
    cout << "===== 坦克对战 v1.0 =====" << endl;
    cout << "操作:W(上) A(左) S(下) D(右) 空格(发射) Q(退出) R(重开)" << endl;
    cout << "玩家:P  敌人:E  子弹:*  障碍物:■" << endl;
    if (gameOver) {
        cout << "★ 游戏结束!" << winner << " ★ 3秒后自动重开..." << endl;
    }
}

void checkCollision() {
    for (vector<Bullet>::iterator it = bullets.begin(); it != bullets.end(); ) {
        if (!it->alive) { it = bullets.erase(it); continue; }
        if (player.alive && it->x == player.x && it->y == player.y) {
            player.alive = false;
            gameOver = true;
            winner = "玩家被击败,电脑获胜";
            it->alive = false;
        }
        bool hitEnemy = false;
        for (size_t k = 0; k < enemies.size(); ++k) {
            if (enemies[k].alive && it->x == enemies[k].x && it->y == enemies[k].y) {
                enemies[k].alive = false;
                it->alive = false;
                hitEnemy = true; break;
            }
        }
        if (hitEnemy) {
            bool allDead = true;
            for (size_t k = 0; k < enemies.size(); ++k) {
                if (enemies[k].alive) { allDead = false; break; }
            }
            if (allDead) {
                gameOver = true;
                winner = "所有敌人被消灭,玩家获胜";
            }
            it = bullets.erase(it);
            continue;
        }
        if (isObstacle(it->x, it->y)) {
            it->alive = false;
            it = bullets.erase(it);
        } else {
            ++it;
        }
    }
}

void moveBullets() {
    for (vector<Bullet>::iterator it = bullets.begin(); it != bullets.end(); ++it) {
        if (!it->alive) continue;
        switch (it->dir) {
            case UP: it->x--; break;
            case DOWN: it->x++; break;
            case LEFT: it->y--; break;
            case RIGHT: it->y++; break;
        }
    }
}

// ==============================================
// 这里已经把 所有概率 提高到 75% 左右!
// ==============================================
void enemyAI() {
    if (gameOver || !player.alive) return;
    for (size_t k = 0; k < enemies.size(); ++k) {
        Tank& enemy = enemies[k];
        if (!enemy.alive) continue;
        bool playerInRange = canAttackPlayer(enemy.x, enemy.y);

        if (playerInRange) {
            if (player.x < enemy.x) enemy.dir = UP;
            else if (player.x > enemy.x) enemy.dir = DOWN;
            else if (player.y < enemy.y) enemy.dir = LEFT;
            else if (player.y > enemy.y) enemy.dir = RIGHT;

            // 75% 移动概率
            if (rand() % 4 != 0) {
                enemy.move(enemy.dir, MAP_WIDTH, MAP_HEIGHT, obstacles);
            }
            // 62.5% 开火概率
            if (rand() % 8 != 0) {
                int bx = enemy.x, by = enemy.y;
                switch (enemy.dir) {
                    case UP: bx--; break; case DOWN: bx++; break;
                    case LEFT: by--; break; case RIGHT: by++; break;
                }
                bullets.push_back(Bullet(bx, by, enemy.dir));
            }
        } else {
            // 70% 随机移动
            if (rand() % 10 != 0) {
                Direction nd = (Direction)(rand() % 4);
                enemy.move(nd, MAP_WIDTH, MAP_HEIGHT, obstacles);
            }
            // 52% 随机开火
            if (rand() % 100 < 52) {
                int bx = enemy.x, by = enemy.y;
                switch (enemy.dir) {
                    case UP: bx--; break; case DOWN: bx++; break;
                    case LEFT: by--; break; case RIGHT: by++; break;
                }
                bullets.push_back(Bullet(bx, by, enemy.dir));
            }
        }
    }
}

bool handleInput() {
    if (!player.alive || gameOver) return false;
    if (!kbhit()) return false;
    char key = getch();
    switch (key) {
        case 'w': case 'W': player.move(UP, MAP_WIDTH, MAP_HEIGHT, obstacles); break;
        case 's': case 'S': player.move(DOWN, MAP_WIDTH, MAP_HEIGHT, obstacles); break;
        case 'a': case 'A': player.move(LEFT, MAP_WIDTH, MAP_HEIGHT, obstacles); break;
        case 'd': case 'D': player.move(RIGHT, MAP_WIDTH, MAP_HEIGHT, obstacles); break;
        case ' ': {
            int bx = player.x, by = player.y;
            switch (player.dir) {
                case UP: bx--; break; case DOWN: bx++; break;
                case LEFT: by--; break; case RIGHT: by++; break;
            }
            bullets.push_back(Bullet(bx, by, player.dir));
            break;
        }
        case 'r': case 'R':
            gameOver = true; winner = "手动重新开始"; break;
        case 'q': case 'Q':
            cout << "\n退出游戏!" << endl; exit(0);
        default: return false;
    }
    return true;
}

void resetGame() {
    player.alive = true;
    bullets.clear();
    gameOver = false;
    winner = "";
    generateOpenMap();
}

int main() {
    cin.tie(NULL);
    cout.tie(NULL);
    srand((unsigned)time(NULL));
    generateOpenMap();
    drawMap();

    DWORD last = GetTickCount();
    while (true) {
        if (gameOver) {
            drawMap(); SLEEP_MS(3000); resetGame(); last = GetTickCount(); drawMap(); continue;
        }

        bool key = handleInput();
        if (key) {
            enemyAI(); moveBullets(); checkCollision();
            drawMap(); last = GetTickCount();
            continue;
        }

        DWORD now = GetTickCount();
        if (now - last >= AUTO_REFRESH_MS) {
            enemyAI(); moveBullets(); checkCollision();
            drawMap(); last = now;
        }
        Sleep(10);
    }
    return 0;
}