三子棋C语言小游戏功能完善

本文详细介绍了使用C语言开发井字棋游戏的过程,包括玩家走、电脑走、判断输赢等核心功能,并优化了电脑下棋算法,使其更具挑战性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录:

在前面的博客中已经对游戏的整体框架做出了分析,在这片博客中将会对整个游戏进行功能的完善的改进。
初始化和打印棋盘的功能已经在前面给出,现在还需要实现的功能便是玩家走、电脑走、和判断输赢的函数。

玩家走:PlayerMove()

在这个函数中通过数组下标确定一个二维数组中的位置,只要该位置没有放入“棋子”,便把该数组空间赋值为'X',所以确定该函数的返回值为void,需要将对数组通过循环遍历的临界值ROW COL传过去。所以函数的功能实现如下:

void PlayerMove(char arr[ROW][COL], int row, int col)
{
    int r = 0;
    int c = 0;
    while (1)
    {
        printf("玩家走:>\n");
        scanf("%d%d", &r, &c);
        if (r>=1 && r<=row && c>=1 && c<=col)
        {
            if (arr[r-1][c-1] == ' ')
            {
                arr[r-1][c-1] = 'X';
                break;
            }
            else
            {
                printf("已选择过!请重新输入\n");         
            }
        }
        else
        {
            printf("输入有误!请重新输入\n");
        }
    }
}

电脑走:ComputerMove()

与电脑走的函数方法类似,不同的是电脑随机生成一个坐标,如果该座标没有放入“棋子”,便将该数组空间赋值为'0',返回值同样为void同样需要把ROW COL传过去。

void ComputerMove(char arr[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    printf("电脑走:>\n");
    while (1)
    {
        i = rand()%row;
        j = rand()%col;
        if (arr[i][j] == ' ')
        {
            arr[i][j] = '0';
            break;
        }
    }
}

rand()函数在调用之前,必须先调用srand()生成随机数起点,因起点生成后不许再变,所以将其放入main()中之调用一次即可。

判断输赢 IsWin()

判断输赢要分四种情况讨论,玩家赢、电脑赢、平局、以上三种情况均不是,比赛继续。

  • 玩家赢、电脑赢、都可以通过循环遍历数组,通过if语句判断棋盘的状态来完成。
  • 如果发现棋盘已满,而胜负未定则为平局。

  • 以上情况均不是则继续游戏。

如何实现这个逻辑,可以通过返回值来判断:当玩家赢返回X,电脑赢返回0,平局返回空字符,如果继续不做处理。

char IsWin(char arr[ROW][COL], int row, int col)
{
    int i = 0;

    for (i=0; i<row; i++)
    {
        //判断是否同行
        if (arr[i][0]==arr[i][1] && arr[i][1]==arr[i][2] && arr[i][1] != ' ')
        {
            return arr[i][1];
        }
        //列
        else if (arr[0][i]==arr[1][i] && arr[1][i]==arr[2][i] && arr[1][i] != ' ')
        {
            return arr[1][i];
        }
        //斜
        else if ((arr[0][0]==arr[1][1] && arr[1][1]==arr[2][2] && arr[1][1] != ' ')
            ||(arr[0][2]==arr[1][1] && arr[1][1]==arr[2][0] && arr[1][1] != ' '))
        {
            return arr[1][1];
        }
        else
        {
            ;
        }
    }

    if (IsFull(arr,ROW,COL))
    {
        return ' ';
    }
}
//判断棋满
static int IsFull(char arr[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 (arr[i][j] == ' ')
            {
                return 0;
            }
        }
    }
    return 1;
}

IsFull()将返回值设置成1/0可以很好的在调用的if语句中能够做出判断,前面加上static是为这个函数不需要在其他地方调用,只用于本源码,避免命名冲突。

电脑下棋算法优化

标题很高大上,其实实现方法很挫,说白了就是对棋盘当前状态的一种判断,与判断输赢的逻辑方法完全一样,根据判断的结果,电脑给出当下的最优选择。就是将很多种状态提前告知电脑,然后判断符合状态后,接下来的走法也人为规定好了。这就跟现在的电脑下象棋,围棋是一个道理,就是检索内存中的当前棋盘已有最优方案。
整体的逻辑如下:先判断是否抢3,如果有符合当前电脑能赢的方案,则优先抢其。
接着选择是否堵3,如果玩家出现再落一子就赢的情况,要对其进行封堵。
最后一点,在下棋的过程中,由于棋盘限制,中间位置尤为重要,占据它,将占据主动权,如果为空,则选其。

void ComputerMove(char arr[ROW][COL], int row, int col)
{
    int m = 0;
    int i = 0;
    int j = 0;
    printf("电脑走:>\n");
    //抢3
    //抢行
    for (m=0; m<ROW; m++)
    {
        if (arr[m][0]=='0' && arr[m][1]=='0' && arr[m][2]==' ')
        {
            arr[m][2] = '0';
            goto exit;
        }
        if (arr[m][0]=='0' && arr[m][2]=='0' && arr[m][1]==' ')
        {
            arr[m][1] = '0';
            goto exit;
        }
        if (arr[m][1]=='0' && arr[m][2]=='0' && arr[m][0]==' ')
        {
            arr[m][0] = '0';
            goto exit;
        }
    }
    //抢列
    for (m=0; m<COL; m++)
    {
        if (arr[0][m]=='0' && arr[1][m]=='0' && arr[2][m]==' ')
        {
            arr[2][m] = '0';
            goto exit;
        }
        if (arr[0][m]=='0' && arr[2][m]=='0' && arr[1][m]==' ')
        {
            arr[1][m] = '0';
            goto exit;
        }
        if (arr[1][m]=='0' && arr[2][m]=='0' && arr[0][m]==' ')
        {
            arr[0][m] = '0';
            goto exit;
        }
    }
    //抢斜行
    //情况一:斜率为-1的斜行
    if (arr[0][0]=='0' && arr[1][1]=='0' && arr[2][2]==' ')
    {
        arr[2][2] = '0';
        goto exit;
    }
    if (arr[0][0]=='0' && arr[2][2]=='0' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='0' && arr[2][2]=='0' && arr[0][0]==' ')
    {
        arr[0][0] = '0';
        goto exit;
    }
    //情况二:斜率为1的斜行
    if (arr[2][0]=='0' && arr[1][1]=='0' && arr[0][2]==' ')
    {
        arr[0][2] = '0';
        goto exit;
    }
    if (arr[2][0]=='0' && arr[0][2]=='0' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='0' && arr[0][2]=='0' && arr[2][0]==' ')
    {
        arr[2][0] = '0';
        goto exit;
    }

    //堵
    //堵行
    for (m=0; m<ROW; m++)
    {
        if (arr[m][0]=='X' && arr[m][1]=='X' && arr[m][2]==' ')
        {
            arr[m][2] = '0';
            goto exit;
        }
        if (arr[m][0]=='X' && arr[m][2]=='X' && arr[m][1]==' ')
        {
            arr[m][1] = '0';
            goto exit;
        }
        if (arr[m][1]=='X' && arr[m][2]=='X' && arr[m][0]==' ')
        {
            arr[m][0] = '0';
            goto exit;
        }
    }
    //堵列
    for (m=0; m<COL; m++)
    {
        if (arr[0][m]=='X' && arr[1][m]=='X' && arr[2][m]==' ')
        {
            arr[2][m] = '0';
            goto exit;
        }
        if (arr[0][m]=='X' && arr[2][m]=='X' && arr[1][m]==' ')
        {
            arr[1][m] = '0';
            goto exit;
        }
        if (arr[1][m]=='X' && arr[2][m]=='X' && arr[0][m]==' ')
        {
            arr[0][m] = '0';
            goto exit;
        }
    }
    //堵斜行
    //情况一:斜率为-1的斜行
    if (arr[0][0]=='X' && arr[1][1]=='X' && arr[2][2]==' ')
    {
        arr[2][2] = '0';
        goto exit;
    }
    if (arr[0][0]=='X' && arr[2][2]=='X' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='X' && arr[2][2]=='X' && arr[0][0]==' ')
    {
        arr[0][0] = '0';
        goto exit;
    }
    //情况二:斜率为1的斜行
    if (arr[2][0]=='X' && arr[1][1]=='X' && arr[0][2]==' ')
    {
        arr[0][2] = '0';
        goto exit;
    }
    if (arr[2][0]=='X' && arr[0][2]=='X' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='X' && arr[0][2]=='X' && arr[2][0]==' ')
    {
        arr[2][0] = '0';
        goto exit;
    }

    //抢2
    if (arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }


    while (1)
    {
        i = rand()%row;
        j = rand()%col;
        if (arr[i][j] == ' ')
        {
            arr[i][j] = '0';
            break;
        }
    }
exit:;
}

由于前面做出选择后,后面将不再落子,前面未作处理,才来到后面。所以通过goto语句进行跳转,以实现其逻辑。

这样的不算优化的优化,也仅仅是让电脑不再继续傻下去。由于棋盘的限制,如果有可能,可以将其所有的棋盘状态进行穷举,而电脑每一步落子都是对自己最优,对玩家最不利的,这样人想赢就难了,因为人脑的逻辑分析能力和存储记忆能力是远不及计算机的。

礼让电脑

由于棋盘大小限制,和谁先走就有抢中间位置的决定权,如果感觉自己萌萌哒,可以让电脑先走~。~,变化只是game函数的调用顺序问题以及多一步switch语句的选择,将会在后面完整代码中体现。

完整代码展示

  • game.h
#ifndef __GAME_H__
#define __GAME_H__

#define ROW 3
#define COL 3

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

void PrintBoard(char arr[ROW][COL], int row, int col);//打印棋盘

void PlayerMove(char arr[ROW][COL], int row, int col);//玩家走

char IsWin(char arr[ROW][COL], int row, int col);//判断输赢

void ComputerMove(char arr[ROW][COL], int row, int col);//电脑走

#endif //__GAME_H__
  • game.c
#include <stdio.h>
#include <stdlib.h>
#include "game.h"

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

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

void PlayerMove(char arr[ROW][COL], int row, int col)
{
    int r = 0;
    int c = 0;
    while (1)
    {
        printf("玩家走:>\n");
        scanf("%d%d", &r, &c);
        if (r>=1 && r<=row && c>=1 && c<=col)
        {
            if (arr[r-1][c-1] == ' ')
            {
                arr[r-1][c-1] = 'X';
                break;
            }
            else
            {
                printf("已选择过!请重新输入\n");         
            }
        }
        else
        {
            printf("输入有误!请重新输入\n");
        }
    }
}

static int IsFull(char arr[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 (arr[i][j] == ' ')
            {
                return 0;
            }
        }
    }
    return 1;
}

char IsWin(char arr[ROW][COL], int row, int col)
{
    int i = 0;

    for (i=0; i<row; i++)
    {
        //判断是否同行
        if (arr[i][0]==arr[i][1] && arr[i][1]==arr[i][2] && arr[i][1] != ' ')
        {
            return arr[i][1];
        }
        //列
        else if (arr[0][i]==arr[1][i] && arr[1][i]==arr[2][i] && arr[1][i] != ' ')
        {
            return arr[1][i];
        }
        //斜
        else if ((arr[0][0]==arr[1][1] && arr[1][1]==arr[2][2] && arr[1][1] != ' ')
            ||(arr[0][2]==arr[1][1] && arr[1][1]==arr[2][0] && arr[1][1] != ' '))
        {
            return arr[1][1];
        }
        else
        {
            ;
        }
    }

    if (IsFull(arr,ROW,COL))
    {
        return ' ';
    }
}

void ComputerMove(char arr[ROW][COL], int row, int col)
{
    int m = 0;
    int i = 0;
    int j = 0;
    printf("电脑走:>\n");
    //抢3
    //抢行
    for (m=0; m<ROW; m++)
    {
        if (arr[m][0]=='0' && arr[m][1]=='0' && arr[m][2]==' ')
        {
            arr[m][2] = '0';
            goto exit;
        }
        if (arr[m][0]=='0' && arr[m][2]=='0' && arr[m][1]==' ')
        {
            arr[m][1] = '0';
            goto exit;
        }
        if (arr[m][1]=='0' && arr[m][2]=='0' && arr[m][0]==' ')
        {
            arr[m][0] = '0';
            goto exit;
        }
    }
    //抢列
    for (m=0; m<COL; m++)
    {
        if (arr[0][m]=='0' && arr[1][m]=='0' && arr[2][m]==' ')
        {
            arr[2][m] = '0';
            goto exit;
        }
        if (arr[0][m]=='0' && arr[2][m]=='0' && arr[1][m]==' ')
        {
            arr[1][m] = '0';
            goto exit;
        }
        if (arr[1][m]=='0' && arr[2][m]=='0' && arr[0][m]==' ')
        {
            arr[0][m] = '0';
            goto exit;
        }
    }
    //抢斜行
    //情况一:斜率为-1的斜行
    if (arr[0][0]=='0' && arr[1][1]=='0' && arr[2][2]==' ')
    {
        arr[2][2] = '0';
        goto exit;
    }
    if (arr[0][0]=='0' && arr[2][2]=='0' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='0' && arr[2][2]=='0' && arr[0][0]==' ')
    {
        arr[0][0] = '0';
        goto exit;
    }
    //情况二:斜率为1的斜行
    if (arr[2][0]=='0' && arr[1][1]=='0' && arr[0][2]==' ')
    {
        arr[0][2] = '0';
        goto exit;
    }
    if (arr[2][0]=='0' && arr[0][2]=='0' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='0' && arr[0][2]=='0' && arr[2][0]==' ')
    {
        arr[2][0] = '0';
        goto exit;
    }

    //堵
    //堵行
    for (m=0; m<ROW; m++)
    {
        if (arr[m][0]=='X' && arr[m][1]=='X' && arr[m][2]==' ')
        {
            arr[m][2] = '0';
            goto exit;
        }
        if (arr[m][0]=='X' && arr[m][2]=='X' && arr[m][1]==' ')
        {
            arr[m][1] = '0';
            goto exit;
        }
        if (arr[m][1]=='X' && arr[m][2]=='X' && arr[m][0]==' ')
        {
            arr[m][0] = '0';
            goto exit;
        }
    }
    //堵列
    for (m=0; m<COL; m++)
    {
        if (arr[0][m]=='X' && arr[1][m]=='X' && arr[2][m]==' ')
        {
            arr[2][m] = '0';
            goto exit;
        }
        if (arr[0][m]=='X' && arr[2][m]=='X' && arr[1][m]==' ')
        {
            arr[1][m] = '0';
            goto exit;
        }
        if (arr[1][m]=='X' && arr[2][m]=='X' && arr[0][m]==' ')
        {
            arr[0][m] = '0';
            goto exit;
        }
    }
    //堵斜行
    //情况一:斜率为-1的斜行
    if (arr[0][0]=='X' && arr[1][1]=='X' && arr[2][2]==' ')
    {
        arr[2][2] = '0';
        goto exit;
    }
    if (arr[0][0]=='X' && arr[2][2]=='X' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='X' && arr[2][2]=='X' && arr[0][0]==' ')
    {
        arr[0][0] = '0';
        goto exit;
    }
    //情况二:斜率为1的斜行
    if (arr[2][0]=='X' && arr[1][1]=='X' && arr[0][2]==' ')
    {
        arr[0][2] = '0';
        goto exit;
    }
    if (arr[2][0]=='X' && arr[0][2]=='X' && arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }
    if (arr[1][1]=='X' && arr[0][2]=='X' && arr[2][0]==' ')
    {
        arr[2][0] = '0';
        goto exit;
    }

    //抢2
    if (arr[1][1]==' ')
    {
        arr[1][1] = '0';
        goto exit;
    }


    while (1)
    {
        i = rand()%row;
        j = rand()%col;
        if (arr[i][j] == ' ')
        {
            arr[i][j] = '0';
            break;
        }
    }
exit:;
}
  • test.c
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "game.h"

void menu1()
{
    printf("****************************************\n");
    printf("*******           1.play         *******\n");
    printf("*******           0.exit         *******\n");
    printf("****************************************\n");
}
void menu2()
{
    printf("****************************************\n");
    printf("*******      1.player_first      *******\n");
    printf("*******     2.computer_first     *******\n");
    printf("****************************************\n");
}
void player_first_game()
{
    char arr[ROW][COL];
    InitBoard(arr,ROW,COL);
    PrintBoard(arr,ROW,COL);
    while (1)
    {
        PlayerMove(arr,ROW,COL);
        PrintBoard(arr,ROW,COL);
        //判断输赢,分为四种情况,如果不是以下三种情况游戏继续
        if (IsWin(arr,ROW,COL)==' ')
        {
            printf("很遗憾,平局!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='X')
        {
            printf("玩家赢!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='0')
        {
            printf("电脑赢!\n");
            break;
        }
        ComputerMove(arr,ROW,COL);
        PrintBoard(arr,ROW,COL);
        if (IsWin(arr,ROW,COL)==' ')
        {
            printf("很遗憾,平局!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='X')
        {
            printf("玩家赢!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='0')
        {
            printf("电脑赢!\n");
            break;
        }
    }
}
void computer_first_game()
{
    char arr[ROW][COL];
    InitBoard(arr,ROW,COL);
    while (1)
    {
        ComputerMove(arr,ROW,COL);
        PrintBoard(arr,ROW,COL);
        //判断输赢,分为四种情况,如果不是以下三种情况游戏继续
        if (IsWin(arr,ROW,COL)==' ')
        {
            printf("很遗憾,平局!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='X')
        {
            printf("玩家赢!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='0')
        {
            printf("电脑赢!\n");
            break;
        }
        PlayerMove(arr,ROW,COL);
        PrintBoard(arr,ROW,COL);
        if (IsWin(arr,ROW,COL)==' ')
        {
            printf("很遗憾,平局!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='X')
        {
            printf("玩家赢!\n");
            break;
        }
        if (IsWin(arr,ROW,COL)=='0')
        {
            printf("电脑赢!\n");
            break;
        }
    }
}
int main()
{
    int input1 = 0;
    int input2 = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu1();
        scanf("%d",&input1);
        switch(input1)
        {
        case 1:
//          game(此处可以添加更完整的游戏功能实现);
            menu2();
            printf("请选择谁先走:>\n");
            scanf("%d",&input2);
            switch(input2)
            {
            case 1:
                player_first_game();
                goto flag;
            case 2:
                computer_first_game();
            }
flag:;
            break;
        case 0:
            printf("游戏结束\n");
            return 0;
        default :
            printf("输入错误!请重新输入\n");
            break;
        }
    }while (input1);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值