【C语言】民间传统游戏——三子棋详细教学

简介: 三子棋(介绍)游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。 🌞

三子棋(介绍)

游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。 🌞

实现效果


2c6d41c6f26b4a728829c02d84b99dd1.png

🧐首先开始执行程序,一张菜单,可以选择0或者1,0退出,1进入游戏

f949d90508d74d8186814feab0758d33.png

如果选择1的话,开始游戏,根据坐标填入数字,直到棋盘满了或者一方先连成一条线获胜为止。

代码实现

1.打印菜单

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

菜单必不可少,让用户进来了解怎么操作

2.main函数

int main()
{
    int input = 0;
    srand((unsigned)time(NULL));   //生成随机数用于人机自动落子
  do 
  {
    menu();    //do-while语句进来先打印菜单栏
    printf("请进行选择(0/1)\n");   //这里进行输入有一个小细节就是把退出设置为0,然后把输入数字放在dowhile()里面这样输入0就直接退出循环了
    scanf("%d", &input);   
    switch (input)       //switch语句进行选择,一目了然
    {
    case 1:
      game();  //进入游戏
      break;
    case 0:
      printf("成功退出");
      break;
    default: 
      printf("输入错误,请重新输入");
      break;
    }
  } while (input); //为0中止
}

由于进程序就有菜单弹出所以这里选择do。while语句,再用switch语句进行判断,当玩家输入1,进入游戏,当玩家输入0,退出程序


让我们想想进入游戏后都需要些什么(也就是game()函数都需要什么)❔

首先我们需要一张棋盘,棋盘本质上来说是一个3*3的空间,我们这里选择用二维数组来放下。

 

char board[ROW][COL] = { 0 };

3.初始化棋盘

  • 在刚进游戏的时候,棋盘上是空的,所以我们要把棋盘上所有位置都初始化成空格
void InitBoard(char board[ROW][COL],int row,int col) //形参的名字不能和define定义的相同,不然会报错
{
  for (int i = 0; i < row; i++)     //把棋盘初始化为空格
  {
    for(int j=0;j< col;j++)
    {
      board[i][j] =' ';
    }
  }
    //也可以使用库函数memset
    //memset(&board[0][0], ' ', row * col * sizeof(board[0][0]));
}

4.打印棋盘

  • 初始化棋盘之后我们就可以开始打印了
void printboard(char board[ROW][COL],int row,int col)//~用于打印棋盘
{
  for (int i = 0; i < row; i++)   
  {
    for (int j = 0; j < col; j++)      //打印一行
    {
      printf(" %c ", board[i][j]);   
      if (j<col - 1)    //打印col-1个|,做到  棋子|棋子|棋子
      {
        printf("|");
      }
    }
    printf("\n");
    if (i < row - 1)  //打印分割线---|---|---
    {
      for (int j = 0; j < col; j++)
      {
        printf("---");      
        if (j < COL - 1)
        {
          printf("|");
        }
      }
      printf("\n");
    }
  }
}

✨✨如果游戏开始只有棋子,那么玩家看到的是一片空,所以我们要打印一个棋盘出来,这里选择用ROW(行)和COL(列)来控制棋盘的长短,如果想打印更大的棋盘就只需改掉define定义的ROW和COL即可。


927950a1553445c6afc8f299c668daab.png

5.玩家落子

  • 打印完棋盘之后玩家进行落子
void playerMove(char board[ROW][COL], int row, int col)//~玩家下子
{
  printf("该你了,请选择坐标(?,?)\n");
  while (1)
  {
    int num1=0;       //玩家输入的行
    int num2=0;       //玩家输入的列
    scanf("%d,%d", &num1, &num2);
    if ((num1 > 3 || num1 < 0) || (num2 > 3 || num2 < 0)) //如果超出棋盘范围,结束本次循环重新选择
    {
      printf("请输入正确位置");
      continue;
    }
    if (board[num1-1][num2-1] == ' ') 
    {
      board[num1-1][num2-1] = '*';    //返回1 ,落子成功,跳出循环
      break;
    }
    else   
    {
      printf("请选择空位下子\n");     //返回0 落子失败,重新输入
    }
  }
}

✨✨轮到玩家输入,首先要给个提示,提示玩家落子,如果玩家输入的坐标不对的话,提示重新下子,如果玩家输入的坐标已经有棋子的话,提示重新下子。

6.人机落子

  • 玩家落子之后人机落子
void computerMove(char board[ROW][COL], int row, int col)//~电脑下子
{
  while(1)
  {
    int num1 = rand() % row;     //生成随机数并取模row,保证row范围在棋盘大小内
    int num2 = rand() % col;   //生成随机数并取模COL,保证COL范围在棋盘大小内
    if (board[num1][num2] == ' ') 
    {
      board[num1][num2] = '#';    //如果为空落子成功,如果不为空重新生成随机数
      break;
    }
  }
  printf("人机落子并说道:你输定了小伙子\n");
}

7.判断输赢

  • 判断输赢是很重要的一步,不论是玩家落子后或电脑落子后,我们都应该进行判断程序是否应该结束
char ending(char board[ROW][COL], int row, int col) //判断游戏是否应该结束
{
  for (int i = 0; i < ROW; i++)
  {
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
    {
      return board[0][i]; //列相等返回所在列的字符,游戏结束
    }
  }
  for (int i = 0; i < COL; i++)
  {
    if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
    {
      return board[i][1];//行相等返回所在行的字符,游戏结束
    }
  }
  if (board[0][0] == board[1][1] && board[1][1] == board[2][2])
  {
    return board[1][1];//斜线相等返回所在字符,游戏结束
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0])
  {
    return board[1][1];//斜线相等返回所在字符,游戏结束
  }
  for (int i = 0; i < ROW; i++)
  {
    for (int j = 0; j < COL; j++)
    {
      if (board[i][j] == ' ')
      {
        return;   //如果还有空位,则游戏继续
      }
    }
  }
  return 'q';//运行到这里证明棋盘已经满了,游戏结束
}

8.game函数

  • 最后我们根据这些函数的作用将所有的函数整合到一块,就形成了我们整个游戏程序
void game()
{
  char board[ROW][COL] = { 0 };     //三子棋是一个长3宽3的棋盘,这里用二维数组来装这个棋盘
  init(board, ROW, COL);        //此函数用于二维数组初始化
  printboard(board, ROW, COL);      //~用于打印棋盘
  while (1)
  {
    char end = '\0';
    playerMove(board, ROW, COL);  //~玩家下子
    printboard(board, ROW, COL);    //~打印棋盘
    end = ending(board, ROW, COL); //查看是否应该结束
    if (end == '*')     //返回值为*玩家胜利
    {
      printf("Player WIN!!!\n");
      break;
    }
    else if (end == 'q')    //返回值为棋盘满了未分胜负,平局,退出游戏
    {
      printf("敌人太强大了,居然平分秋色\n");
    }
    computerMove(board, ROW, COL);    //~电脑下子
        printboard(board, ROW, COL);    //打印棋盘
    end = ending(board, ROW, COL);  //查看是否应该结束
    if (end == '#')     //返回值为#人机获得胜利
    {
      printf("Computer WIN!!!\n");
      break;
    }
    else if (end == 'q')
    {
      printf("平局\n");     
    }
  }
}

文件分类

🌞🌞为了使代码更有阅读性,我们不建议把所有函数写在一个文件里,所以这里分成三个文件

test.c

  • 这个文件包含程序的主体构思,程序用到的一系列函数我们封装在其他文件夹,这里只需要引入头文件即可
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu() //菜单
{
  printf("****************************\n");
  printf("******    1.  play     *****\n");
  printf("******    0.  exit     *****\n");
  printf("****************************\n");
}
void game()
{
  char board[ROW][COL] = { 0 };     //三子棋是一个长3宽3的棋盘,这里用二维数组来装这个棋盘
  initboard(board, ROW, COL);       //此函数用于二维数组初始化
  printboard(board, ROW, COL);      //~用于打印棋盘
  while (1)
  {
    char end = '\0';
    playerMove(board, ROW, COL);  //~玩家下子
    printboard(board, ROW, COL);    //~打印棋盘
    end = ending(board, ROW, COL); //查看是否应该结束
    if (end == '*')
    {
      printf("Player WIN!!!\n");
      break;
    }
    else if (end == 'q')
    {
      printf("敌人太强大了,居然平分秋色\n");
    }
    computerMove(board, ROW, COL);    //~电脑下子
    printboard(board, ROW, COL);    //打印棋盘
    end = ending(board, ROW, COL);  //查看是否应该结束
    if (end == '#')
    {
      printf("Computer WIN!!!\n");
      break;
    }
    else if (end == 'q')
    {
      printf("平局\n");
    }
  }
}
int main()
{
    int input = 0;
    srand((unsigned)time(NULL));   //生成随机数用于人机自动落子
  do 
  {
    menu();    //do-while语句进来先打印菜单栏
    printf("请进行选择(0/1)\n");   //这里进行输入有一个小细节就是把退出设置为0,然后把输入数字放在dowhile()里面这样输入0就直接退出循环了
    scanf("%d", &input);   
    switch (input)       //switch语句进行选择,一目了然
    {
    case 1:
      game();  //进入游戏
      break;
    case 0:
      printf("成功退出");
      break;
    default: 
      printf("输入错误,请重新输入");
      break;
    }
  } while (input);
}

game.c

  • 进入游戏后需要的所有函数都封装在这里
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void initboard(char board[ROW][COL],int row,int col)//此函数用于二维数组初始化
{
  memset(&board[0][0], ' ', row * col * sizeof(board[0][0]));
}
void printboard(char board[ROW][COL],int row,int col)//~用于打印棋盘
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++) 
    {
      printf(" %c ", board[i][j]);
      if (j<col - 1)
      {
        printf("|");
      }
    }
    printf("\n");
    if (i < row - 1) 
    {
      for (int 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");
  while (1)
  {
    int num1=0;
    int num2=0;
    scanf("%d,%d", &num1, &num2);
    if ((num1 > 3 || num1 < 0) || (num2 > 3 || num2 < 0))
    {
      printf("请输入正确位置");
      continue;
    }
    if (board[num1-1][num2-1] == ' ')
    {
      board[num1-1][num2-1] = '*';
      break;
    }
    else
    {
      printf("请选择空位下子\n");
    }
  }
}
void computerMove(char board[ROW][COL], int row, int col)//~电脑下子
{
  while(1)
  {
    int num1 = rand() % row;
    int num2 = rand() % col;
    if (board[num1][num2] == ' ')
    {
      board[num1][num2] = '#';
      break;
    }
  }
  printf("你输定了小伙子\n");
}
char ending(char board[ROW][COL], int row, int col) //判断游戏是否应该结束
{
  for (int i = 0; i < ROW; i++)
  {
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
    {
      return board[0][i]; //列相等返回所在列的字符,游戏结束
    }
  }
  for (int i = 0; i < COL; i++)
  {
    if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
    {
      return board[i][1];//行相等返回所在行的字符,游戏结束
    }
  }
  if (board[0][0] == board[1][1] && board[1][1] == board[2][2])
  {
    return board[1][1];//斜线相等返回所在字符,游戏结束
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0])
  {
    return board[1][1];//斜线相等返回所在字符,游戏结束
  }
  for (int i = 0; i < ROW; i++)
  {
    for (int j = 0; j < COL; j++)
    {
      if (board[i][j] == ' ')
      {
        return;   //如果还有空位,则游戏继续
      }
    }
  }
  return 'q';//运行到这里证明棋盘已经满了
}

game.h

  • 将;主程序所需要的函数全部在头文件中声明,增加代码阅读性
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define COL  3
#define ROW  3
void printboard(char board[ROW][COL], int row, int col);//~用于打印棋盘
void initboard(char board[ROW][COL], int row, int col);//此函数用于二维数组初始化
void playerMove(char board[ROW][COL], int row, int col);//~玩家下子
void computerMove(char board[ROW][COL], int row, int col);//~电脑下子
char ending(char board[ROW][COL], int row, int col);//查看是否应该结束

撒花

这就是实现三子棋的全部内容了,创作不易,还请各位小伙伴多多点赞关注,以后也会更新各种小游戏还有关于c语言的博客。



4ed92917abb246f691397003d6654cfd.gif

















相关文章
|
13天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
53 24
|
9天前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
47 16
|
13天前
|
C语言
【C语言程序设计——循环程序设计】枚举法换硬币(头歌实践教学平台习题)【合集】
本文档介绍了编程任务的详细内容,旨在运用枚举法求解硬币等额 - 循环控制语句(`for`、`while`)及跳转语句(`break`、`continue`)的使用。 - 循环嵌套语句的基本概念和应用,如双重`for`循环、`while`嵌套等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台将对编写的代码进行测试,并给出预期输出结果。 5. **通关代码**:提供完整的代码示例,帮助理解并完成任务。 6. **测试结果**:展示代码运行后的实际输出,验证正确性。 文档结构清晰,逐步引导读者掌握循环结构与嵌套的应用,最终实现硬币兑换的程序设计。
44 19
|
13天前
|
算法 C语言
【C语言程序设计——循环程序设计】求解最大公约数(头歌实践教学平台习题)【合集】
采用欧几里得算法(EuclideanAlgorithm)求解两个正整数的最大公约数。的最大公约数,然后检查最大公约数是否大于1。如果是,就返回1,表示。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。作为新的参数传递进去。这个递归过程会不断进行,直到。有除1以外的公约数;变为0,此时就找到了最大公约数。开始你的任务吧,祝你成功!是否为0,如果是,那么。就是最大公约数,直接返回。
66 18
|
13天前
|
Serverless C语言
【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】
根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码,求解出数值x的平方根;运用迭代公式,编写一个循环程序,求解出数值x的平方根。注意:不能直接用平方根公式/函数求解本题!开始你的任务吧,祝你成功!​ 相关知识 求平方根的迭代公式 绝对值函数fabs() 循环语句 一、求平方根的迭代公式 1.原理 在C语言中,求一个数的平方根可以使用牛顿迭代法。对于方程(为要求平方根的数),设是的第n次近似值,牛顿迭代公式为。 其基本思想是从一个初始近似值开始,通过不断迭代这个公式,使得越来越接近。
44 18
|
13天前
|
C语言
【C语言程序设计——循环程序设计】统计海军鸣放礼炮声数量(头歌实践教学平台习题)【合集】
有A、B、C三艘军舰同时开始鸣放礼炮各21响。已知A舰每隔5秒1次,B舰每隔6秒放1次,C舰每隔7秒放1次。编程计算观众总共听到几次礼炮声。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。开始你的任务吧,祝你成功!
44 13
|
9天前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
19 3
|
13天前
|
存储 安全 C语言
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
36 10
|
13天前
|
小程序 C语言
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
32 10
|
9天前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
11 2

热门文章

最新文章