#include <iostream>
#include <conio.h>
#include <windows.h>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <string>
#include <fstream>

using namespace std;

const int SCREEN_WIDTH = 60;
const int SCREEN_HEIGHT = 20;
const int GROUND_Y = 15;
const int PLAYER_START_X = 8;
const int FPS = 60;
const int BASE_SPEED = 80;

const char CHAR_PLAYER = '&';
const char CHAR_PLAYER_JUMP = '^';
const char CHAR_PLAYER_SLIDE = '~';
const char CHAR_GROUND = '_';
const char CHAR_COIN = '$';
const char CHAR_SPIKE = '^';
const char CHAR_BLOCK = '#';
const char CHAR_BIRD = 'V';
const char CHAR_STAR = '*';
const char CHAR_SHIELD = 'O';
const char CHAR_MAGNET = 'M';

const int COLOR_DEFAULT = 7;
const int COLOR_PLAYER = 11;
const int COLOR_GROUND = 10;
const int COLOR_COIN = 14;
const int COLOR_OBSTACLE = 12;
const int COLOR_SHIELD = 9;
const int COLOR_MAGNET = 13;
const int COLOR_STAR = 14;
const int COLOR_UI = 15;

enum PlayerState {
    STATE_RUNNING,
    STATE_JUMPING,
    STATE_DOUBLE_JUMP,
    STATE_SLIDING,
    STATE_DEAD
};

enum ObstacleType {
    OBSTACLE_SPIKE,
    OBSTACLE_BLOCK,
    OBSTACLE_TALL_BLOCK,
    OBSTACLE_BIRD,
    OBSTACLE_COUNT
};

struct Position {
    int x;
    int y;
    Position() : x(0), y(0) {}
    Position(int px, int py) : x(px), y(py) {}
};

struct Obstacle {
    Position pos;
    ObstacleType type;
    int width;
    int height;
    bool passed;
};

struct Collectible {
    Position pos;
    int type;
    int value;
    bool active;
};

struct Particle {
    Position pos;
    char symbol;
    int color;
    int life;
    int maxLife;
    float vy;
};

class ParkourGame {
private:
    HANDLE hConsole;
    COORD bufferSize;
    SMALL_RECT windowRect;
    
    Position playerPos;
    float playerVelocityY;
    PlayerState playerState;
    int playerJumps;
    int playerSlideTimer;
    
    bool gameRunning;
    bool gamePaused;
    int score;
    int coins;
    int distance;
    int highScore;
    int gameSpeed;
    int frameCount;
    int difficulty;
    
    bool hasShield;
    int shieldTimer;
    bool hasMagnet;
    int magnetTimer;
    int invincibleTimer;
    
    vector<Obstacle> obstacles;
    vector<Collectible> collectibles;
    vector<Particle> particles;
    
    int bgOffset;
    vector<Position> bgStars;
    
public:
    ParkourGame() {
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        setupConsole();
        loadHighScore();
        initGame();
    }
    
    ~ParkourGame() {
        saveHighScore();
        resetConsole();
    }
    
    void setupConsole() {
        SetConsoleTitle("Parkour Runner");
        
        bufferSize.X = SCREEN_WIDTH + 2;
        bufferSize.Y = SCREEN_HEIGHT + 10;
        SetConsoleScreenBufferSize(hConsole, bufferSize);
        
        windowRect.Left = 0;
        windowRect.Top = 0;
        windowRect.Right = SCREEN_WIDTH + 1;
        windowRect.Bottom = SCREEN_HEIGHT + 5;
        SetConsoleWindowInfo(hConsole, TRUE, &windowRect);
        
        CONSOLE_CURSOR_INFO cursorInfo;
        GetConsoleCursorInfo(hConsole, &cursorInfo);
        cursorInfo.bVisible = FALSE;
        SetConsoleCursorInfo(hConsole, &cursorInfo);
        
        DWORD consoleMode;
        GetConsoleMode(hConsole, &consoleMode);
        consoleMode &= ~ENABLE_QUICK_EDIT_MODE;
        SetConsoleMode(hConsole, consoleMode);
    }
    
    void resetConsole() {
        CONSOLE_CURSOR_INFO cursorInfo;
        GetConsoleCursorInfo(hConsole, &cursorInfo);
        cursorInfo.bVisible = TRUE;
        SetConsoleCursorInfo(hConsole, &cursorInfo);
        setColor(COLOR_DEFAULT);
        system("cls");
    }
    
    void initGame() {
        playerPos = Position(PLAYER_START_X, GROUND_Y - 1);
        playerVelocityY = 0;
        playerState = STATE_RUNNING;
        playerJumps = 0;
        playerSlideTimer = 0;
        
        gameRunning = true;
        gamePaused = false;
        score = 0;
        coins = 0;
        distance = 0;
        gameSpeed = BASE_SPEED;
        frameCount = 0;
        difficulty = 1;
        
        hasShield = false;
        shieldTimer = 0;
        hasMagnet = false;
        magnetTimer = 0;
        invincibleTimer = 0;
        
        obstacles.clear();
        collectibles.clear();
        particles.clear();
        bgOffset = 0;
        
        initBackground();
    }
    
    void initBackground() {
        bgStars.clear();
        for (int i = 0; i < 20; i++) {
            Position star;
            star.x = rand() % SCREEN_WIDTH;
            star.y = rand() % (GROUND_Y - 2);
            bgStars.push_back(star);
        }
    }
    
    void loadHighScore() {
        ifstream file("parkour_highscore.dat");
        if (file.is_open()) {
            file >> highScore;
            file.close();
        } else {
            highScore = 0;
        }
    }
    
    void saveHighScore() {
        if (score > highScore) {
            ofstream file("parkour_highscore.dat");
            if (file.is_open()) {
                file << score;
                file.close();
            }
        }
    }
    
    void gotoxy(int x, int y) {
        COORD coord;
        coord.X = x;
        coord.Y = y;
        SetConsoleCursorPosition(hConsole, coord);
    }
    
    void setColor(int color) {
        SetConsoleTextAttribute(hConsole, color);
    }
    
    bool isKeyPressed(int keyCode) {
        return (GetAsyncKeyState(keyCode) & 0x8000) != 0;
    }
    
    void run() {
        showStartScreen();
        
        while (gameRunning) {
            handleInput();
            
            if (!gamePaused) {
                update();
                checkCollisions();
                spawnObjects();
                render();
            }
            
            Sleep(gameSpeed / FPS);
        }
        
        showGameOverScreen();
    }
    
    void handleInput() {
        if (_kbhit()) {
            char key = _getch();
            
            switch (key) {
                case ' ':
                case 'w':
                case 'W':
                    jump();
                    break;
                    
                case 's':
                case 'S':
                    slide();
                    break;
                    
                case 'p':
                case 'P':
                    gamePaused = !gamePaused;
                    if (gamePaused) showPauseScreen();
                    break;
                    
                case 27:
                    gameRunning = false;
                    break;
            }
        }
        
        if (isKeyPressed(VK_SPACE) && playerState == STATE_RUNNING) {
            jump();
        }
        if (isKeyPressed('S') && playerState == STATE_RUNNING) {
            slide();
        }
    }
    
    void jump() {
        if (playerState == STATE_RUNNING) {
            playerVelocityY = -1.8f;
            playerState = STATE_JUMPING;
            playerJumps = 1;
            createJumpParticles();
        } else if (playerState == STATE_JUMPING && playerJumps == 1) {
            playerVelocityY = -2.5f;
            playerState = STATE_DOUBLE_JUMP;
            playerJumps = 2;
            createJumpParticles();
        }
    }
    
    void slide() {
        if (playerState == STATE_RUNNING) {
            playerState = STATE_SLIDING;
            playerSlideTimer = 15;
        }
    }
    
    void createJumpParticles() {
        for (int i = 0; i < 5; i++) {
            Particle p;
            p.pos = Position(playerPos.x, playerPos.y + 1);
            p.symbol = '*';
            p.color = COLOR_STAR;
            p.life = 10;
            p.maxLife = 10;
            p.vy = -(rand() % 20) / 10.0f - 1;
            particles.push_back(p);
        }
    }
    
    void update() {
        frameCount++;
        distance++;
        
        if (distance % 500 == 0 && gameSpeed > 30) {
            difficulty++;
            gameSpeed = max(30, BASE_SPEED - difficulty * 5);
        }
        
        if (frameCount % 10 == 0) {
            score += difficulty;
            if (score > highScore) highScore = score;
        }
        
        updatePlayer();
        updateObstacles();
        updateCollectibles();
        updateParticles();
        updatePowerups();
        
        if (frameCount % 3 == 0) {
            bgOffset = (bgOffset + 1) % SCREEN_WIDTH;
        }
    }
    
    void updatePlayer() {
        if (playerState == STATE_JUMPING || playerState == STATE_DOUBLE_JUMP) {
            playerVelocityY += 0.15f;
            playerPos.y += (int)playerVelocityY;
            
            if (playerPos.y >= GROUND_Y - 1) {
                playerPos.y = GROUND_Y - 1;
                playerState = STATE_RUNNING;
                playerVelocityY = 0;
                playerJumps = 0;
                createLandParticles();
            }
        }
        
        if (playerState == STATE_SLIDING) {
            playerSlideTimer--;
            if (playerSlideTimer <= 0) {
                playerState = STATE_RUNNING;
            }
        }
        
        if (playerPos.y > GROUND_Y - 1) {
            playerPos.y = GROUND_Y - 1;
        }
        if (playerPos.y < 0) {
            playerPos.y = 0;
            playerVelocityY = 0;
        }
    }
    
    void updateObstacles() {
        for (size_t i = 0; i < obstacles.size(); i++) {
            obstacles[i].pos.x--;
            
            if (obstacles[i].pos.x + obstacles[i].width < playerPos.x && !obstacles[i].passed) {
                obstacles[i].passed = true;
                score += 10 * difficulty;
            }
        }
        
        while (!obstacles.empty() && obstacles[0].pos.x < -5) {
            obstacles.erase(obstacles.begin());
        }
    }
    
    void updateCollectibles() {
        for (size_t i = 0; i < collectibles.size(); i++) {
            if (hasMagnet && magnetTimer > 0) {
                if (collectibles[i].pos.x > playerPos.x) {
                    collectibles[i].pos.x--;
                }
                if (collectibles[i].pos.y < playerPos.y) {
                    collectibles[i].pos.y++;
                } else if (collectibles[i].pos.y > playerPos.y) {
                    collectibles[i].pos.y--;
                }
            } else {
                collectibles[i].pos.x--;
            }
        }
        
        while (!collectibles.empty() && collectibles[0].pos.x < 0) {
            collectibles.erase(collectibles.begin());
        }
    }
    
    void updateParticles() {
        for (size_t i = 0; i < particles.size(); i++) {
            particles[i].pos.y += (int)particles[i].vy;
            particles[i].vy += 0.1f;
            particles[i].life--;
        }
        
        while (!particles.empty() && particles[0].life <= 0) {
            particles.erase(particles.begin());
        }
    }
    
    void updatePowerups() {
        if (hasShield) {
            shieldTimer--;
            if (shieldTimer <= 0) hasShield = false;
        }
        if (hasMagnet) {
            magnetTimer--;
            if (magnetTimer <= 0) hasMagnet = false;
        }
        if (invincibleTimer > 0) {
            invincibleTimer--;
        }
    }
    
    void createLandParticles() {
        for (int i = 0; i < 3; i++) {
            Particle p;
            p.pos = Position(playerPos.x + rand() % 3 - 1, playerPos.y);
            p.symbol = '.';
            p.color = COLOR_GROUND;
            p.life = 8;
            p.maxLife = 8;
            p.vy = -0.5f;
            particles.push_back(p);
        }
    }
    
    void checkCollisions() {
        if (invincibleTimer > 0) return;
        
        int playerWidth = (playerState == STATE_SLIDING) ? 3 : 1;
        int playerHeight = (playerState == STATE_SLIDING) ? 1 : 2;
        int playerTop = (playerState == STATE_SLIDING) ? playerPos.y : playerPos.y - 1;
        
        for (size_t i = 0; i < obstacles.size(); i++) {
            if (checkRectCollision(
                    playerPos.x, playerTop, playerWidth, playerHeight,
                    obstacles[i].pos.x, obstacles[i].pos.y - obstacles[i].height + 1,
                    obstacles[i].width, obstacles[i].height)) {
                
                if (hasShield) {
                    hasShield = false;
                    shieldTimer = 0;
                    invincibleTimer = 30;
                    createShieldBreakParticles();
                } else {
                    playerState = STATE_DEAD;
                    gameRunning = false;
                    return;
                }
            }
        }
        
        for (size_t i = 0; i < collectibles.size(); i++) {
            if (collectibles[i].active &&
                abs(collectibles[i].pos.x - playerPos.x) <= 1 &&
                abs(collectibles[i].pos.y - playerPos.y) <= 1) {
                
                collectItem(i);
            }
        }
    }
    
    bool checkRectCollision(int x1, int y1, int w1, int h1,
                            int x2, int y2, int w2, int h2) {
        return !(x1 + w1 <= x2 || x2 + w2 <= x1 ||
                 y1 + h1 <= y2 || y2 + h2 <= y1);
    }
    
    void collectItem(int index) {
        Collectible& item = collectibles[index];
        
        switch (item.type) {
            case 0:
                coins += item.value;
                score += item.value * 2;
                break;
            case 1:
                hasShield = true;
                shieldTimer = 300;
                break;
            case 2:
                hasMagnet = true;
                magnetTimer = 300;
                break;
            case 3:
                score += 100;
                invincibleTimer = 60;
                break;
        }
        
        item.active = false;
        collectibles.erase(collectibles.begin() + index);
    }
    
    void createShieldBreakParticles() {
        for (int i = 0; i < 15; i++) {
            Particle p;
            p.pos = playerPos;
            p.symbol = 'O';
            p.color = COLOR_SHIELD;
            p.life = 20;
            p.maxLife = 20;
            p.vy = -(rand() % 30) / 10.0f - 1;
            particles.push_back(p);
        }
    }
    
    void spawnObjects() {
        int spawnChance = max(20, 100 - difficulty * 3);
        
        if (frameCount % spawnChance == 0) {
            Obstacle obs;
            obs.passed = false;
            obs.pos.x = SCREEN_WIDTH;
            
            int typeRoll = rand() % 100;
            if (typeRoll < 40) {
                obs.type = OBSTACLE_SPIKE;
                obs.width = 1;
                obs.height = 1;
                obs.pos.y = GROUND_Y;
            } else if (typeRoll < 70) {
                obs.type = OBSTACLE_BLOCK;
                obs.width = 1;
                obs.height = 2;
                obs.pos.y = GROUND_Y;
            } else if (typeRoll < 85) {
                obs.type = OBSTACLE_TALL_BLOCK;
                obs.width = 1;
                obs.height = 4;
                obs.pos.y = GROUND_Y;
            } else {
                obs.type = OBSTACLE_BIRD;
                obs.width = 1;
                obs.height = 2;
                obs.pos.y = GROUND_Y - 3 - rand() % 3;
            }
            
            obstacles.push_back(obs);
        }
        
        if (frameCount % 40 == 0 && rand() % 100 < 40) {
            Collectible coin;
            coin.pos = Position(SCREEN_WIDTH, GROUND_Y - 1 - rand() % 3);
            coin.type = 0;
            coin.value = 1 + rand() % 3;
            coin.active = true;
            collectibles.push_back(coin);
        }
        
        if (frameCount % 300 == 0 && rand() % 100 < 30) {
            Collectible powerup;
            powerup.pos = Position(SCREEN_WIDTH, GROUND_Y - 2);
            powerup.active = true;
            
            int roll = rand() % 3;
            if (roll == 0) {
                powerup.type = 1;
                powerup.value = 1;
            } else if (roll == 1) {
                powerup.type = 2;
                powerup.value = 1;
            } else {
                powerup.type = 3;
                powerup.value = 1;
            }
            
            collectibles.push_back(powerup);
        }
    }
    
    void render() {
        gotoxy(0, 0);
        
        drawBackground();
        drawGround();
        drawParticles();
        drawCollectibles();
        drawObstacles();
        drawPlayer();
        drawUI();
    }
    
    void drawBackground() {
        for (int y = 0; y < GROUND_Y; y++) {
            gotoxy(0, y);
            for (int x = 0; x < SCREEN_WIDTH; x++) {
                bool isStar = false;
                for (size_t i = 0; i < bgStars.size(); i++) {
                    if (bgStars[i].x == (x + bgOffset) % SCREEN_WIDTH && 
                        bgStars[i].y == y) {
                        isStar = true;
                        break;
                    }
                }
                
                if (isStar) {
                    setColor(8);
                    cout << '.';
                } else {
                    cout << ' ';
                }
            }
        }
    }
    
    void drawGround() {
        setColor(COLOR_GROUND);
        gotoxy(0, GROUND_Y);
        for (int x = 0; x < SCREEN_WIDTH; x++) {
            if (x % 4 == 0) {
                cout << '|';
            } else {
                cout << CHAR_GROUND;
            }
        }
        
        for (int y = GROUND_Y + 1; y < SCREEN_HEIGHT; y++) {
            gotoxy(0, y);
            setColor(8);
            for (int x = 0; x < SCREEN_WIDTH; x++) {
                cout << ':';
            }
        }
    }
    
    void drawPlayer() {
        if (playerState == STATE_DEAD) return;
        
        if (invincibleTimer > 0 && frameCount % 4 < 2) {
            setColor(COLOR_PLAYER + 8);
        } else {
            setColor(COLOR_PLAYER);
        }
        
        char playerChar;
        switch (playerState) {
            case STATE_SLIDING:
                playerChar = CHAR_PLAYER_SLIDE;
                gotoxy(playerPos.x, playerPos.y);
                cout << playerChar << playerChar << playerChar;
                break;
            default:
                if (playerPos.y < GROUND_Y - 1) {
                    playerChar = CHAR_PLAYER_JUMP;
                } else {
                    playerChar = CHAR_PLAYER;
                }
                gotoxy(playerPos.x, playerPos.y);
                cout << playerChar;
                gotoxy(playerPos.x, playerPos.y - 1);
                cout << 'O';
                break;
        }
        
        if (hasShield) {
            setColor(COLOR_SHIELD);
            gotoxy(playerPos.x - 1, playerPos.y - 1);
            cout << '(';
            gotoxy(playerPos.x + 1, playerPos.y - 1);
            cout << ')';
        }
    }
    
    void drawObstacles() {
        for (size_t i = 0; i < obstacles.size(); i++) {
            if (obstacles[i].pos.x < 0 || obstacles[i].pos.x >= SCREEN_WIDTH) continue;
            
            switch (obstacles[i].type) {
                case OBSTACLE_SPIKE:
                    setColor(COLOR_OBSTACLE);
                    gotoxy(obstacles[i].pos.x, obstacles[i].pos.y);
                    cout << CHAR_SPIKE;
                    break;
                    
                case OBSTACLE_BLOCK:
                    setColor(COLOR_OBSTACLE);
                    gotoxy(obstacles[i].pos.x, obstacles[i].pos.y);
                    cout << CHAR_BLOCK;
                    gotoxy(obstacles[i].pos.x, obstacles[i].pos.y - 1);
                    cout << CHAR_BLOCK;
                    break;
                    
                case OBSTACLE_TALL_BLOCK:
                    setColor(COLOR_OBSTACLE + 4);
                    gotoxy(obstacles[i].pos.x, obstacles[i].pos.y);
                    cout << CHAR_BLOCK;
                    for (int h = 1; h < obstacles[i].height; h++) {
                        gotoxy(obstacles[i].pos.x, obstacles[i].pos.y - h);
                        cout << CHAR_BLOCK;
                    }
                    break;
                    
                case OBSTACLE_BIRD:
                    setColor(COLOR_OBSTACLE + 2);
                    gotoxy(obstacles[i].pos.x, obstacles[i].pos.y);
                    cout << CHAR_BIRD;
                    gotoxy(obstacles[i].pos.x, obstacles[i].pos.y - 1);
                    cout << CHAR_BIRD;
                    break;
            }
        }
    }
    
    void drawCollectibles() {
        for (size_t i = 0; i < collectibles.size(); i++) {
            if (!collectibles[i].active || 
                collectibles[i].pos.x < 0 || 
                collectibles[i].pos.x >= SCREEN_WIDTH) continue;
            
            if (collectibles[i].pos.y < 0 || 
                collectibles[i].pos.y >= GROUND_Y) continue;
            
            switch (collectibles[i].type) {
                case 0:
                    setColor(COLOR_COIN);
                    gotoxy(collectibles[i].pos.x, collectibles[i].pos.y);
                    cout << CHAR_COIN;
                    break;
                case 1:
                    setColor(COLOR_SHIELD);
                    gotoxy(collectibles[i].pos.x, collectibles[i].pos.y);
                    cout << CHAR_SHIELD;
                    break;
                case 2:
                    setColor(COLOR_MAGNET);
                    gotoxy(collectibles[i].pos.x, collectibles[i].pos.y);
                    cout << CHAR_MAGNET;
                    break;
                case 3:
                    setColor(frameCount % 6 < 3 ? COLOR_STAR : COLOR_STAR + 8);
                    gotoxy(collectibles[i].pos.x, collectibles[i].pos.y);
                    cout << CHAR_STAR;
                    break;
            }
        }
    }
    
    void drawParticles() {
        for (size_t i = 0; i < particles.size(); i++) {
            if (particles[i].pos.y < 0 || particles[i].pos.y >= GROUND_Y) continue;
            if (particles[i].pos.x < 0 || particles[i].pos.x >= SCREEN_WIDTH) continue;
            
            float alpha = (float)particles[i].life / particles[i].maxLife;
            int color = particles[i].color;
            if (alpha < 0.5) color += 8;
            
            setColor(color);
            gotoxy(particles[i].pos.x, particles[i].pos.y);
            cout << particles[i].symbol;
        }
    }
    
    void drawUI() {
        setColor(COLOR_UI);
        
        gotoxy(0, SCREEN_HEIGHT + 1);
        cout << "══════════════════════════════════════════════════════════════";
        
        gotoxy(2, SCREEN_HEIGHT + 2);
        cout << "Score: " << score << "  ";
        cout << "High: " << highScore << "  ";
        cout << "Coins: " << coins << "  ";
        cout << "Distance: " << distance / 10 << "m  ";
        cout << "Level: " << difficulty;
        
        gotoxy(2, SCREEN_HEIGHT + 3);
        if (hasShield) {
            setColor(COLOR_SHIELD);
            cout << "[SHIELD " << shieldTimer / 60 << "s] ";
        }
        if (hasMagnet) {
            setColor(COLOR_MAGNET);
            cout << "[MAGNET " << magnetTimer / 60 << "s] ";
        }
        if (invincibleTimer > 0) {
            setColor(COLOR_STAR);
            cout << "[INVINCIBLE " << invincibleTimer / 10 << "]";
        }
        
        setColor(8);
        gotoxy(2, SCREEN_HEIGHT + 4);
        cout << "SPACE:Jump(2x) | S:Slide | P:Pause | ESC:Quit";
        
        if (gamePaused) {
            setColor(COLOR_STAR);
            gotoxy(SCREEN_WIDTH / 2 - 5, SCREEN_HEIGHT / 2);
            cout << "[ PAUSED ]";
        }
    }
    
    void showStartScreen() {
        system("cls");
        setColor(COLOR_STAR);
        
        string title[] = {
            "╔═══════════════════════════════╗",
            "║     PARKOUR RUNNER v2.0       ║",
            "║        ___    ___   _         ║",
            "║       | _ \\  / _ \\ | |        ║               恭喜你发现了彩蛋!",
            "║       |  _/ | (_) ||_|        ║               作者:Wink                            真正作者:Deepseek",
            "║       |_|    \\___/ (_)        ║",
            "║                               ║",
            "╚═══════════════════════════════╝"
        };
        
        for (int i = 0; i < 8; i++) {
            gotoxy(SCREEN_WIDTH / 2 - 16, 5 + i);
            cout << title[i];
        }
        
        setColor(COLOR_UI);
        gotoxy(SCREEN_WIDTH / 2 - 12, 14);
        cout << "Press ENTER to Start";
        gotoxy(SCREEN_WIDTH / 2 - 10, 15);
        cout << "High Score: " << highScore;
        
        while (true) {
            if (_kbhit()) {
                char key = _getch();
                if (key == 13) break;
                if (key == 27) exit(0);
            }
        }
    }
    
    void showPauseScreen() {
        setColor(COLOR_STAR);
        gotoxy(SCREEN_WIDTH / 2 - 5, SCREEN_HEIGHT / 2);
        cout << "[ PAUSED ]";
    }
    
    void showGameOverScreen() {
        system("cls");
        
        if (score > highScore) {
            highScore = score;
            saveHighScore();
        }
        
        setColor(COLOR_OBSTACLE);
        string gameOver[] = {
            "╔═══════════════════════════════╗",
            "║          GAME OVER!           ║",
            "╚═══════════════════════════════╝"
        };
        
        for (int i = 0; i < 3; i++) {
            gotoxy(SCREEN_WIDTH / 2 - 16, 6 + i);
            cout << gameOver[i];
        }
        
        setColor(COLOR_STAR);
        gotoxy(SCREEN_WIDTH / 2 - 10, 10);
        cout << "Final Score: " << score;
        
        setColor(COLOR_COIN);
        gotoxy(SCREEN_WIDTH / 2 - 10, 11);
        cout << "Coins: " << coins;
        
        setColor(COLOR_UI);
        gotoxy(SCREEN_WIDTH / 2 - 10, 12);
        cout << "Distance: " << distance / 10 << "m";
        
        if (score >= highScore) {
            setColor(COLOR_STAR);
            gotoxy(SCREEN_WIDTH / 2 - 12, 14);
            cout << "*** NEW HIGH SCORE! ***";
        }
        
        setColor(COLOR_UI);
        gotoxy(SCREEN_WIDTH / 2 - 12, 16);
        cout << "Press ENTER to Restart";
        gotoxy(SCREEN_WIDTH / 2 - 10, 17);
        cout << "Press ESC to Exit";
        
        while (true) {
            if (_kbhit()) {
                char key = _getch();
                if (key == 13) {
                    initGame();
                    run();
                    break;
                }
                if (key == 27) {
                    break;
                }
            }
        }
    }
};

int main() {
    srand((unsigned int)time(NULL));
    
    ParkourGame game;
    game.run();
    
    return 0;
}