Bootstrap

【C语言】五子棋(附源码+思路讲解)

在这里插入图片描述
欢迎来到我的博客!!💃💃
🏡🏡推荐博客:August_._一起持续学习,不断总结,共同进步🎊🎊

思路讲解

文件结构设计

我们学过多文件的形式对函数的声明和定义,现在我们设计三个文件:

game.h //游戏需要的数据类型和函数声明
game.c //游戏中函数的实现
main.c //游戏的测试逻辑

游戏逻辑流程图

在 main.c 文件中游戏测试的主体逻辑:
在这里插入图片描述

游戏简介

连成五子即为胜利!

玩家选择游戏模式玩家
0退出游戏
1人机对战X—人 、 0—电脑
2双人对战X—人 、 0—人

初始化棋盘

在 main.c 文件中定义棋盘【二维数组】:

char board[LEN][LEN];

利用 for 循环初始化棋盘,使数组每个数为空字符。

void initialize_board(char board[LEN][LEN], int row, int col)
{
    for(int i=0; i<row; i++)
        for(int j=0; j<col; j++)
            board[i][j] = ' ';
}

打印棋盘

15 x 15 的棋盘,在 game.h 中先宏定义:

#define LEN 15

代码实现:【printf(“\033[31m[0]\033[0m”); 知识详解见知识补充

void print_board(char board[LEN][LEN], int row, int col)
{
    int i, j;
    printf("\n");
    for (i=0; i<=row; i++) printf("%2d ", i);
    printf("\n");
    for (i=0; i<row; i++) {
        printf("%2d ", i+1);
        for (j=0; j<col; j++){
            if (board[i][j] == 'X') printf("\033[31m[X]\033[0m");  
            else if (board[i][j] == '0') printf("\033[34m[0]\033[0m");
            else printf("[ ]");
        }
    printf("\n");
    }
}

在这里插入图片描述

电脑玩家下棋

定义变量 row (行)、col (列),随机生成0—14的数字作为二维数组的下标,再判断数组该处是否为空字符,如果是,则电脑玩家下棋在该处,反之,进入下次循环,重新生成坐标。

void computer_move(char board[LEN][LEN], char Player){
    while(1){
        int row,col;
        //随机生成0-14数字
        row = rand()%LEN;
        col = rand()%LEN;
        if (board[row][col] != ' ') continue;
        else{
            board[row][col] = Player;
            printf("\n 电脑玩家(%c)下在:(%d,%d)", Player, row+1, col+1);
            break;
        }
    }
}

判断移动是否有效

game.c 文件:

int is_valid_move(int row, int col)
{
    return (row>=1 && row<=LEN && col>=1 && col<=LEN);
}

若条件成立,则 is_valid_move() 返回数字1,在 main.c 测试过程中用 if 判断:

if (!(is_valid_move(row, col))){
	printf("\n请输入正确的行、列(1<=row<=%d, 1<=col<=%d): ", LEN, LEN);
    continue;
}

判断胜负

五子棋连城五子即为胜利,判断输赢须在一个棋子的四个方向(横、竖、左斜、右斜),遍历是否有五子相连。若有五子连棋,则函数返回1,反之,则返回0。

int is_winner(char board[LEN][LEN], char Player)
{
    int i, j;
    //横 
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i][j+1]==Player && board[i][j+2]==Player && board[i][j+3]==Player && board[i][j+4]==Player)
                return 1;
        }
    }
    //竖 
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i+1][j]==Player && board[i+2][j]==Player && board[i+3][j]==Player && board[i+4][j]==Player)
                return 1;
        }
    }
    //左斜
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i+1][j+1]==Player && board[i+2][j+2]==Player && board[i+3][j+3]==Player && board[i+4][j+4]==Player)
                return 1;
        }
    }
    //右斜
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i-1][j-1]==Player && board[i-2][j-2]==Player && board[i-3][j-3]==Player && board[i-4][j-4]==Player)
                  return 1;
        }
    }
    return 0;
}

棋盘是否已满

利用 for 循环遍历棋盘,判断棋盘是否已满,若已满,则此局和棋,本局游戏结束;反之,本局游戏继续。

for (int i=0; i<LEN; i++){
	for (int j=0; j<LEN; j++){
		if (board[i][j] != ' ') counts++;
    }
}
if (counts == LEN * LEN){
    printf("棋盘已满,未分出胜负,该局和棋!");
    break;
}

源代码

头文件 game.h

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define LEN 15

//游戏
void game(char board[LEN][LEN], int game_mode);
//菜单
void meun();
//初始化棋盘
void initialize_board(char board[LEN][LEN], int row, int col);
//打印棋盘
void print_board(char board[LEN][LEN], int row, int col);
//判断移动是否有效
int is_valid_move(int row, int col);
//判断胜负
int is_winner(char board[LEN][LEN], char Player);
//电脑玩家下棋
void computer_move(char board[LEN][LEN], char Player);

主函数 main.c

#include "game.h"

void game(char board[LEN][LEN], int game_mode)
{
    char Player = 'X';
    int row, col, counts;

    //设置随机数种子
    srand((unsigned)time(NULL));
    //初始化棋盘
    initialize_board(board, LEN, LEN);
    print_board(board, LEN, LEN);

    while(1){
        if (game_mode == 2 || Player == 'X'){
            printf("当前玩家: %c", Player);
            printf("\n请输入你的选择(行 列): ");

            if (scanf("%d %d", &row, &col) != 2){
                printf("\n输入有误,请正确输入(行 列)!");
                //清空缓冲区
                while (getchar() != '\n')
                    continue;
            }
            //判断下棋是否有效
            if (!(is_valid_move(row, col))){
                printf("\n请输入正确的行、列(1<=row<=%d, 1<=col<=%d): ", LEN, LEN);
                continue;
            }
            if (board[row-1][col-1] != ' '){
                printf("\n此处已经有旗子,请重新输入(行 列) ");
                continue;
            }
            board[row-1][col-1] = Player;
            print_board(board, LEN, LEN);
        }
        //电脑玩家
        else{
            computer_move(board, Player);
            print_board(board, LEN, LEN);
        }
        //判断胜负
        if (is_winner(board, Player)){
            printf("恭喜玩家%c获得胜利!", Player);
            break;
        }
        //判断棋盘是否已满
        for (int i=0; i<LEN; i++){
            for (int j=0; j<LEN; j++){
                if (board[i][j] != ' ') counts++;
            }
        }
        if (counts == LEN * LEN){
            printf("棋盘已满,未分出胜负,该局和棋!");
            break;
        }
        //切换玩家
        Player = (Player == 'X')? '0':'X';
    }
}

int main()
{
    int game_mode;
    char board[LEN][LEN];

    do{
        //菜单
        meun();
        //选择模式
        printf("请选择游戏模式: ");
        scanf("%d", &game_mode);

        switch(game_mode){
            case 0:
                printf("\n游戏结束!");
                break;
            case 1:
            case 2:
                game(board, game_mode);
                break;
            default:
                printf("输入有误,请重新输入!");
        }

    }while(game_mode);


    return 0;
}

游戏函数 game.c

#include "game.h"

//菜单
void meun()
{
    printf("\n----------------------五子棋-------------------\n");
    printf("|       游戏模式         |       游戏介绍     |\n");
    printf("|      0.退出游戏        |                    |\n");
    printf("|      1.人机模式        |    ‘X' —— 红色     |\n");
    printf("|      2.双人对战        |    '0' —— 蓝色     |\n");
    printf("-----------------------------------------------\n");

}
//初始化棋盘
void initialize_board(char board[LEN][LEN], int row, int col)
{
    for(int i=0; i<row; i++)
        for(int j=0; j<col; j++)
            board[i][j] = ' ';
}
//打印棋盘
void print_board(char board[LEN][LEN], int row, int col)
{
    int i, j;
    printf("\n");
    for (i=0; i<=row; i++) printf("%2d ", i);
    printf("\n");
    for (i=0; i<row; i++) {
        printf("%2d ", i+1);
        for (j=0; j<col; j++){
            if (board[i][j] == 'X') printf("\033[31m[X]\033[0m");
            else if (board[i][j] == '0') printf("\033[34m[0]\033[0m");
            else printf("[ ]");
        }
    printf("\n");
    }
}
//判断移动是否有效
int is_valid_move(int row, int col)
{
    return (row>=1 && row<=LEN && col>=1 && col<=LEN);
}

int is_winner(char board[LEN][LEN], char Player)
{
    int i, j;
    //横 —
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i][j+1]==Player && board[i][j+2]==Player && board[i][j+3]==Player && board[i][j+4]==Player)
                return 1;
        }
    }
    //竖 |
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i+1][j]==Player && board[i+2][j]==Player && board[i+3][j]==Player && board[i+4][j]==Player)
                return 1;
        }
    }
    //左斜
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i+1][j+1]==Player && board[i+2][j+2]==Player && board[i+3][j+3]==Player && board[i+4][j+4]==Player)
                return 1;
        }
    }
    //右斜
    for (i=0; i<LEN; i++){
        for (j=0; j<LEN-4; j++){
            if (board[i][j]==Player && board[i-1][j-1]==Player && board[i-2][j-2]==Player && board[i-3][j-3]==Player && board[i-4][j-4]==Player)
                  return 1;
        }
    }
    return 0;
}
//电脑玩家下棋
void computer_move(char board[LEN][LEN], char Player){
    while(1){
        int row,col;
        //随机生成0-14数字
        row = rand()%LEN;
        col = rand()%LEN;
        if (board[row][col] != ' ') continue;
        else{
            board[row][col] = Player;
            printf("\n 电脑玩家(%c)下在:(%d,%d)", Player, row+1, col+1);
            break;
        }
    }
}

知识补充

在C语言中,printf(“\033[31m[0]\033[0m”); 这行代码的作用是输出带有颜色的文本。

这里使用了ANSI转义序列(ANSI escape codes)来控制文本的颜色。具体来说:

  • \033[:这是一个特殊的字符序列,表示接下来的字符是ANSI转义序列的开始
  • 31m:这个序列表示将文本颜色设置为红色(31是ANSI颜色代码中红色的代号)。
  • [0]:这是要输出的文本内容。
  • \033[0m:这个序列表示重置文本颜色为默认颜色(0是ANSI颜色代码中重置颜色的代号)。

所以,printf(“\033[31m[0]\033[0m”); 会在终端中输出红色的"[0]"文本,然后将其颜色重置为默认颜色。请注意,这种颜色输出在支持ANSI转义序列的终端和环境中有效,例如Linux或macOS的终端以及某些Windows命令提示符环境。在不支持ANSI转义序列的环境中,这段代码可能不会有任何效果或者显示奇怪的字符。

运行截图

以下是部分截图,大家可以自己运行试试哦!
在这里插入图片描述

在这里插入图片描述

;