#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <conio.h>
#include <utility>
#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 = 50;
const int MAP_HEIGHT = 25;
const int REFRESH_RATE = 100;
Tank player(20, 2, 'P');
Tank enemy(5, 45, 'E');
vector<Bullet> bullets;
vector<pair<int, int> > obstacles;
bool gameOver = false;
string winner = "";
bool isObstacle(int x, int y) {
    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 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)) {
        x = newX;
        y = newY;
        return true;
    }
    return false;
}


void initObstacles() {
    obstacles.clear();
    for (int i = 3; i <= 22; i += 2) {
        obstacles.push_back(make_pair(i, 5));
    }
    for (int j = 7; j <= 15; j += 2) {
        obstacles.push_back(make_pair(8, j));
    }
    for (int i = 10; i <= 22; i += 2) {
        obstacles.push_back(make_pair(i, 20));
    }
    for (int j = 22; j <= 30; j += 2) {
        obstacles.push_back(make_pair(15, j));
    }
    for (int i = 3; i <= 13; i += 2) {
        obstacles.push_back(make_pair(i, 35));
    }
    for (int j = 37; j <= 45; j += 2) {
        obstacles.push_back(make_pair(10, j));
    }
    obstacles.push_back(make_pair(5, 10));
    obstacles.push_back(make_pair(12, 25));
    obstacles.push_back(make_pair(18, 30));
    obstacles.push_back(make_pair(7, 40));
    obstacles.push_back(make_pair(20, 15));
}
void clearScreen() {
    system(CLEAR_SCREEN);
}
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) {
                cout << "#";
            }
            else if (isObstacle(i, j)) {
                cout << "X";
            }
            else if (i == player.x && j == player.y && player.alive) {
                cout << player.symbol;
            }
            else if (i == enemy.x && j == enemy.y && enemy.alive) {
                cout << enemy.symbol;
            }
            else {
                bool isBullet = false;
                for (vector<Bullet>::iterator it = bullets.begin(); it != bullets.end(); ++it) {
                    if (it->alive && it->x == i && it->y == j) {
                        cout << "*";
                        isBullet = true;
                        break;
                    }
                }
                if (!isBullet) {
                    cout << " "; 
                }
            }
        }
        cout << endl;
    }
    cout << "===== 坦克对战游戏(Dev-C++ 5.11)=====" << endl;
    cout << "界面尺寸:宽" << MAP_WIDTH << " × 高" << MAP_HEIGHT << endl;
    cout << "操作:W(上) A(左) S(下) D(右) 空格(发射) Q(退出)" << endl;
    cout << "玩家:P  电脑:E  子弹:*  边界:#  障碍物:X" << endl;
    if (gameOver) {
        cout << "游戏结束!" << winner << "获胜!" << endl;
    }
}
void checkCollision() {
    for (vector<Bullet>::iterator it = bullets.begin(); it != bullets.end(); ) {
        if (!it->alive) {
            it = bullets.erase(it);
            continue;
        }
        if (it->x == player.x && it->y == player.y && player.alive) {
            player.alive = false;
            gameOver = true;
            winner = "电脑";
            it->alive = false;
        }
        else if (it->x == enemy.x && it->y == enemy.y && enemy.alive) {
            enemy.alive = false;
            gameOver = true;
            winner = "玩家";
            it->alive = false;
        }
        else if (isObstacle(it->x, it->y)) {
            it->alive = false;
        }
        else if (it->x <= 0 || it->x >= MAP_HEIGHT-1 || it->y <= 0 || it->y >= MAP_WIDTH-1) {
            it->alive = false;
        }
        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;
        }
    }
}
void enemyAI() {
    if (!enemy.alive || gameOver) return;
    int moveRand = rand() % 3;
    if (moveRand == 0) {
        Direction newDir = (Direction)(rand() % 4);
        enemy.move(newDir, MAP_WIDTH, MAP_HEIGHT, obstacles);
    }
    int fireRand = rand() % 15;
    if (fireRand == 0) {
        bullets.push_back(Bullet(enemy.x, enemy.y, enemy.dir));
    }
}
char getInput() {
#ifdef _WIN32
    if (kbhit()) {
        return getch();
    }
#else
    fd_set rfds;
    struct timeval tv;
    FD_ZERO(&rfds);
    FD_SET(STDIN_FILENO, &rfds);
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    if (select(STDIN_FILENO+1, &rfds, NULL, NULL, &tv) > 0) {
        return getchar();
    }
#endif
    return 0;
}
void handleInput() {
    if (!player.alive || gameOver) return;

    char key = getInput();
    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 ' ': bullets.push_back(Bullet(player.x, player.y, player.dir)); break;
        case 'q': case 'Q': gameOver = true; winner = "退出"; break;
    }
}

int main() {
    srand(static_cast<unsigned int>(time(NULL)));
    initObstacles();
    while (!gameOver) {
        handleInput();
        enemyAI();
        moveBullets();
        checkCollision();
        drawMap();
        SLEEP_MS(REFRESH_RATE);
    }
    drawMap();
    cout << "\n按任意键退出..." << endl;
    getch();
    return 0;
}