#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <assert.h>
#include <time.h>

#define ROW 20
#define COL 20

int TABLE[ROW][COL];

int Menu();
void tableInit();
void print_table();
void PlayerMove();
void BotMove();
int Check_Winner();
void PlayNow();

// 1表示玩家 10表示bot

int Menu() {
    int choice = -1;

    printf("-----------------------------------\n");
    printf("           1. 开始游戏              \n");
    printf("           2. 退出程序              \n");
    printf("-----------------------------------\n");
    printf("请输入选项:");
    scanf("%d", &choice);

    return choice;
}

// 棋盘初始化为空格
void tableInit() {
    for (int row = 0; row < ROW; row++) {
        for (int col = 0; col < COL; col++) {
            TABLE[row][col] = 0;
        }
    }
}

void print_table() {
    int i, j;

    printf("  1 2 3 4 5 6 7 8 9 1011121314151617181920\n");
    for (i = 1; i <= 20; i++)
    {
        printf("%2d", i);
        //第一行
        if (i == 1)
        {
            //第一列
            if (TABLE[i - 1][0] == 1)
                printf("●");
            if (TABLE[i - 1][0] == 10)
                printf("○");
            if (TABLE[i - 1][0] == 0)
                printf("┌ ");

            //第2-19列
            for (j = 2; j <= 19; j++)
            {
                if (TABLE[i - 1][j - 1] == 1)
                    printf("●");
                if (TABLE[i - 1][j - 1] == 10)
                    printf("○");
                if (TABLE[i - 1][j - 1] == 0)
                    printf("┬ ");
            }

            //第20列
            if (TABLE[i - 1][j - 1] == 1)
                printf("●");
            if (TABLE[i - 1][j - 1] == 10)
                printf("○");
            if (TABLE[i - 1][j - 1] == 0)
                printf("┐ ");

            printf("\n");
        }

        //第2-19行
        if (i <= 19 && i >= 2)
        {
            //第一列
            if (TABLE[i - 1][0] == 1)
                printf("●");
            if (TABLE[i - 1][0] == 10)
                printf("○");
            if (TABLE[i - 1][0] == 0)
                printf("├ ");

            //第2-19列
            for (j = 2; j <= 19; j++)
            {
                if (TABLE[i - 1][j - 1] == 1)
                    printf("●");
                if (TABLE[i - 1][j - 1] == 10)
                    printf("○");
                if (TABLE[i - 1][j - 1] == 0)
                    printf("┼ ");
            }

            //第20列
            if (TABLE[i - 1][j - 1] == 1)
                printf("●");
            if (TABLE[i - 1][j - 1] == 10)
                printf("○");
            if (TABLE[i - 1][j - 1] == 0)
                printf("┤ ");

            printf("\n");
        }

        //第20行
        if (i == 20)
        {
            if (TABLE[i - 1][0] == 1)
                printf("●");
            if (TABLE[i - 1][0] == 10)
                printf("○");
            if (TABLE[i - 1][0] == 0)
                printf("└ ");

            for (j = 2; j <= 19; j++)
            {
                if (TABLE[i - 1][j - 1] == 1)
                    printf("●");
                if (TABLE[i - 1][j - 1] == 10)
                    printf("○");
                if (TABLE[i - 1][j - 1] == 0)
                    printf("┴ ");
            }

            if (TABLE[i - 1][j - 1] == 1)
                printf("●");
            if (TABLE[i - 1][j - 1] == 10)
                printf("○");
            if (TABLE[i - 1][j - 1] == 0
)
                printf("┘ ");

            printf("\n");
        }

    }
}

void PlayerMove() {
    int row, col;

    printf("玩家落子!\n");

    while (1) {
        printf("请输入你要落子的位置(ROW COLUMN):");
        scanf("%d %d", &row, &col);
        row--; col--;

        // 检查用户输入是否合法
        if (row < 0 || row >= ROW) {
            printf("输入不合法,请重新输入!\n");
            continue;
        }
        if (col < 0 || col >= COL) {
            printf("输入不合法,请重新输入!\n");
            continue;
        }
        if (TABLE[row][col] != 0) {
            printf("这个位置已被占用,请重新输入!\n");
            continue;
        }

        // 合法 落子
        TABLE[row][col] = 1;
        system("cls");
        break;
    }

}

// 5个连续格子中已经有了n个玩家或bot的子
// rowN colN用于返回决定要下的子的位置
// 返回10表示找到了bot可以下的位置
// 返回1表示找到了玩家可以下的位置
int fuckPlayer(int n, int* rowN, int* colN) {
    int row, col;
    int tmp;
    int res;
    int rowIndex = -1, colIndex = -1;

    // 先检查bot
    // 检查横线
    for (row = 0; row < ROW; row++) {
        for (col = 0; col < COL - n; col++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {  // tmp用于循环n个相邻格子
                if (TABLE[row][col + tmp] == 0) {  // 记录下一个为空的格子,如果后面找到了可以下的位置,用于返回这个空格的坐标
                    rowIndex = row;
                    colIndex = col + tmp;
                }
                res += TABLE[row][col + tmp];
            }
            if (res == n * 10) {  // 五个格子中有了n个bot的子
                *rowN = rowIndex;
                *colN = colIndex;
                return 10;
            }
        }
    }

    // 检查竖线
    for (col = 0; col < COL; col++) {
        for (row = 0; row < ROW - n; row++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {  // tmp用于循环n个相邻格子
                if (TABLE[row + tmp][col] == 0) {  // 记录下一个为空的格子,如果后面找到了可以下的位置,用于返回这个空格的坐标
                    rowIndex = row + tmp;
                    colIndex = col;
                }
                res += TABLE[row + tmp][col];
            }
            if (res == n * 10) {  // 五个格子中有了n个bot的子
                *rowN = rowIndex;
                *colN = colIndex;
                return 10;
            }
        }
    }

    // 检查反斜线:'\'
    for (row = 0; row < ROW - n; row++) {
        for (col = 0; col < COL - n; col++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {
                if (TABLE[row + tmp][col + tmp] == 0) {
                    rowIndex = row + tmp;
                    colIndex = col + tmp;
                }
                res += TABLE[row + tmp][col + tmp];
            }
            if (res == n * 10) {
                *rowN = rowIndex;
                *colN = colIndex;
                return 10;
            }
        }
    }

    // 检查斜线:'/'
    for (row = 0; row < ROW - n; row++) {
        for (col = n; col < COL; col++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {
                if (TABLE[row + tmp][col - tmp] == 0) {
                    rowIndex = row + tmp;
                    colIndex = col - tmp;
                }
                res += TABLE[row + tmp][col - tmp];
            }
            if (res == n * 10) {
                *rowN = rowIndex;
                *colN = colIndex;
                return 10;
            }
        }
    }

    // 再检查玩家
    // 检查横线
    for (row = 0; row < ROW; row++) {
        for (col = 0; col < COL - n; col++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {  // tmp用于循环n个相邻格子
                if (TABLE[row][col + tmp] == 0) {  // 记录下一个为空的格子,如果后面找到了可以下的位置,用于返回这个空格的坐标
                    rowIndex = row;
                    colIndex = col + tmp;
                }
                res += TABLE[row][col + tmp];
            }
            if (res == n * 1) {  // 五个格子中有了n个玩家的子
                *rowN = rowIndex;
                *colN = colIndex;
                return 1;
            }
        }
    }

    // 检查竖线
    for (col = 0; col < COL; col++) {
        for (row = 0; row < ROW - n; row++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {  // tmp用于循环n个相邻格子
                if (TABLE[row + tmp][col] == 0) {  // 记录下一个为空的格子,如果后面找到了可以下的位置,用于返回这个空格的坐标
                    rowIndex = row + tmp;
                    colIndex = col;
                }
                res += TABLE[row + tmp][col];
            }
            if (res == n * 1) {  // 五个格子中有了n个玩家的子
                *rowN = rowIndex;
                *colN = colIndex;
                return 1;
            }
        }
    }

    // 检查反斜线:'\'
    for (row = 0; row < ROW - n; row++) {
        for (col = 0; col < COL - n; col++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {
                if (TABLE[row + tmp][col + tmp] == 0) {
                    rowIndex = row + tmp;
                    colIndex = col + tmp;
                }
                res += TABLE[row + tmp][col + tmp];
            }
            if (res == n * 1) {
                *rowN = rowIndex;
                *colN = colIndex;
                return 1;
            }
        }
    }

    // 检查斜线:'/'
    for (row = 0; row < ROW - n; row++) {
        for (col = n; col < COL; col++) {
            for (tmp = 0, res = 0; tmp < n + 1; tmp++) {
                if (TABLE[row + tmp][col - tmp] == 0) {
                    rowIndex = row + tmp;
                    colIndex = col - tmp;
                }
                res += TABLE[row + tmp][col - tmp];
            }
            if (res == n * 1) {
                *rowN = rowIndex;
                *colN = colIndex;
                return 1;
            }
        }
    }

    return 0;
}

void BotMove() {
    int row = -1, col = -1;
    if (fuckPlayer(4, &row, &col)) {

    }
    else if (fuckPlayer(3, &row, &col)) {

    }
    else if (fuckPlayer(2, &row, &col)) {

    }
    else if (fuckPlayer(1, &row, &col)) {

    }
    else {
        while (1) {
            row = rand() % 20;
            col = rand() % 20;

            if (TABLE[row][col] != 0) {
                continue;
            }
            else {
                break;
            }
        }
    }

    // 落子
    TABLE[row][col] = 10;
    system("cls");
}

// 玩家赢返回1
// bot赢返回10
// 和棋返回100
// 暂无胜者返回0
int Check_Winner() {
    int row, col;

    // 检查横线
    for (row = 0; row < ROW; row++) {
        for (col = 0; col <= COL - 5; col++) {
            if (TABLE[row][col]) {  // 有子才检查
                if ((TABLE[row][col] + TABLE[row][col + 1]
                    + TABLE[row][col + 2] + TABLE[row][col + 3]
                    + TABLE[row][col + 4]) == 5) {  // 玩家胜利
                    return 1;
                }
                if ((TABLE[row][col] + TABLE[row][col + 1]
                    + TABLE[row][col + 2] + TABLE[row][col + 3]
                    + TABLE[row][col + 4]) == 50) {  // bot胜利
                    return 10;
                }
            }
        }
    }

    // 检查竖线
    for (col = 0; col < COL; col++) {
        for (row = 0; row <= ROW - 5; row++) {
            if (TABLE[row][col]) {  // 有子才检查
                if ((TABLE[row][col] + TABLE[row + 1][col]
                    + TABLE[row + 2][col] + TABLE[row + 3][col]
                    + TABLE[row + 4][col]) == 5) {  // 玩家获胜
                    return 1;
                }
                if ((TABLE[row][col] + TABLE[row + 1][col]
                    + TABLE[row + 2][col] + TABLE[row + 3][col]
                    + TABLE[row + 4][col]) == 50) {  // bot获胜
                    return 10;
                }
            }
        }
    }

    // 检查反斜线:'\'
    for (row = 0; row <= ROW - 5; row++) {
        for (col = 0; col <= COL - 5; col++) {
            if (TABLE[row][col]) {  // 有子才检查
                if ((TABLE[row][col] + TABLE[row + 1][col + 1]
                    + TABLE[row + 2][col + 2] + TABLE[row + 3][col + 3]
                    + TABLE[row + 4][col + 4]) == 5) {  // 玩家胜利
                    return 1;
                }
                if ((TABLE[row][col] + TABLE[row + 1][col + 1]
                    + TABLE[row + 2][col + 2] + TABLE[row + 3][col + 3]
                    + TABLE[row + 4][col + 4]) == 50) {  // bot胜利
                    return 10;
                }
            }
        }
    }

    // 检查斜线:'/'
    for (row = 0; row <= ROW - 5; row++) {
        for (col = 4; col < COL; col++) {
            if (TABLE[row][col]) {  // 有子才检查
                if ((TABLE[row][col] + TABLE[row + 1][col - 1]
                    + TABLE[row + 2][col - 2] + TABLE[row + 3][col - 3]
                    + TABLE[row + 4][col - 4]) == 5) {  // 玩家胜利
                    return 1;
                }
                if ((TABLE[row][col] + TABLE[row + 1][col - 1]
                    + TABLE[row + 2][col - 2] + TABLE[row + 3][col - 3]
                    + TABLE[row + 4][col - 4]) == 50) {  // bot胜利
                    return 10;
                }
            }
        }
    }

    // 检查和棋
    for (row = 0; row < ROW; row++) {
        for (col = 0; col < COL; col++) {
            if (TABLE[row][col] == 0)
                return 0;
        }
    }

    // 和棋
    return 100;
}

void game() {
    int winner;

    // 1. 初始化棋盘
    tableInit();
    print_table();

    while (1) {
        // 2. 用户落子
        PlayerMove();
        print_table();

        // 3. 判断胜负
        winner = Check_Winner();
        if (winner != 0)  // 胜负已分
            break;

        // 4. bot落子
        BotMove();
        print_table();

        // 5. 判断胜负
        winner = Check_Winner();
        if (winner != 0)  // 胜负已分
            break;
    }

    if (winner == 1) {
        printf("您获胜了! ");
        Sleep(500);
        printf("niubi ");
        Sleep(500);
        printf("niubi ");
        Sleep(500);
        printf("niubi ");
        Sleep(500);
        printf("niubi \n");
        Sleep(500);
        return;
    }
    else if (winner == 10) {
        printf("Bot获胜了! ");
        Sleep(500);
        printf("ha ha ");
        Sleep(500);
        printf("ha ha ");
        Sleep(500);
        printf("ha ha ");
        Sleep(500);
        printf("ha ha\n");
        Sleep(500);
        return;
    }
    else if (winner == 100) {
        printf("您和Bot55开! ");
        Sleep(500);
        printf("55开 ");
        Sleep(500);
        printf("55开 ");
        Sleep(500);
        printf("55开 ");
        Sleep(500);
        printf("55开 \n");
        Sleep(500);
        return;
    }
    else {
        assert(0);
    }
}

void PlayNow() {
    int choice;

    srand((unsigned int)time(0));  // 设置种子

    while (1) {
        choice = Menu();
        if (choice == 1) {
            Sleep(200);
            system("cls");
            game();
            system("pause");
        }
        else if (choice == 2) {
            exit(0);
        }
        else {
            printf("输入错误,请重新输入");
            Sleep(500);
            printf("!");
            Sleep(500);
            printf("!");
            Sleep(500);
            printf("!");
            Sleep(500);
            system("cls");
            continue;
        }

        system("cls");
    }
}

int main() {
    PlayNow();

    system("pause");
    return 0;
}
Last modification:November 10th, 2019 at 10:09 am