#include <iostream>
#include <cstdio>
#include <cstring>
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <ctime>

using namespace std;

class Button {
    public:
        int startX, endX;
        int startY, endY;
};

int width, height;
int numTarget;
int numHasWent;
Button startGame, quit;

char a[101][101];
bool s[101][101];
int way[101][3];
int dx[] = {0, 0, 1, -1, 1, 1, -1, -1};
int dy[] = {1, -1, 0, 0, -1, 1, -1, 1};

void init();
void start();
void procedure();
void bfs(int,int);
void die();
void color(int);
int suiJi();
int numTargetAround(int,int);
COORD mousePosition();
bool hasClicked();

int main(int argc, char *argv[])
{
    SetConsoleTitle("扫雷");
    init();
    procedure();
    return 0;
}

void init()
{
    startGame.startX = 1;
    startGame.endX = 8;
    startGame.startY = startGame.endY = 2;
    quit.startX = 10;
    quit.endX = 13;
    quit.startY = quit.endY = 2;
    start();

    cout << "请输入雷阵行数:";
    cin >> height;
    cout << "请输入雷阵列数:";
    cin >> width;
    if (height < 3) height = 3;
    if (height > 20) height = 20;
    if (width < 3) width = 3;
    if (width > 20) width = 20;

    memset(s, false, sizeof(s));
    memset(a, 0, sizeof(a));
    numHasWent = 0;
    numTarget = height*width/4;
    srand(time(0));
    for (int i=1; i<=numTarget; i++) {
        int targetX = rand()%height+1;
        int targetY = rand()%width+1;
        a[targetX][targetY] = '*';
    }
    numTarget = 0;
    for (int i=1; i<=height; i++) {
        for (int j=1; j<=width; j++) {
            if (a[i][j] == '*') {
                numTarget++;
            }
        }
    }
    for (int i=1; i<=height; i++) {
        for (int j=1; j<=width; j++) {
            if (a[i][j] != '*') {
                a[i][j] = numTargetAround(i, j)+48;
            }
        }
    }

    quit.startX = 1;
    quit.endX = 4;
    quit.startY = height+2;
    quit.endY = height+2;

    cout << "按任意键开始......";
    getch();
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0, 0});
    cout << "                                     " << endl;
    cout << "                                     " << endl;
    cout << "                                     " << endl;
    cout << "                                     " << endl;
    cout << "                                     " << endl;
    cout << "                                     " << endl;
    cout << "                                     " << endl;
    cout << "                                     " << endl;
}

void start()
{
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0,0});
    cout << "#  控制台扫雷  #" << endl;
    cout << "#--------------#" << endl;
    cout << "#开始游戏|退出|#" << endl;
    cout << "#--------------#" << endl;

    while (1) {
        if (hasClicked()) {
            COORD pos = mousePosition();
            if (pos.X>=startGame.startX and pos.X<=startGame.endX and pos.Y>=startGame.startY and pos.Y<=startGame.endY) {
                break;
            }else if (pos.X>=quit.startX and pos.X<=quit.endX and pos.Y>=quit.startY and pos.Y<=quit.endY) {
                exit(0);
            }
        }
    }
}

void procedure()
{
    while (numHasWent+numTarget < height*width) {
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0, 0});
        for (int i=0; i<=height+1; i++) {
            for (int j=0; j<=width+1; j++) {
                if (i>=1 && i<=height && j>=1 && j<=width) {
                    if (s[i][j] == false) {
                        color(9);
                        cout << '#';
                    }else{
                        color(10);
                        if (a[i][j] != '0') cout << a[i][j];
                        else cout << ' ';
                    }
                }else{
                    color(15);
                    cout << '#';
                }
            }
            cout << endl;
        }
        color(7);
        cout << "|退出|" << endl;
        cout << "------" << endl;

        bool clicked = false;
        while (!clicked) {
            if (hasClicked()) {
                COORD pos = mousePosition();
                if (pos.X>=quit.startX and pos.X<=quit.endX and pos.Y>=quit.startY and pos.Y<=quit.endY) {
                    return;
                }else{
                    if (pos.Y>=1 and pos.Y<=height and pos.X>=1 and pos.X<=width) {
                        if (s[pos.Y][pos.X] == false) {
                            if (a[pos.Y][pos.X] == '*') {
                                die();
                                return;
                            }else{
                                numHasWent++;
                                s[pos.Y][pos.X] = true;
                                bfs(pos.Y, pos.X);
                            }
                        }
                    }
                }
                clicked = true;
            }
        }
    }
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0,0});
    for (int i=0; i<=height+1; i++) {
        for (int j=0; j<=width+1; j++) {
            if (i>=1 and i<=height and j>=1 and j<=width) {
                if (s[i][j] == false) {
                    color(9);
                    cout << '#';
                }else{
                    color(10);
                    if (a[i][j] != '0') cout << a[i][j];
                    else cout << ' ';
                }
            }else{
                color(15);
                cout << '#';
            }
        }
        cout << endl;
    }
    color(7);
    cout << "        " << endl << "        " << endl;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0, height+2});
    cout << "你赢了!" << endl;
    cout << "按任意键退出......";
    getch();
}

void bfs(int x, int y)
{
    int head = 0, tail = 1;
    memset(way, 0, sizeof(way));
    way[1][0] = x;
    way[1][1] = y;
    while (head < tail) {
        head++;
        for (int i=0; i<4; i++) {
            int xx = way[head][0]+dx[i];
            int yy = way[head][1]+dy[i];
            if (xx>=1 && xx<=height && yy>=1 && yy<=width && !s[xx][yy] && a[xx][yy]!='*' && way[head][2]<height/2) {
                s[xx][yy] = true;
                numHasWent++;
                tail++;
                way[tail][0] = xx;
                way[tail][1] = yy;
                way[tail][2] = way[head][2]+1;
            }
        }
    }
}

void die()
{
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0, 0});
    for (int i=0; i<=height+1; i++) {
        for (int j=0; j<=width+1; j++) {
            cout << ' ';
        }
    }
    cout << "                " << endl;
    cout << "                " << endl;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), (COORD){0, 0});
    for (int i=0; i<=height+1; i++) {
        for (int j=0; j<=width+1; j++) {
            if (i>=1 and i<=height and j>=1 and j<=width) {
                if (a[i][j] == '*') {
                    color(12);
                    cout << a[i][j];
                }else{
                    if (s[i][j] == false) {
                        color(9);
                        cout << '#';
                    }else{
                        color(10);
                        if (a[i][j] != '0') cout << a[i][j];
                        else cout << ' ';
                    }
                }    
            }else{
                color(15);
                cout << '#';
            }
        }
        cout << endl;
    }
    color(7);
    cout << "你over了!" << endl;
    cout << "按任意键退出......";
    getch();
    cout << endl;
}

void color(int a) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}

int suiJi()
{
    srand(time(0));
    return rand();
}

int numTargetAround(int x, int y)
{
    int ans = 0;
    for (int i=0; i<8; i++) {
        int xx = x+dx[i], yy = y+dy[i];
        if (xx>=1 && xx<=height && yy>=1 && yy<=width) {
            if (a[xx][yy] == '*') {
                ans++;
            }
        }
    }
    return ans;
}

COORD mousePosition()
{
    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    DWORD res;
    INPUT_RECORD inRec;
    ReadConsoleInput(hIn, &inRec, 1, &res);
    if (inRec.EventType == MOUSE_EVENT) {
        return inRec.Event.MouseEvent.dwMousePosition;
    }
    return (COORD){-1, -1};
}

bool hasClicked()
{
    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    DWORD res;
    INPUT_RECORD inRec;
    ReadConsoleInput(hIn, &inRec, 1, &res);
    if (inRec.EventType == MOUSE_EVENT) {
        if (inRec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) {
            return true;
        }
        return false;
    }
    return false;
}