#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <conio.h>
#include <cmath>
#include <windows.h>
#include <bits/stdc++.h>
using namespace std;

HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord;

void locate(int x, int y) {
    coord.X = y;
    coord.Y = x;
    SetConsoleCursorPosition(hout, coord);
}

void hide() {
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(hout, &cursor_info);
}

double random(double start, double end) {
    return start + (end - start) * rand() / (RAND_MAX + 1.0);
}

int m = 25, n = 40;

struct node {
    int x, y;
};

struct Snake {
    node body[1000];
    int length;
    int direction;
    char headChar;
    char bodyChar;
} snake1, snake2;

node food;
int direct[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
bool allow_self_collision = false;
bool two_players = false;

void print_wall() {
    cout << " ";
    for (int i = 1; i <= n; i++) cout << "-";
    cout << endl;
    for (int j = 1; j <= m; j++) {
        cout << "|";
        for (int i = 1; i <= n; i++) cout << " ";
        cout << "|" << endl;
    }
    cout << " ";
    for (int i = 1; i <= n; i++)
        cout << "-";
}

void print_snake(const Snake& s) {
    locate(s.body[0].x, s.body[0].y);
    cout << s.headChar;
    for (int i = 1; i < s.length; i++) {
        locate(s.body[i].x, s.body[i].y);
        cout << s.bodyChar;
    }
}

bool is_correct(const Snake& s) {
    // 检查墙壁碰撞
    if (s.body[0].x < 1 || s.body[0].y < 1 || s.body[0].x > m || s.body[0].y > n)
        return false;

    // 检查自身碰撞
    if (!allow_self_collision) {
        for (int i = 1; i < s.length; i++) {
            if (s.body[0].x == s.body[i].x && s.body[0].y == s.body[i].y)
                return false;
        }
    }

    // 双人模式下检查与另一条蛇的碰撞
    if (two_players) {
        const Snake& other = (&s == &snake1) ? snake2 : snake1;
        for (int i = 0; i < other.length; i++) {
            if (s.body[0].x == other.body[i].x && s.body[0].y == other.body[i].y)
                return false;
        }
    }

    return true;
}

bool print_food() {
    srand((unsigned)time(0));
    while (true) {
        food.x = rand() % m + 1;
        food.y = rand() % n + 1;

        bool valid = true;
        
        // 检查是否与蛇1重叠
        for (int k = 0; k < snake1.length; k++) {
            if (snake1.body[k].x == food.x && snake1.body[k].y == food.y) {
                valid = false;
                break;
            }
        }

        // 检查是否与蛇2重叠
        if (two_players && valid) {
            for (int k = 0; k < snake2.length; k++) {
                if (snake2.body[k].x == food.x && snake2.body[k].y == food.y) {
                    valid = false;
                    break;
                }
            }
        }

        if (valid) break;
    }
    locate(food.x, food.y);
    cout << "$";
    return true;
}

bool go_ahead(Snake& s) {
    node temp = s.body[s.length-1];

    // 移动蛇身
    for (int i = s.length-1; i >= 1; i--)
        s.body[i] = s.body[i-1];

    // 移动蛇头
    s.body[0].x += direct[s.direction][0];
    s.body[0].y += direct[s.direction][1];

    // 打印移动后的蛇
    locate(s.body[1].x, s.body[1].y);
    cout << s.bodyChar;

    bool ateFood = (s.body[0].x == food.x && s.body[0].y == food.y);
    if (ateFood) {
        s.length++;
        s.body[s.length-1] = temp;
        print_food();
    } else {
        locate(temp.x, temp.y);
        cout << " ";
    }

    // 打印蛇头
    locate(s.body[0].x, s.body[0].y);
    cout << s.headChar;

    if (!is_correct(s)) {
        system("cls");
        if (two_players) {
            cout << ((&s == &snake1) ? "玩家2" : "玩家1") << "获胜!" << endl;
            cout << "玩家1长度: " << snake1.length << endl;
            cout << "玩家2长度: " << snake2.length << endl;
        } else {
            cout << "游戏结束! 你的长度: " << s.length << endl;
        }
        return false;
    }
    return true;
}

int main() {
    cout << "--------------------贪吃蛇---------------------" << endl;
    cout << "请注意窗口大小,以免发生错位.建议将窗口调为最大." << endl;
    cout << "选择游戏模式: (1-单人, 2-双人): ";
    int mode;
    cin >> mode;
    two_players = (mode == 2);
    
    cout << "是否允许蛇碰到自己的身体? (1-允许, 0-不允许): ";
    int allow_coll;
    cin >> allow_coll;
    allow_self_collision = (allow_coll == 1);
    
    cout << "先选择难度(1-100, 1最简单,100最难): ";
    int hard;
    cin >> hard;
    if (hard < 1 || hard > 100) {
        cout << "无效难度!" << endl;
        return 1;
    }

    // 初始化蛇1 - 左上角向右
    snake1.length = 3;
    snake1.direction = 3; // 右
    snake1.headChar = '@';
    snake1.bodyChar = '*';
    for (int i = 0; i < 3; i++) {
        snake1.body[i].x = 5;
        snake1.body[i].y = 5 - i;
    }

    // 初始化蛇2 - 右下角向左
    if (two_players) {
        snake2.length = 3;
        snake2.direction = 2; // 左
        snake2.headChar = 'O';
        snake2.bodyChar = '+';
        for (int i = 0; i < 3; i++) {
            snake2.body[i].x = m - 4;
            snake2.body[i].y = n - 5 + i;
        }
    }

    system("cls");
    hide();
    print_wall();
    print_food();
    print_snake(snake1);
    if (two_players) {
        print_snake(snake2);
    }
    locate(m+2, 0);
    cout << "玩家1长度: " << snake1.length;
    if (two_players) {
        locate(m+3, 0);
        cout << "玩家2长度: " << snake2.length;
    }

    double hard_len;
    clock_t a, b;
    while (true) {
        hard_len = (double)snake1.length / (m * n);
        a = clock();
        while (true) {
            b = clock();
            if (b - a >= (int)(400 - 30 * hard) * (1 - sqrt(hard_len)))
                break;
                
            if (_kbhit()) {
                int ch = _getch();
                if (ch == 0xE0) { // 方向键
                    ch = _getch();
                    switch (ch) {
                        case 72: if (snake1.direction != 1) snake1.direction = 0; break; // 上
                        case 80: if (snake1.direction != 0) snake1.direction = 1; break; // 下
                        case 75: if (snake1.direction != 3) snake1.direction = 2; break; // 左
                        case 77: if (snake1.direction != 2) snake1.direction = 3; break; // 右
                    }
                } else if (two_players) {
                    ch = tolower(ch);
                    if (ch == 'w' && snake2.direction != 1) snake2.direction = 0;
                    else if (ch == 's' && snake2.direction != 0) snake2.direction = 1;
                    else if (ch == 'a' && snake2.direction != 3) snake2.direction = 2;
                    else if (ch == 'd' && snake2.direction != 2) snake2.direction = 3;
                }
            }
        }

        bool snake1_alive = go_ahead(snake1);
        locate(m+2, 12);
        cout << snake1.length;
        
        bool snake2_alive = true;
        if (two_players) {
            snake2_alive = go_ahead(snake2);
            locate(m+3, 12);
            cout << snake2.length;
        }

        if (!snake1_alive || !snake2_alive)
            break;
    }

    system("pause");
    return 0;
}