超详细的三子棋讲解来了

简介: 今天我给大家分享的是在C语言学习过程中一个很有意思的部分,那就是三子棋的实现,我想大家学习到这里的时候应该对C语言更加的有兴趣了吧。那么接下来我讲给大家讲解如何实现这一过程。

整体思路


在开始之前我们需要创建三个文件:


test.c  --- 用来构建三子棋实现的整体逻辑


game.h  ---  用来存放函数所需要的头文件和声明


game.c  --- 存放函数的主体


我们可以现实中我们见过的三子棋来思考怎样实现我们自己的三子棋。首先我们得有一个开始结束的菜单,在确定了要开始三子棋的时候,就先得展示我们的空棋盘,然后就是双方下棋,每个人下完棋后都得判断输赢,最后如果棋盘满了但还是没能分出输赢的话,那就是平局。所以这里就少不了循环的使用。


我们知道了三子棋的整体思路后就可以想想代码应该怎么写了。接下来我将带领大家一步步niji


菜单

void menu()
{
  printf("*************************************\n");
  printf("**********    1.play  ***************\n");
  printf("**********    0.exit  ***************\n");
  printf("*************************************\n");
}    //选择1开始游戏,选择0退出游戏,选择其他的提示选择错误并重新输入
int main()
{
  int input = 0;
  do
  {
    menu();
    printf("请输入;>\n");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();   //这里是游戏的主体
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

接下来当你选择了1开始游戏的时候就得去实现game()函数了,而这就是整个程序的核心


实现程序核心——game()


棋盘本质上就相当于一个二维数组,所以我们需要创建一个二维数组,并添加适当细节,将棋盘给展示出来。


打印棋盘格

char board[ROW][COL] = {0};   //ROW和COL通过宏来实现对棋盘的修改,方便随时更改
void InitBoard(char board[ROW][COL],int row,int col)  
//初始化棋盘,将棋盘中放置空格,这里row和col用小写来防止与我们的宏混淆
{
    //这里通过遍历来实现
    int i = 0;
    for(i=0;i<row;i++)
    {
        int j = 0;
        for(j=0;j<col;j++)
        {
            board[i][j] = ' ';
        }
    }
}
void PrintBoard(char board[ROW][COL],int row,int col) //通过添加线段来打印棋盘格
{
    int i = 0;
    for(i=0;i<row;i++)
    {
        int j = 0;
        for(j=0;j<col;j++)
        {
            printf(" %c ",board[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");    
        }
    }
}

棋盘打印出来是这样的

22.png

玩家下棋

void PlayerMove(char board[ROW][COL], int row, int col)
{
  printf("请输入坐标:>\n");
  int x = 0;
  int y = 0;
  again:
  scanf("%d %d", &x, &y); 
//这里因为玩家并不一定都是程序员所以不知道行和列是从0开始的,所以在后面x,y的值都需要减去1 
  if (x <= ROW && y <= COL)
  {
    if (board[x - 1][y - 1] == ' ')  //判断该位置是否被占用
    {
      board[x - 1][y - 1] = '#';    //用#来表示玩家的棋子
    }
  }
  else   //判断坐标的合法性
  {
    printf("坐标非法,请重新输入:>\n");
    goto again;
  }
}

判断输赢


这里需要判断玩家或者电脑是否赢了,三子棋赢得标志是一行或者一列或者对角线是否都是玩家或电脑的棋子,如果都没有赢就还需要判断是否是棋盘满了平局还是继续游戏。

char IsFull(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == ' ')
      {
        return 0;
      }
    }
  }
  return 1;
}
//判断输赢
//玩家赢 - ‘#’
//电脑赢 - ‘*’
//平局   - ‘Q’
//继续   - ‘C’
char IsWin(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][2] != ' ')
  {
    return board[0][2];
  }
//判断是否平局
  if(IsFull(board, ROW, COL))  //IsFull返回1表示平局,返回0则不是
  {
    return 'Q';
  }
  return 'C';
}

玩家下完棋后就是电脑下棋,电脑下棋就需要随机生成坐标,


这里就需要sran((unsigned int)time(NULL)函数和rand()函数了,而使用这两个函数还需要包含头文件#include<stdlib.h>和#include<time.h>,而为了使rand产生的坐标更加随机我们就在主函数中使用srand()函数


电脑下棋

void ComputerMove(char board[ROW][COL], int row, int col)
{
  printf("电脑下棋\n");
  int x = 0;
  int y = 0;
  x = rand() % row;
  y = rand() % col;
  if (board[x][y] == ' ')
  {
    board[x][y] = '*';
  }
}

然后就也是判断输赢,将上面的判断输赢函数再使用一次就行了。


总结


这里是game.h里面的内容

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//声明
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void PrintBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
char IsFull(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row,int col);

game.c里面的内容

#include"game.h"
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      board[i][j] = ' ';
    }
  }
}
void PrintBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      printf(" %c ", board[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 board[ROW][COL], int row, int col)
{
  printf("请输入坐标:>\n");
  int x = 0;
  int y = 0;
  again:
  scanf("%d %d", &x, &y);
  if (x <= ROW && y <= COL)
  {
    if (board[x - 1][y - 1] == ' ')
    {
      board[x - 1][y - 1] = '#';
    }
  }
  else
  {
    printf("坐标非法,请重新输入:>\n");
    goto again;
  }
}
char IsFull(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == ' ')
      {
        return 0;
      }
    }
  }
  return 1;
}
//判断输赢
//玩家赢 - ‘#’
//电脑赢 - ‘*’
//平局   - ‘Q’
//继续   - ‘C’
char IsWin(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][2] != ' ')
  {
    return board[0][2];
  }
  //判断是否平局
  if(IsFull(board, ROW, COL))
  {
    return 'Q';
  }
  return 'C';
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
  printf("电脑下棋\n");
  int x = 0;
  int y = 0;
  x = rand() % row;
  y = rand() % col;
  if (board[x][y] == ' ')
  {
    board[x][y] = '*';
  }
}

test.c里面的内容

#include"game.h"
void menu()
{
  printf("*************************************\n");
  printf("**********    1.play  ***************\n");
  printf("**********    0.exit  ***************\n");
  printf("*************************************\n");
}
void game()
{
  char board[ROW][COL] = { 0 };
  //初始化棋盘
  InitBoard(board,ROW,COL);
  //打印棋盘
  PrintBoard(board, ROW, COL);
  char ret = 0;
  while (1)
  {
    //玩家下棋
    PlayerMove(board, ROW, COL);
    PrintBoard(board, ROW, COL);
    //判断输赢
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    //电脑下棋
    ComputerMove(board, ROW, COL);
    PrintBoard(board, ROW, COL);
    ret = IsWin(board, ROW, COL);
    if(ret != 'C')
    {
      break;
    }
  }
  if (ret == '#')
  {
    printf("玩家赢\n");
  }
  else if (ret == '*')
  {
    printf("电脑赢\n");
  }
  else if(ret == 'Q')
  {
    printf("平局\n");
  }
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu();
    printf("请输入;>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入错误请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

游戏实现


23.png


到这里就是三子棋的全部内容了,感谢大家的观看,后续也会更新更多相关内容,点赞关注不迷路。

相关文章
|
开发工具 git
git checkout (branchname
git checkout (branchname) 是 Git 中切换分支的一种命令。通过这个命令,你可以将当前工作目录切换到指定的分支上。branchname 参数是可选的,如果不指定,则默认切换到主分支(master 或 main)。
329 2
|
关系型数据库 MySQL 分布式数据库
使用Sqoop从Mysql向云HBase同步数据
Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具。本文介绍如何使用sqoop将数据从Mysql导入到HBase。从成本的角度考虑,针对没有hadoop集群的用户,重点介绍单机运行sqoop的配置和参数。
5974 0
|
8月前
|
存储 Java 编译器
课时60:子类对象实例化流程
摘要: 1.子类对象实例化要求 2.范例1:默认情况下的子类实例化 3.范例2:修改子类,显式使用 super() 4.范例3:父类仅提供有参构造方法,不使用无参构造 5.范例4:其他父类构造
161 6
|
Arthas Java 测试技术
JVM —— 类加载器的分类,双亲委派机制
类加载器的分类,双亲委派机制:启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器;JDK8及之前的版本,JDK9之后的版本;什么是双亲委派模型,双亲委派模型的作用,如何打破双亲委派机制
JVM —— 类加载器的分类,双亲委派机制
|
前端开发 JavaScript 项目管理
Poetry vs npm:两个包管理器的迷人相似性
我们知道 Python 有自己的生态链。Python 版本也非常多,为了处理这么多的版本造成的包问题,Python 有了虚拟环境。在开始之前本文默认对 Python 的生态有了基础的了解(pip 等等)。 本文全面介绍了 Python 包管理项目管理,虚拟环境管理工具的 Poetry 的基本用法。对比不同的编程语言对包的管理其实都是相似的,Peotry 的与 npm 极为相似,你掌握其中一个另一个基本也熟悉了。
|
消息中间件 监控 Cloud Native
如何在 FlowUs、Notion 等笔记软件中使用思维导图?
如何将笔记软件和思维导图进行整合?
1165 0
|
SQL 缓存 Oracle
Kettle性能调优汇总
Kettle性能调优汇总
|
安全 算法 大数据
对称加密加密原理和开发场景解析
加密是自古以来人们都在不断使用的技术,目的是为了隐藏信息,只是随着时代在不断的变化,加密也在不断的更新。从古代的藏宝图对藏宝地点进行隐藏。到二战时候,破译敌方电台,都是属于加密和破解的过程。进入21世纪后,加密在互联网时代也有了新的加密方法。也创造了密码学这个学科。目前在加密的场景下,通常分为:可逆加密和不可逆加密。而在可逆加密场景里又分为:对称加密和非对称加密。本次主要讨论集中在可逆加密上。可逆加密顾名思义就是在对明文进行加密后生成密文,能够通过解密把密文再还原成明文。数据加密一般主要解决三个问题:可信问题(非对称加密可解决),防篡改问题(不可逆加密解决),防窃听问题...
697 0
|
数据处理
「连接平台」钉钉与电商ERP系统打通,流程超自动化助力业务起飞
数环通基于连接平台iPass能力完成了与钉钉的深度融合,打通了电商平台与企业ERP系统之间的数据桥梁,应用通过连接平台的数据处理和字段匹配做串联,实现数据线上线下自动同步与集成,提高企业运营管理效率和准确性,为企业数字化赋能升级。
1771 0