#include <stdio.h>
#include <stdlib.h>  // rand()
#include <conio.h>   // _getch()
#include <windows.h> // Sleep()

#define CELL_W 24 // 迷路のx方向のマスの数
#define CELL_H 13 // 迷路のy方向のマスの数
#define MON_MAX 3 // モンスターの数
enum { UP, DOWN, LEFT, RIGHT }; // 進む向きを列挙定数とする

char maze[CELL_H][CELL_W + 1] = { // 文字列配列で迷路を定義
    "########################",
    "#     G   #            #",
    "# ##### # # # ###### # #",
    "# #     # # #      # #G#",
    "#G# ##### # ###### # # #",
    "#          G         #G#",
    "### ##### # ###### # # #",
    "#  G    #          # #G#",
    "# # ####### ###### # # #",
    "# #                #   #",
    "# # # ##### ########## #",
    "#   #         G G G    #",
    "########################"
};

struct CHARACTER { // キャラクター用の構造体
    int x;
    int y;
    int dir;
};

void cursor(int x, int y) { // カーソル位置を指定する関数
    printf("\x1b[%d;%dH", y + 1, x + 1);
}

int main(void) { // main関数
    int score = 0; // スコアを代入する変数
    int timer = 0; // 時間（フレーム数）を数える変数
    struct CHARACTER player = { 1, 1, 0 }; // プレイヤーの座標を扱う構造体変数
    struct CHARACTER monster[MON_MAX] = { // モンスター用の構造体の配列
        { 22,  1, UP   },
        {  1, 11, DOWN },
        { 22, 11, LEFT }
    };

    while (1) { // 無限ループで繰り返す
        timer++; // フレーム数をカウント

        cursor(0, 0); // カーソル位置を左上角にする
        for (int i = 0; i < CELL_H; i++) { // 迷路を表示
            printf(maze[i]);
            printf("\n");
        }

        // プレイヤーの処理
        if (_kbhit()) { // キー入力があった時
            char key = _getch();
            int nx = player.x, ny = player.y; // 現在の座標をnxとnyに代入
            if (key == 72) ny -= 1; // 上キー
            if (key == 80) ny += 1; // 下キー
            if (key == 75) nx -= 1; // 左キー
            if (key == 77) nx += 1; // 右キー
            if (maze[ny][nx] != '#') { // 移動先が壁ではない
                player.x = nx;
                player.y = ny;
            }
        }
        if (maze[player.y][player.x] == 'G') { // 宝に載った
            maze[player.y][player.x] = ' ';
            score += 100;
        }
        cursor(player.x, player.y); // プレイヤーキャラを表示
        printf("P");

        // モンスターの処理
        char caught = 0; // モンスターに捕まったか
        for (int i = 0; i < MON_MAX; i++) {
            if (timer % 2 == 0) { // 1フレームおきに動かす
                int nx = monster[i].x, ny = monster[i].y; // 現在の座標をnxとnyに代入
                if (monster[i].dir == UP) ny -= 1; // 上
                if (monster[i].dir == DOWN) ny += 1; // 下
                if (monster[i].dir == LEFT) nx -= 1; // 左
                if (monster[i].dir == RIGHT) nx += 1; // 右
                if (maze[ny][nx] != '#') { // 移動先が壁ではない
                    monster[i].x = nx;
                    monster[i].y = ny;
                }
                else { // 壁にぶつかったらランダムに向きを変える
                    monster[i].dir = rand() % 4;
                }
            }
            cursor(monster[i].x, monster[i].y); // モンスターを表示
            printf("M");
            if (player.x == monster[i].x && player.y == monster[i].y) caught = 1; // ヒットチェック
        }

        if (timer % 30 == 0) { // 定期的に宝が出現
            int x = 1 + rand() % (CELL_W - 2);
            int y = 1 + rand() % (CELL_H - 2);
            if (maze[y][x] == ' ') maze[y][x] = 'G';
        }

        cursor(0, 14);
        printf("SCORE %d", score); // スコア
        if (caught) break; // モンスターに捕まったらwhileを抜ける
        Sleep(100); // 一定時間待って繰り返す
    }

    // ゲームオーバー時に表示
    cursor(0, 16);
    printf("GAME OVER\n");
    Sleep(3000); // 一定時間待って処理を終える
}