【C语言】小游戏-三字棋

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

一、游戏介绍

三子棋》是一款古老的民间传统游戏,又被称为黑白棋、圈圈叉叉棋、井字棋、一条龙、九宫棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子连成一条线的一方则视为胜利者


二、文件分装

源文件:内含函数实现,变量定义等内容

头文件:内含函数声明、宏定义、结构体定义等内容

实现这个三子棋,我创建了三个文件

源文件:

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

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

头文件:

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


三、代码实现步骤

1.制作简易游戏菜单

(1)定义一个menu函数来打印游戏菜单,菜单中需要有游戏菜单选项:1.开始游戏  0.退出游戏,当我们输入1就进入游戏,0就退出游戏

(2)考虑到玩家可能玩一局以后还想继续玩,就用do while循环打印菜单,while(input),当输入的值为0,就跳出循环(退出游戏),如果输入非0值就再次进入循环(再次选择)

(3)玩家选择了进入游戏还是退出游戏需要判断,就用switch case语句来进行判断

test.c

#include"game.h"
void menu()
{
  printf("*****************************************\n");
  printf("**********      1.开始游戏      *********\n");
  printf("**********      0.退出游戏      *********\n");
  printf("*****************************************\n");
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do//实现玩多盘游戏
  { 
    menu();//打印菜单
    printf("请选择1/0:>\n");
    scanf("%d", &input);//选择进入游戏/退出游戏
    switch (input)//判断输入input的值决定是进入游戏还是退出游戏
    {
    case 1:
      game();//三子棋游戏的实现
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误,请重新选择\n");
      break;
    }
  } while (input);//当input为0,跳出循环;为1再玩一盘游戏(重新进入循环);为其他值进入循环重新选择
  return 0;
}


考虑到game.c和test.c可能都要用printf函数的头文件#include<stdio.h>,我们直接把这个头文件写进game.h,那么test.c这个文件只需引用#inlclude"game.h"即可

系统头文件一般用<>

用户自己定义的则可以使用" ",加快搜索速度


效果展示:


选择1,进入game()

选择0,退出游戏:

选择非1非0(选择错误),重新选择


2.初始化棋盘

(1)首先我们需要定义一个二维数组来存放数据,可以采用宏定义


宏定义:方便程序的修改,如果我们要改变棋盘的大小,直接修改宏定义的数字即可


(2)初始化棋盘我们定义一个InitBoard(board)函数,将棋盘全部初始化为' '

game.h

//宏定义:
//为了方便直接改变棋盘的大小,在头文件里面定义(ROW和COL就是常量)
#define ROW 3 //没有逗号     //行
#define COL 3                //列
//初始化数组为空格
void InitBoard(char board[ROW][COL]);

game.c

//初始化数组为空格
void InitBoard(char board[ROW][COL])
{
  for (int i = 0; i <ROW; i++)
  {
    for (int j = 0; j <COL; j++)
    {
      board[i][j] = ' ';//全部初始化为空格
    }
  }
}

3.打印棋盘

我们想打印这样打一个棋盘:用分隔线分开方便观察

(1)先打印数据(最后一个不用打印‘|’ )

(2)再打印分割行(最后一行不用打印)

game.h

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

game.c

//打印棋盘
void DisplayBoard(char board[ROW][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");
    }
  }
}

4.玩家下棋

注意:

(1)玩家下棋输入坐标要在1-3(如果不在这个范围要重新输入),而不是数组下标的范围0-2,所以放入坐标是输入坐标分别-1得到的结果放入


(2)玩家下棋我们需要考虑坐标是否已经被占用


(3)字符的比较可以用==,既可用于常量也可用于变量比较

      字符串的比较要用strcmp函数,并且只能用于变量比较

game.h

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

game.c

//玩家下棋
void PlayerMove(char board[ROW][COL])
{
  int x = 0;
  int y = 0;
  printf("玩家下棋\n");
  while (1)
  {
    printf("请输入要下棋的坐标:>\n");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= ROW && y >= 1 && y <= COL)//下棋的坐标必须在二维数组内部
    {
      if (board[x - 1][y - 1] == ' ')//1.输入的横纵坐标-1才是数组的下标  2.字符串的比较不能用==,但是这只是一个字符空格而已
      {
        board[x - 1][y - 1] = '*';
        break;
      }
      else
      {
        printf("该坐标已被占用,请输入其他坐标\n");
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
}

5.电脑随机下棋

电脑随机下棋就需要随机生成两个随机数,但是这两个数要在棋盘范围内,那就对生成的随机数进行取模x = rand() % ROW;产生的数为0-(ROW-1),这个时候就不用-1了,因为电脑下棋不用我们自己输入,它就以数组的形式下棋就行


这里介绍三个函数


rand():

头文件:#include<stdlib.h>

这个函数返回的是0-rand max之间的值(0-32767)

在使用rand函数之前,我们要求调用srand函数,这样才能实现rand的功能

srand():

头文件:#include<stdlib.h>

要想生成一个随机数,还得给srand一个随机数(要想rand函数产生的随机数不同,就需要给srand函数输入一个不断改变的值(如果只给一个常数,那么rand给出的随机数就是同一个值,不会改变))

srand的参数需要是unsigned int(无符号整形)eg:srand((unsigned int)time(NULL));

time():

头文件:#include<time.h>

原理:时间戳:把不停在改变的时间转化为数字返回,从而给srand一个随机值

game.h

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

game.c

//电脑随机下棋
void ComputerMove(char board[ROW][COL]) 
{
  int x = 0;
  int y = 0;
  printf("电脑下棋\n");
  while (1)
  {
    x = rand() % ROW;//产生的数为0-(ROW-1)
    y = rand() % COL;
    if (board[x][y] == ' ')//如果这个位置已经有棋子了,再进入循环,重新生成x和y直到下了一个棋子为止
    {
      board[x][y] = '#';
      break;
    }
  }
}

6.判断输赢

判断输赢:设置四种结果:

玩家赢-返回*

电脑赢-#

平局-Q

游戏继续—C

game.h

//判断输赢
char IsWin(char board[ROW][COL]);

game.c

//判断输赢:四种结果:
//玩家赢-返回*
//电脑赢-#
//平局-Q
//游戏继续—C
char IsWin(char board[ROW][COL])
{
  for (int i = 0; i < ROW; i++)
  {
    if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')//注意要排除三个空格的情况
      return board[i][0];//谁的棋子连着三个就返回谁的棋子
  }
  for (int i = 0; i < COL; i++)
  {
    if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')//注意要排除三个空格的情况
      return board[0][i];//谁的棋子连着三个就返回谁的棋子
  }
  if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' ')
    return board[0][0];
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    return board[1][1];
  if (IsFull(board))
    return 'Q';//如果棋盘满了,就表示平局,返回Q
  return 'C';//否则就继续下棋
}

7.判断棋盘是否满了

遍历二维数组,只要有一个空格就继续下棋(没满),如果都不是空格,那就是表示满了

game.h

//判断棋盘是否满了
int IsFull(char board[ROW][COL]);

game.c

//判断棋盘是否是满的
static int IsFull(char board[ROW][COL])//staic表示只在这个game.c的文件中使用这个函数
{
  for (int i = 0; i < ROW; i++)
  {
    for (int j = 0; j < COL; j++)
    {
      if (board[i][j] == ' ')//只要有一个空格就继续进行
        return 0;
    }
  }
  return 1;//如果都不是空格,那就是表示全满
}

四、完整代码

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

//头文件:内含函数声明、宏定义、结构体定义等内容
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//宏定义:
//为了方便直接改变棋盘的大小,在头文件里面定义(ROW和COL就是常量)
#define ROW 3 //没有逗号     //行
#define COL 3                //列
//函数声明:
//初始化数组为空格
void InitBoard(char board[ROW][COL]);//row和col为真实的行和列
//打印棋盘
void DisplayBoard(char board[ROW][COL]);
//玩家下棋
void PlayerMove(char board[ROW][COL]);
//电脑下棋
void ComputerMove(char board[ROW][COL]);
//判断输赢
char IsWin(char board[ROW][COL]);
//判断棋盘是否满了
int IsFull(char board[ROW][COL]);

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

//实现游戏相关的代码
#include"game.h"//这里也要包含自己定义的头文件,不然ROW和COL宏定义就不起作用了
//初始化数组为空格
void InitBoard(char board[ROW][COL])
{
  for (int i = 0; i <ROW; i++)
  {
    for (int j = 0; j <COL; j++)
    {
      board[i][j] = ' ';//全部初始化为空格
    }
  }
}
//打印棋盘
void DisplayBoard(char board[ROW][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 x = 0;
  int y = 0;
  printf("玩家下棋\n");
  while (1)
  {
    printf("请输入要下棋的坐标:>\n");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= ROW && y >= 1 && y <= COL)//下棋的坐标必须在二维数组内部
    {
      if (board[x - 1][y - 1] == ' ')//1.输入的横纵坐标-1才是数组的下标  2.字符串的比较不能用==,但是这只是一个字符空格而已
      {
        board[x - 1][y - 1] = '*';
        break;
      }
      else
      {
        printf("该坐标已被占用,请输入其他坐标\n");
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
}
//电脑随机下棋
void ComputerMove(char board[ROW][COL]) 
{
  int x = 0;
  int y = 0;
  printf("电脑下棋\n");
  while (1)
  {
    x = rand() % ROW;//产生的数为0-(ROW-1)
    y = rand() % COL;
    if (board[x][y] == ' ')//如果这个位置已经有棋子了,再进入循环,重新生成x和y直到下了一个棋子为止
    {
      board[x][y] = '#';
      break;
    }
  }
}
//判断棋盘是否是满的
static int IsFull(char board[ROW][COL])//staic表示只在这个game.c的文件中使用这个函数
{
  for (int i = 0; i < ROW; i++)
  {
    for (int j = 0; j < COL; j++)
    {
      if (board[i][j] == ' ')//只要有一个空格就继续进行
        return 0;
    }
  }
  return 1;//如果都不是空格,那就是表示全满
}
//判断输赢:四种结果:
//玩家赢-返回*
//电脑赢-#
//平局-Q
//游戏继续—C
char IsWin(char board[ROW][COL])
{
  for (int i = 0; i < ROW; i++)
  {
    if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')//注意要排除三个空格的情况
      return board[i][0];//谁的棋子连着三个就返回谁的棋子
  }
  for (int i = 0; i < COL; i++)
  {
    if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')//注意要排除三个空格的情况
      return board[0][i];//谁的棋子连着三个就返回谁的棋子
  }
  if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' ')
    return board[0][0];
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    return board[1][1];
  if (IsFull(board))
    return 'Q';//如果棋盘满了,就表示平局,返回Q
  return 'C';//否则就继续下棋
}

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

game函数的逻辑:

(1)初始化数组,并打印出来看看什么样子

(2)开始下棋,玩家先下,下完进行打印,打印完进行判断输赢,如果不是游戏继续,就直接跳出循环,输出游戏结果(玩家赢/电脑赢/平局)

(3)电脑下棋下棋的逻辑一样

//源文件,内含函数实现,变量定义等内容
#include"game.h"//系统头文件一般用<>;用户自己定义的则可以使用""
//整个游戏相关的测试
void menu()
{
  printf("*****************************************\n");
  printf("**********      1.开始游戏      *********\n");
  printf("**********      0.退出游戏      *********\n");
  printf("*****************************************\n");
}
void game()
{
  char ret = 0;
  char board[ROW][COL];
  //开始的时候,数组的内容应该全是空格
  InitBoard(board);//用于初始化数组为空格
  DisplayBoard(board);//用于打印棋盘
  //下棋
  while (1)
  {
    PlayerMove(board);//玩家下棋放*
    DisplayBoard(board);
    //判断输赢
    ret=IsWin(board);
    if (ret != 'C')
    {
      break;//不是游戏继续就跳出循环,输出结果
    }
    ComputerMove(board);//电脑随机下棋放#
    DisplayBoard(board);
    //判断输赢
    ret = IsWin(board);
    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("请选择1/0:>\n");
    scanf("%d", &input);//选择进入游戏/退出游戏
    switch (input)//判断输入input的值决定是进入游戏还是退出游戏
    {
    case 1:
      game();//三子棋游戏的实现
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误,请重新选择\n");
      break;
    }
  } while (input);//当input为0,跳出循环;为1再玩一盘游戏(重新进入循环);为其他值进入循环重新选择
  return 0;
}

本次C语言小游戏三子棋的内容就到此啦,有什么问题欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 !


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