C语言——三子棋游戏的设计与实现

先介绍游戏的整体实现逻辑:在一个3*3大小的棋盘内使用两种不同的棋子下棋,这两种棋子分别为#和*,先把相同的棋子连成三个的一方获胜,否则平局。

两种游戏模式:玩家1vs电脑 玩家1vs玩家2

这里先展示一下最终要实现的下棋功能:

玩家1vs电脑

玩家1vs玩家2

以下使用VS2013制作

基本框架——三个文件

test.c === 存放主函数,游戏整体逻辑实现

game.c === 函数功能的实现

game.h === 头文件,存放函数声明

game.h

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 3//声明棋盘中的行
#define COL 3//声明棋盘中的列
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//函数的声明
void InitBoard(char board[ROW][COL], int row, int col);//初始化函数的声明
void DisplayBoard(char board[ROW][COL], int row, int col);//显示棋盘函数的声明

void PlayeroneMove(char board[ROW][COL], int row,int col);//玩家一下棋函数声明
void PlayertwoMove(char board[ROW][COL], int row, int col);//玩家二下棋函数声明

void AiMove(char board[ROW][COL], int row, int col);//电脑下棋函数声明
//建立一个IsWin函数,通过返回的字符判断游戏进程
char IsWin(char board[ROW][COL],int row,int col);//判断输赢函数声明

test.c

包含的函数介绍如下:

menu()——菜单

oneplayer()——玩家1VS电脑

twoplayer()——玩家1VS玩家2

test()——游戏整体框架

如下,

//测试游戏的程序
#include "game.h"
#include <windows.h>
void menu()//菜单函数,定义菜单
{
    printf("\n");
    printf("***** 1. 1player *****\n");
    printf("***** 2. 2player *****\n");
    printf("***** 0.  exit   *****\n");

}

void oneplayer()//游戏函数,内容为玩家1VS电脑,定义游戏整体逻辑
{
    //建立数组存放棋盘的信息
    char board[ROW][COL] = {0};
    char win = 0;//定义一个数来判断游戏进程
   //初始化棋盘
    InitBoard(board,ROW,COL);
    //显示棋盘
    DisplayBoard(board,ROW,COL);  
          
    while (1)//没有分出游戏结果就继续下棋,游戏分出结果跳出循环
    {
        //玩家走
        PlayeroneMove(board, ROW, COL);
        DisplayBoard(board, ROW, COL);//当有一方落子,打印一次棋盘
        //当有一方走完一步,需要判断一下是否有一方胜出
        win = IsWin(board, ROW, COL);//用win来接收IsWin返回的值
        if (win != 'c')//当win是'c'时,表示游戏没有结束,继续下棋,当win是其他值时,跳出循环
        {
            break;
        }
        //电脑走
        Sleep(1000);//延迟电脑下棋的速度,单位ms
        AiMove(board, ROW, COL);
        DisplayBoard(board, ROW, COL);//当有一方落子,打印一次棋盘
        win =IsWin(board, ROW, COL);//用win来接收IsWin返回的值
        if (win != 'c')//当win是'c'时,表示游戏没有结束,继续下棋,当win是其他值时,跳出循环
        {
            break;
        }
    }
    
    if (win == '*')
    {
        printf("玩家获得胜利\n");
    }
    else if (win == '#')
    {
        printf("电脑获得胜利\n");
    }
    else
    {
        printf("平局\n");
    }

}

void twoplayer()//游戏函数,玩家与玩家之间的对局实现,定义玩家对战的整体逻辑
{
    //建立数组存放棋盘的信息
    char board[ROW][COL] = { 0 };
    char win = 0;//定义一个数来判断游戏进程
    //初始化棋盘
    InitBoard(board, ROW, COL);
    //显示棋盘
    DisplayBoard(board, ROW, COL);//将需要打印的数组以及行,列数传参
            
    while (1)//没有分出游戏结果就继续下棋,游戏分出结果跳出循环
    {
        //玩家走
        PlayeroneMove(board, ROW, COL);
        DisplayBoard(board, ROW, COL);//当有一方落子,打印一次棋盘
        //当有一方走完一步,需要判断一下是否有一方胜出
        win = IsWin(board, ROW, COL);//用win来接收IsWin返回的值
        if (win != 'c')//当win是'c'时,表示游戏没有结束,继续下棋,当win是其他值时,跳出循环
        {
            break;
        }
        //电脑走
        PlayertwoMove(board, ROW, COL);
        DisplayBoard(board, ROW, COL);//当有一方落子,打印一次棋盘
        win = IsWin(board, ROW, COL);//用win来接收IsWin返回的值
        if (win != 'c')//当win是'c'时,表示游戏没有结束,继续下棋,当win是其他值时,跳出循环
        {
            break;
        }
    }

    if (win == '*')
    {
        printf("玩家1获得胜利\n");
    }
    else if (win == '#')
    {
        printf("玩家2获得胜利\n");
    }
    else
    {
        printf("平局\n");
    }

}

void test()//游戏整体框架
{
    int input = 0;
    srand((unsigned int)time(NULL));//提供一个随机数起点,作用于game.c的rand()函数
    do{
        menu();//提供菜单选择
        printf("请选择:");
        scanf("%d", &input);
        switch (input)
        {
            case 1:
                oneplayer();//单人与电脑进行游戏
                break;
            case 2:
                twoplayer();//玩家之间进行游戏
                break;
            case 0:
                printf("退出游戏\n");
                break;
            default :
                printf("你的输入有误,请输入1或0\n");
                break;
        }
    } while (input != 0);
}

int main()
{
    test();
    return 0;
}

game.c

存放游戏的功能函数,如何实现棋盘的打印是该游戏设计的一个难点

打印棋盘,将棋盘的整体分为三个组,分组打印,一个组又分成内容组分割线组(最后一行假设有分割线)这里先说明棋盘的整体划分方式,具体实现在game.c里面


  % | % | %   1-1
 ---|---|---  1-2
  % | % | %   2-1
 ---|---|---  2-2
  % | % | %   3-1
              3-2

下面是game.c的整体实现

#include "game.h"
//函数的定义
//游戏的内容设计
void InitBoard(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++)
        {
            board[i][j] = ' ';
        }
    }

}

void DisplayBoard(char board[ROW][COL], int row, int col)//显示棋盘函数,打印棋盘
{
    //分组打印
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)//打印第i组
    {
        for (j = 0; j < col; j++)//打印i-1组
        {
            printf(" %c ", board[i][j]);//打印落棋处
            if (j < col - 1)//筛选,当j到达最后一列时(3-1=2,而[2]是数组中最后的一个元素),跳过打印|
            {
                printf("|");//打印分隔
            }
        }
        printf("\n");
        for (j = 0; j < row; j++)//打印i-2组
        {
            //建立双重筛选,先判断i是否达到最后一行,再判断j是否到最后一列
            if (i < row - 1)//筛选,当i到达最后一行时,跳过打印---
            {
                printf("---");//打印分隔
                if (j < col - 1)//筛选,当j到达最后一列时,跳过打印|
                {
                    printf("|");//打印分隔
                }
            }
        }

        printf("\n");
    }
}

void PlayeroneMove(char board[ROW][COL], int row, int col)//玩家落棋函数
{
    int x = 0;
    int y = 0;

    while (1)
    {
        printf("玩家1请输入落棋坐标:");
        scanf("%d%d", &x, &y);
        if (x>0 && x <= row  && y>0 && y <= col)//保证落棋范围在棋盘内
        {
            if (board[x - 1][y - 1] == ' ')//x和y是正常玩家认知中的位置坐标,而x-1和y-1是其对应的下标位置,保证落棋处没有棋子
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else
            {
                printf("该坐标已有棋子,请重新输入\n");
            }
        }
        else
        {
            printf("你输入的坐标有误,请重新输入\n");
        }
    }
    printf("玩家1走\n");
}

void PlayertwoMove(char board[ROW][COL], int row, int col)//玩家落棋函数
{
    int x = 0;
    int y = 0;

    while (1)
    {
        printf("玩家2请输入落棋坐标:");
        scanf("%d%d", &x, &y);
        if (x>0 && x <= row  && y>0 && y <= col)//保证落棋范围在棋盘内
        {
            if (board[x - 1][y - 1] == ' ')//x和y是正常玩家认知中的位置坐标,而x-1和y-1是其对应的下标位置,保证落棋处没有棋子
            {
                board[x - 1][y - 1] = '#';
                break;
            }
            else
            {
                printf("该坐标已有棋子,请重新输入\n");
            }
        }
        else
        {
            printf("你输入的坐标有误,请重新输入\n");
        }
    }
    printf("玩家2走\n");
}

void AiMove(char board[ROW][COL], int row, int col)//电脑落棋函数,配合rand()实现电脑随机下棋
{
    int x = 0;
    int y = 0;
    printf("电脑走\n");
    while (1)//因为要排除落棋处有棋子的情况,所以这里建立一个循环,当落棋处已有棋子,将重新生成新的x,y坐标
    {
        x = rand() % row;//rand函数最大值为0-rand_max,这里要把数的范围定在0-2,所以模以row(3)
        y = rand() % col;//因此生成的随机坐标不会产生非法坐标,这样就不用判断电脑坐标会不会超出范围了
        //因为是电脑下棋,所以不用再考虑一般玩家不懂数组下标从0开始的情况
        //所以这里不用再运用x-1和y-1的下标,同时上面定好了x和y的随机值保持在0-2的下标范围,保证落棋不超出棋盘范围
        if (board[x][y] == ' ')//落棋处没有棋子
        {
            board[x][y] = '#';
            break;
        }
    }
}
//建立IsFull函数判断棋盘是否已经下满了,如果满了返回1,如果没满返回0
int IsFull(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;
}

char IsWin(char board[ROW][COL], int row, int col)//判断胜负函数,可用于落棋后判断局势
{
    //判断有四种游戏情况,1.玩家赢 2.电脑赢 3.平局 4.未分胜负继续对局
    //赢又有三种情况,一种是横三行同子,一种是竖三行同子,一种是对角线同子
    //对于这几种情况,我们让赢的一方返回它本身的值,平局返回'p',未分胜负返回'c'
    int i = 0;
    //横三行
    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];

    if (IsFull(board,row,col) == 1)//当IsFull函数=1的时候,表示棋盘已经下满了
    {
        return 'p';
    }
    return 'c';//上述情况都没有发生,返回'c'
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值