[ C语言 ] C语言小游戏 ---- 三子棋 代码 + 解析

前言:

本篇文章记录了用C语言实现三子棋小游戏,主要目的是对之前C语言知识学习的巩固,联系各个知识,以及怎么样实际使用各个知识。

一、三子棋游戏规则

玩家使用一个3*3的网络棋盘,由玩家先下棋,电脑后下棋。

规定:先连成一条直线(3个棋子)的玩家获胜,行,列,对角线均可。若在棋盘下满时仍未分出胜负,则为平局

二、基本流程

  1. 菜单界面选择开始或者退出游戏

  1. 棋盘初始化

  1. 打印棋盘

  1. 玩家选择落子位置再次打印棋盘

  1. 电脑选择落子位置再次打印棋盘

  1. 每次下棋后判断输赢,和棋

三、具体步骤

使用到的头文件

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

定义3*3的棋盘

#define ROW 3
#define COL 3

初始化棋盘

void init_board(char board[ROW][COL], int row, int col);

打印棋盘

void display_board(char board[ROW][COL], int row, int col);

玩家下棋

void player_move(char board[ROW][COL], int row, int col);

电脑下棋

void computer_move(char board[ROW][COL], int row, int col);

判断输赢

//玩家赢  - '*'
//电脑赢  - '#'
//平局  -  'Q'
//继续  - 'C'
char is_win(char board[ROW][COL],int row,int col);

四、游戏测试

主函数

int main()
{
    srand((unsigned int)time(NULL));
    int input = 0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出游戏");
            break;
        default:
            printf("请重新选择");
            break;
        }
    } while (input);
}

解析main函数构成

i>菜单menu()函数

void menu()
{
    printf("***************************************\n");
    printf("***************************************\n");
    printf("************     1.play    ************\n");
    printf("************     0.exit    ************\n");
    printf("***************************************\n");
    printf("***************************************\n");
    printf("***************************************\n");
}

效果:

ii>switch case语句:实现了玩家通过不同输入选择实现不同的功能。

效果:

iii>game()函数:玩家输入1进入

void game()
{
    char board[ROW][COL] = { 0 };//定义一个棋盘
    init_board(board, ROW, COL);//初始化棋盘
    display_board(board, ROW, COL);//显示棋盘

    char ret = 0;

    while (1)
    {
    //玩家下棋
        player_move(board, ROW, COL);
    //显示棋盘
        display_board(board, ROW, COL);
    //判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    //电脑下棋
        computer_move(board, ROW, COL);
    //显示棋盘
        display_board(board, ROW, COL);
    //判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    }
    if (ret == '*')
        printf("玩家赢\n");
    else if (ret == '#')
        printf("电脑赢\n");
    else
        printf("平局\n");
}

game()函数里面包括了:打印棋盘函数,初始化棋盘函数,玩家下棋函数,电脑下棋函数,判断输赢函数的调用,已经规定输赢的条件,具体每个函数的实现代码和问题如下。

注:最后有game()函数的逻辑顺序。

五、游戏实现

(一)打印棋盘

我们首先实现对棋盘的打印:

我们在头文件中规定了 3行3列

#define ROW 3
#define COL 3 

自定义函数DisplayBoard实现对棋盘的打印:

void display_board(char board[ROW][COL], int row, int col)
{
    int i = 0;
        for (i = 0; i < row; i++)
        {
            /*printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
            if (i < row - 1)*/
            int j = 0;
            for (j = 0; j < col; j++)
            {
                printf(" %c ", board[i][j]);
                if (j < col - 1)
                    printf("|");
                 
            }
                /*printf("---|---|---\n");*/
            printf("\n");
            if (i < row - 1)
            {
                for (j = 0; j < col; j++)
                {
                    printf("---");
                    if (j < col - 1)
                        printf("|");

                }
            }
            printf("\n");
        }
}

(二)初始化棋盘函数

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

    }
}

初始化棋盘全为空格

(三)玩家下棋

void player_move(char board[ROW][COL], int row, int col)
{
    int x, y;
    printf("玩家下棋:>\n");
 
    while (1)
    {
        printf(" 请输入要下棋的坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else
            {
                printf("坐标被占用,重新输入\n");
            }
        }
        else
        {
            printf("坐标错误,请重新输入\n");
        }
    }
 
}

这里面包含了很多小问题和解决方案:

1:输入的坐标不在棋盘的范围内怎么办?

答:使用if else 选择语句,如果输入的坐标合法,则输入成功,如果输入的坐标不合法则会提醒“坐标非法,请重新输入!”字样。

if (x >= 1 && x <= row && y >= 1 && y <= col)

2:输入的坐标在棋盘上已被占用怎么办?

这个问题我们需要转化成这个问题解决:

i>怎么判断输入坐标被占用?

答:我们通过对选择语句if else 对改坐标进行判断,由于我们在初始化棋盘时,初始化棋盘全部为空格,如果输入坐标所对应的格子是空格,则说明未被占用,如果输入坐标所对应的格子不是空格,则说明该格子已经被占用。

if (board[x - 1][y - 1] == ' ')

ii>如何正确输入棋子?

如果输入坐标所对应的格子是空格,则可以成功输入,如果不是空格,则会else提醒玩家“该坐标被占用,请重新输入!”字样。利用while循环语句可再次输入正确的未被占用的坐标。

(四)电脑下棋

void computer_move(char board[ROW][COL], int row, int col)
{
    printf("电脑下棋:>\n");
    int x, y;

    while (1)
    {
        x = rand() % row;
        y = rand() % col;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
            
        }
        
    }
    
}

这里也包含了几个小问题和解决方案:

1:这里电脑的输入是随机输入,如何实现?

答:这里我们并非是真的随机值,只是利用了时间戳,由于时间在每时每刻的改变,所以在不同的时间,经过处理后的时间我们也无法知道,可当做随机值使用。这里调用了time函数,实现代码如下:

#include <time.h>
srand((unsigned int)time(NULL));
由于在这里强制转化为正整数。

2:如何控制电脑随机输入的值合法?

答:这个问题的意思是,如果不对这个随机值进行处理,那么这个值很可能超出棋盘,所以要对这个值进行控制,由于棋盘规定3行3列,数组下标由0开始,所以随机值只要在0~2之内即可。所以我们对这个随机值进行取模(取余数)处理即可解决此问题:

x = rand() % ROW; // 0 ~ 2
y = rand() % COL; // 0 ~ 2

为了区分玩家和电脑的棋子不同,在此规定

玩家使用 ' * ' , 电脑使用 ' # '

注:电脑输入坐标为随机值,并不具备判断的能力

(五)判断输赢

//判断输赢
//玩家赢 - ‘*’
//电脑赢 - ‘#'
//平局 -  ‘Q’
//继续 - ‘C’
char is_win(char board[ROW][COL], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
        {
            return board[i][0];
        }
    }
    for (i = 0; i < col; i++)
    {
        if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
        {
            return board[0][i];
        }
    }
    if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
    {
        return board[0][0];
    }
    if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][0] != ' ')
    {
        return board[0][2];
    }
    //判断是否平局
    if (is_full(board, row, col))
    {
        return 'Q';
    }
    //游戏继续
    return 'C';
}

三行的判断:

for (i = 0; i < row; i++) {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
            return board[i][1];
    }

三列的判断:

    for (i = 0; i < col; i++) {
        if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
            return board[1][i];
    }

两条对角线的判断:

//第一条对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ') {
        return board[1][1];
    }
 
//第二条对角线
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    {
        return board[1][1];
    }

平局的判断:

int is_full(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

代码逻辑:我们通过返回值来判断棋盘是否下满,

如果未被下满,则返回值是0(return 0 )

如果下满我们将返回1(return 1)

六、game()函数

void game()
{
    char board[ROW][COL] = { 0 };//定义一个棋盘
    init_board(board, ROW, COL);//初始化棋盘
    display_board(board, ROW, COL);//显示棋盘

    char ret = 0;

    while (1)
    {
    //玩家下棋
        player_move(board, ROW, COL);
    //显示棋盘
        display_board(board, ROW, COL);
    //判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    //电脑下棋
        computer_move(board, ROW, COL);
    //显示棋盘
        display_board(board, ROW, COL);
    //判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    }
    if (ret == '*')
        printf("玩家赢\n");
    else if (ret == '#')
        printf("电脑赢\n");
    else
        printf("平局\n");
}

完整代码:main.c部分

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"


void menu()
{
    printf("***************************************\n");
    printf("***************************************\n");
    printf("************     1.play    ************\n");
    printf("************     0.exit    ************\n");
    printf("***************************************\n");
    printf("***************************************\n");
    printf("***************************************\n");
}

void game()
{
    char board[ROW][COL] = { 0 };//定义一个棋盘
    init_board(board, ROW, COL);//初始化棋盘
    display_board(board, ROW, COL);//显示棋盘

    char ret = 0;

    while (1)
    {
    //玩家下棋
        player_move(board, ROW, COL);
    //显示棋盘
        display_board(board, ROW, COL);
    //判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    //电脑下棋
        computer_move(board, ROW, COL);
    //显示棋盘
        display_board(board, ROW, COL);
    //判断输赢
        ret = is_win(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    }
    if (ret == '*')
        printf("玩家赢\n");
    else if (ret == '#')
        printf("电脑赢\n");
    else
        printf("平局\n");
}

int main()
{
    srand((unsigned int)time(NULL));
    int input = 0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出游戏");
            break;
        default:
            printf("请重新选择");
            break;
        }
    } while (input);
}

game.c部分

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

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

    }
}

void display_board(char board[ROW][COL], int row, int col)
{
    int i = 0;
        for (i = 0; i < row; i++)
        {
            /*printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
            if (i < row - 1)*/
            int j = 0;
            for (j = 0; j < col; j++)
            {
                printf(" %c ", board[i][j]);
                if (j < col - 1)
                    printf("|");
                 
            }
                /*printf("---|---|---\n");*/
            printf("\n");
            if (i < row - 1)
            {
                for (j = 0; j < col; j++)
                {
                    printf("---");
                    if (j < col - 1)
                        printf("|");

                }
            }
            printf("\n");
        }
}

void player_move(char board[ROW][COL], int row, int col)
{
    int x, y;
    printf("玩家下棋:>\n");
 
    while (1)
    {
        printf(" 请输入要下棋的坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else
            {
                printf("坐标被占用,重新输入\n");
            }
        }
        else
        {
            printf("坐标错误,请重新输入\n");
        }
    }
 
}

void computer_move(char board[ROW][COL], int row, int col)
{
    printf("电脑下棋:>\n");
    int x, y;

    while (1)
    {
        x = rand() % row;
        y = rand() % col;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
            
        }
        
    }
    
}


int is_full(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

//判断输赢
//玩家赢 - ‘*’
//电脑赢 - ‘#'
//平局 -  ‘Q’
//继续 - ‘C’
char is_win(char board[ROW][COL], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
        {
            return board[i][0];
        }
    }
    for (i = 0; i < col; i++)
    {
        if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
        {
            return board[0][i];
        }
    }
    if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
    {
        return board[0][0];
    }
    if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][0] != ' ')
    {
        return board[0][2];
    }
    //判断是否平局
    if (is_full(board, row, col))
    {
        return 'Q';
    }
    //游戏继续
    return 'C';
}

game.h部分

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>


#define ROW 3
#define COL 3

void init_board(char board[ROW][COL], int row, int col);//棋盘初始化

void display_board(char board[ROW][COL], int row, int col);//棋盘显示

void player_move(char board[ROW][COL], int row, int col);//玩家下棋

void computer_move(char board[ROW][COL], int row, int col);//电脑下棋

char is_win(char board[ROW][COL], int row, int col);//判断输赢
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值