【C语言】三子棋小游戏

简介: 【C语言】三子棋小游戏

一、三子棋游戏介绍

  三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。

   下面作者将带着大家一起用C语言实现一个三子棋的小游戏。

二、代码分装

源文件:

test.c: 整个游戏相关的测试

game.c: 实现游戏的相关函数

头文件:

game.h: 相关函数的声明,整个代码要引用的头文件以及宏定义

三、代码实现步骤

1.制作菜单menu函数以及游戏运行逻辑流程

  • 首先在 test.c 中定义一个menu函数打印菜单,提示玩家1开始游戏,0退出游戏。
  • scanf接收玩家输入并用switch判断,1即开始游戏,0则退出游戏,非1非0则提示选择错误,重新选择。而为了能够让用户重新选择以及结束一局游戏后能够再来一盘,需要使用do while语句将它们包含起来。

test.c

void menu()
{
  printf("*********************\n");
  printf("*****  1. game  *****\n");
  printf("*****  0. exit  *****\n");
  printf("*********************\n");
}
void game()
{
  printf("三子棋\n");
}
int main()
{
  int input = 0;
  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;
}

运行代码检测游戏运行逻辑流程

2.初始化棋盘InitBoard函数

  • 首先三子棋是九个格子,即需要创建一个3x3的数组。为了方便未来修改代码数值,头文件 game.h 中定义ROW(行),COL(竖),然后在 test.c 中引用头文件 game.h即可。
  • 在game函数中创建棋盘board数组,开始的时候,数组的内容应该都是空格,为了方便后续使用,创建一个初始化棋盘函数InitBoard。
  • game.h 中定义InitBoard函数,并在 game.c 中实现函数。

game.h

#include <stdio.h>
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL],int row,int col);

game.c

//初始化棋盘
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] = ' ';//空格
    }
  }
}

3.打印棋盘DisplayBoard函数

接下来创建一个打印棋盘函数DisplayBoard来查看一下初始化是否完成。同样的:在 game.h 中定义DisplayBoard函数,并在 game.c 中实现函数。

首先看棋盘效果图:

思路如下:先打印数据行,再打印分割行

1、数据行打印形式:空格数据空格竖杠

当到达最后一列时不打印竖杠

2、分割行打印形式:---|

当到达最后一列时不打印竖杠,并且当到达最后一行时,不打印分割行

game.h

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

game.c

//打印棋盘
void DisplayBoard(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++)
    {
      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");
  }
}

4.玩家下棋PlayerMove函数

game.h 中定义PlayerMove函数,并在 game.c 中实现函数。

game.h

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

game.c

需要考虑坐标被占用的情况以及输入非法坐标的情况。

使用while循环嵌套输入部分与判断部分,这样当输入错误或者输入的坐标被占用时,可以重新输入。当输入正确时且没被占用,则在该坐标里将 空格 改为 * 。

//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  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] == ' ') //玩家的输入对应数组的下标需要-1
      {
        board[x - 1][y - 1] = '*';
        break;
      }
      else
      {
        printf("该坐标被占用,请输入其他坐标\n");
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
}

需要注意的是,因为玩家下棋的坐标范围是1-3的,而数组中的范围是0-2,因此需要将玩家输入的数-1得到对应的数组下标,才能执行正确。

5.电脑下棋ComputerMove函数

   这里电脑的下棋策列是随机下棋,因此首先需要生成随机数,这就需要用到srand函数、rand函数和time函数,关于srand函数、rand函数和time函数之间的知识点,我在往期的博客中有进行讲解,感兴趣的可以前往:【C语言】猜数字小游戏——深度刨析rand函数生成随机数_Hacynn的博客-CSDN博客查看,在这里就不过多赘述。

使用srand和rand需要包含 stdlib.h 头文件,使用time需要包含 time.h 头文件。并且在main函数中调用srand生成随机种子,这样rand函数便可以生成随机数。

game.h

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

game.c

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

当完成这一步时,三子棋游戏就大概完成了,玩家和电脑可以相互下棋,但是缺少了获胜的条件,因此还需要设置一个获胜条件来停止游戏。

6. 判断输赢IsWin函数

这里我们先要考虑判断IsWin函数需要返回几种结果:

1、玩家获胜===》函数返回*

2、电脑获胜===》函数返回#

3、平局       ===》函数返回Q

4、游戏继续===》函数返回C

game函数

void game()
{
  int ret = 0;
  char board[ROW][COL];
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  while (1)
  {
    //玩家
    PlayerMove(board, ROW, COL);//玩家下棋
    DisplayBoard(board, ROW, COL);//打印棋盘结果
    ret = IsWin(board, ROW, COL);//判断输赢
    if (ret != 'C')
    {
      break;
    }
    //电脑
    ComputerMove(board, ROW, COL);//电脑下棋
    DisplayBoard(board, ROW, COL);//打印棋盘结果
    ret = IsWin(board, ROW, COL);//判断输赢
    if (ret != 'C')
    {
      break;
    }
  }
  if (ret == '*')
    printf("玩家赢!\n");
  else if (ret == '#')
    printf("电脑赢!\n");
  else
    printf("平局!\n");
}

判断IsWin函数返回的值并返回提示或者继续游戏。

game.h

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

game.c

//判断是否为满
static 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)
{
  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[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))
  {
    return 'Q';//平局
  }
  return 'C';//继续
}

其中需要注意的是,IsFull函数仅是用来判断数组是否已满,未满返回0满返回1。而且IsFull只辅助于IsWin函数,不被其他函数调用,因此可以在前面加static修饰。

四、三子棋完整代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
  printf("*********************\n");
  printf("*****  1. game  *****\n");
  printf("*****  0. exit  *****\n");
  printf("*********************\n");
}
void game()
{
  int ret = 0;
  char board[ROW][COL];
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  while (1)
  {
    //玩家
    PlayerMove(board, ROW, COL);//玩家下棋
    DisplayBoard(board, ROW, COL);//打印棋盘结果
    ret = IsWin(board, ROW, COL);//判断输赢
    if (ret != 'C')
    {
      break;
    }
    //电脑
    ComputerMove(board, ROW, COL);//电脑下棋
    DisplayBoard(board, ROW, COL);//打印棋盘结果
    ret = IsWin(board, ROW, COL);//判断输赢
    if (ret != 'C')
    {
      break;
    }
  }
  if (ret == '*')
    printf("玩家赢!\n");
  else if (ret == '#')
    printf("电脑赢!\n");
  else
    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;
}

game.h

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL],int row,int col);
//打印棋盘
void DisplayBoard(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 IsWin(char board[ROW][COL], int row, int col);

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#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++)
  {
    //打印数据行
    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)
{
  int x = 0;
  int y = 0;
  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 ComputerMove(char board[ROW][COL], int row, int col)
{
  printf("电脑下棋\n");
  int x = 0;
  int y = 0;
  while (1)
  {
    x = rand() % row;
    y = rand() % col;
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
}
//判断是否为满
static 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)
{
  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[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))
  {
    return 'Q';//平局
  }
  return 'C';//继续
}

此次的三子棋小游戏的内容就到此为止了,相信大家也能够做出属于自己的三子棋小游戏,这个游戏最重要的是代码思维而不是代码本身,理解代码思维能够得到更大的提升。

如果觉得作者写的不错,求给作者一个大大的点赞支持一下,你们的支持是我更新的最大动力!

目录
相关文章
|
2月前
|
C语言 C++
【C语言】编写“猜数字“小游戏
【C语言】编写“猜数字“小游戏
|
3月前
|
定位技术 API C语言
C语言——实现贪吃蛇小游戏
本文介绍了一个基于Windows控制台的贪吃蛇游戏的实现方法。首先,需调整控制台界面以便更好地显示游戏。接着,文章详细描述了如何使用Win32 API函数如`COORD`、`GetStdHandle`、`GetConsoleCursorInfo`等来控制控制台的光标和窗口属性。此外,还介绍了如何利用`GetAsyncKeyState`函数实现键盘监听功能。文中还涉及了`&lt;locale.h&gt;`库的使用,以支持本地化字符显示。
61 1
C语言——实现贪吃蛇小游戏
|
3月前
|
存储 安全 算法
C 语言——实现扫雷小游戏
本文介绍了使用二维数组创建棋盘并实现扫雷游戏的方法。首先,通过初始化数组创建一个9x9的棋盘,并添加行列标识以便操作。接着,利用随机数在棋盘上布置雷。最后,通过判断玩家输入的坐标来实现扫雷功能,包括显示雷的数量和处理游戏胜利或失败的情况。文中提供了完整的代码实现。
50 1
C 语言——实现扫雷小游戏
|
2月前
|
C语言 定位技术 API
【C语言】实践:贪吃蛇小游戏(附源码)(二)
【C语言】实践:贪吃蛇小游戏(附源码)
【C语言】实践:贪吃蛇小游戏(附源码)(二)
|
2月前
|
C语言 开发者
C语言实现猜数字小游戏(详细教程)
C语言实现猜数字小游戏(详细教程)
|
6月前
|
C语言
C语言实现2048小游戏---粤嵌GE6818嵌入式系统实训
C语言实现2048小游戏---粤嵌GE6818嵌入式系统实训
|
2月前
|
C语言
【C语言】实践:贪吃蛇小游戏(附源码)(三)
【C语言】实践:贪吃蛇小游戏(附源码)
|
2月前
|
存储 API C语言
【C语言】实践:贪吃蛇小游戏(附源码)(一)
【C语言】实践:贪吃蛇小游戏(附源码)
|
2月前
|
C语言
C语言贪吃蛇小游戏来啦!
C语言贪吃蛇小游戏来啦!
33 0
|
5月前
|
存储 编译器 C语言