超详细教学用c语言实现三子棋小游戏

简介: 超详细教学用c语言实现三子棋小游戏

1.三子棋游戏规则

在设计游戏前,我们先得知道最基础的游戏规则,以实现我们最基本的设计需求:

1、人机双方轮流在格子里落子棋子,先连成三棋一线者视为胜利

2、棋盘被摆满棋子仍未分出胜利,视为平局

2.分析需求

       其实设计程序的难点就在于,把抽象的逻辑概念转化为计算机语言可识别的逻辑语句,再简单的设计需求,都要用科学的分析方法,先分析需求,再针对性的设计,不可想当然的拿起手就开始写代码,也就是我们始终强调的编程思维。要用工程化的方法解决实际问题。


       首先,一个游戏是必须有菜单界面的,供以玩家选择是否开始游戏或者退出游戏,同时我们也要考虑游戏多次游玩的情况,需要用一个循环语句将菜单界面封装起来,可以让玩家在游玩后再次进入菜单选择是否开始游戏;其次是游戏的初始化问题,我们需要一个数组来保存玩家和电脑下棋时落子的位置,并且要在屏幕上打印出来,在这里我们就得考虑落子的问题,玩家落子很简单,用一个数组保存就行了,但是电脑的落子应该是随机的,我们可以考虑使用rand函数和time函数来做到随机生成的功能,,并且在落子的时候我们得考虑输入是否合理,不能越界输入,不能重复在同一个位置落子;解决了以上的问题后,我们要思考,怎么设计一个判断输赢的逻辑,怎么样是玩家赢,怎么样是电脑赢,怎么样算是平局。


       在有了以上大致的规划和思考后,我们就可以正式的开始设计了。


       在开始设计之前,我们首先得明确,这个程序是由多个功能的函数语句共同实现的,因此在创建工程时,我们就应该提前做好创建多个文件的工作,不同的文件实现不同的功能和逻辑,以保证程序的健康性和完整性,也方便我们日后更改。我们可以分为一下三个文件实现,game.h用于包含程序所需要的头文件和函数的申明,chessboard.c用于实现棋盘上具体的初始化和判断逻辑,game.c文件为主要的主程序所在的文件,是程序的主体,也是各个函数的集合实现。

3.菜单界面设计

       首先需要在屏幕上打印菜单,然后让玩家选择,若玩家输入不正确或者想在游玩后再次游玩的话,则需要个循环来实现,因此,这里需要的是先执行循环体再判断循环条件的语句,也就是do...whlie...语句,以下是代码实现

void screen()
{
  printf("--------------------------\n");
  printf("---------1.Play ----------\n");
  printf("--------------------------\n");
  printf("---------2.Esc  ----------\n");
  printf("--------------------------\n");
}
int input = 0;//记录玩家的输入选择
  printf("请进行输入确认是否开始游戏\n");
  do
  {
    screen();//调用屏幕打印菜单的函数
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      printf("开始游戏\n");
      printf("三子棋\n");
      game();
      break;
    case 2:
      printf("退出游戏\n");
      break;
    default:
      printf("非法输入,请重新输入\n");
      break;
    }
  } while (input != 2);

4.游戏主体设计(棋盘的初始化部分)

       在这里,为了方便以后对棋盘大小进行更改,我们可以在头文件中进行宏定义,我们用ROWCOL分别来代表行和列

#define ROW 3 //定义 行为3
#define COL 3 //定义 列为3

    然后我们需要用一个3*3的数组去对我们的棋盘的数据进行保存,并对其进行初始化,将其封装成一个函数,并且放在chessboard.c文件中实现,需要传入的参数是一个数组和行以及列。我们对数组中每一个赋值为空格。

char board[ROW][COL] = { 0 };
  initialize(board, ROW, COL);//初始化棋盘
void initialize(char board[ROW][COL], int row, int col)
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++)
    {
      board[i][j] = ' ';
    }
  }
}

 在完成了初始化之后,我们需要打印棋盘到屏幕上供玩家看见,但是此时打印出来的全是空格,玩家是看不见什么有意义的信息的,所以我们要制定一个棋盘的框架,既要实现需求,也要保证美观,所以需要打印部分分割线

isplayboard(board, ROW, COL);//打印棋盘
void displayboard(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("|");
    }
    //打印分割行
    if (i < row - 1)
      printf("\n---|---|---\n");
  }
  printf("\n");
}

我们可以运行着测试一下

5.游戏主体设计(玩家下棋部分)

        在拥有完整的棋盘后,我们就可以开始着手设计玩家下棋和电脑下棋的部分了,首先是玩家下棋的部分,我们可以用之前定义的board数组来防止玩家落子的结果,可以设计如下的封装函数。使用while循环来保证玩家落子是真确合法的,否则就一直进行循环,直到输入正确的落子坐标。

palyer_move(board, ROW, COL);//玩家下棋
void palyer_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("\n----玩家下棋----\n");//提示语句
  while (1)
  {
    printf("请输入落子的坐标:");
    scanf("%d %d", &x, &y);
    if (x <= 0 || x > 3 || y <= 0 || y > 3)//判断输入是否越界
    {
      printf("非法输入,请重新输入\n");
    }
    else if (board[x-1][y-1] == ' ')
    {
      board[x-1][y-1] = '*';//用*表示玩家落子
      break;
    }
    else
      printf("输入位置被占用,请重新输入\n");
  }
}

6.游戏主体(电脑下棋部分)

       电脑下棋,最需要的就是随机,不然每一次电脑都是一个下法,游戏就不能正常游玩了,在这里,我们可以使用rand函数来生成随机数,使用srand函数来作为生成随机数的种子,为了保证随机数的动态变化,我们使用time函数来获取时间戳供以srand函数作为参数,对于以上知识点有不了解的小伙伴可以参考笔者的这篇文章,里面对rand函数,srand函数,time函数有非常详细的教学和参数返回值的讲解:c语言实现猜数字小游戏以及如何做到生成真正的随机数

computer_move(board, ROW, COL);//电脑下棋
srand((unsigned int)time(NULL));//初始化随机数的种子
void computer_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("\n----电脑下棋----\n");//提示语句
  while (1)
  {
    int x = rand() % ROW;//使得随机数大小为1--3
    int y = rand() % COL;//使得随机数大小为1--3
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';//用#表示电脑落子
      break;
    }
  }
}

在这里的while循环是为了避免不合理的落子,比如在以及有玩家落子的地方是不允许再一次落子的,在不满足这样的条件下会再一次生成新的随机数,直到可以有正确的落子坐标为止

7.判断输赢逻辑逻辑设计

在玩家和电脑落子都设计完成后,我们需要思考,怎么样的情况下算是玩家赢,怎么样的情况下算是电脑赢,怎么样算是平局,在玩家或者电脑赢了后怎么样实现立即停止游戏。


       我们可以设计一个函数,用其返回值来表示谁赢的了游戏的胜利,谁先完成三子连成一线就返回谁的棋子符号,在这里可以用俩个for循环判断3行和3列是否已经达成三子一线的情况,并且不能是三个空格,如果满足条件,则返回满足条件的元素符号,也就是*或者#,在用俩个if语句去判断俩条对角线是否满足条件,都没完成就继续游戏,并且设计一个函数判断棋盘是否满了,当棋盘下满后返回Q表示棋盘已经下满了,游戏平局,否则返回C表示游戏继续正常进行

//玩家赢 - '*'
//电脑赢 - '#'
//平局 --- '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[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';
}

其中的判断棋盘是否下满的函数具体实现如下

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;//判断有空位,返回0
    }
  }
  return 1;//判断棋盘已满,返回1
}

      并且在游戏的主程序中,玩家每下一次棋以及电脑每下一次棋,都进行一次判断,用一个while循环,当某一方胜利或者平局时,也就是ret拿到的返回值只要不是C(游戏继续),就执行if语句,跳出循环,具体实现如下,在跳出循环后我们要对结果进行打印,也就是使用if...else if...else的多分支语句进行判断

while (1)
  {
    palyer_move(board, ROW, COL);//玩家下棋
    displayboard(board, ROW, COL);//打印棋盘
    //判断输赢
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    computer_move(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");
  }

综上完成了各个模块的设计后,我们就可以进行组装,最后完成程序的设计

8.游戏完整代码

1.头文件代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3 //定义 行为3
#define COL 3 //定义 列为3
//打印屏幕菜单
void screen();
//初始化
void initialize(char board[ROW][COL], int row, int col);
//打印棋盘
void displayboard(char board[ROW][COL],int row,int col);
//玩家下棋
void palyer_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);

2.棋盘模块代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void screen()
{
  printf("--------------------------\n");
  printf("---------1.Play ----------\n");
  printf("--------------------------\n");
  printf("---------2.Esc  ----------\n");
  printf("--------------------------\n");
}
void initialize(char board[ROW][COL], int row, int col)
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++)
    {
      board[i][j] = ' ';
    }
  }
}
void displayboard(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("|");
    }
    //打印分割行
    if (i < row - 1)
      printf("\n---|---|---\n");
  }
  printf("\n");
}
void palyer_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("\n----玩家下棋----\n");
  while (1)
  {
    printf("请输入落子的坐标:");
    scanf("%d %d", &x, &y);
    if (x <= 0 || x > 3 || y <= 0 || y > 3)
    {
      printf("非法输入,请重新输入\n");
    }
    else if (board[x-1][y-1] == ' ')
    {
      board[x-1][y-1] = '*';
      break;
    }
    else
      printf("输入位置被占用,请重新输入\n");
  }
}
void computer_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("\n----电脑下棋----\n");
  while (1)
  {
    int x = rand() % ROW;//使得随机数大小为1--3
    int y = rand() % COL;//使得随机数大小为1--3
    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;
}
//玩家赢 - '*'
//电脑赢 - '#'
//平局 --- '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[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';
}

3.游戏主函数文件代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game()
{
  //打印棋盘
  void screen();
  char ret = 0;
  char board[ROW][COL] = { 0 };
  initialize(board, ROW, COL);//初始化棋盘
  displayboard(board, ROW, COL);//打印棋盘
  while (1)
  {
    palyer_move(board, ROW, COL);//玩家下棋
    displayboard(board, ROW, COL);//打印棋盘
    //判断输赢
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    computer_move(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()
{
  srand((unsigned int)time(NULL));
  int input = 0;
  printf("请进行输入确认是否开始游戏\n");
  do
  {
    screen();
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      printf("开始游戏\n");
      printf("三子棋\n");
      game();
      break;
    case 2:
      printf("退出游戏\n");
      break;
    default:
      printf("非法输入,请重新输入\n");
      break;
    }
  } while (input != 2);
  return 0;
}

9.程序运行部分截图

本次的分享就到此为止啦,希望对各位小伙伴有所帮助

目录
相关文章
|
12天前
|
C语言
C语言实现2048小游戏---粤嵌GE6818嵌入式系统实训
C语言实现2048小游戏---粤嵌GE6818嵌入式系统实训
35 0
|
5天前
|
程序员 C语言
C语言小游戏之猜数字
C语言小游戏之猜数字
14 5
|
5天前
|
C语言
【海贼王编程冒险 - C语言海上篇】C语言如何实现简单的三子棋游戏?
【海贼王编程冒险 - C语言海上篇】C语言如何实现简单的三子棋游戏?
7 1
|
6天前
|
C语言
C语言小游戏的源代码
C语言小游戏的源代码
|
2月前
|
C语言
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(二)
我们可以通过创建并定义符号常量NUMBER,来作为判断是否胜利的标准。如三子棋中,令NUMBER为3,则这八个方向中有任意一个方向达成3子连珠,则连珠的这个棋子所代表的玩家获胜。
28 1
|
2月前
|
算法 C语言 C++
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(一)
三子棋游戏设计的核心是对二维数组的把握和运用。
28 1
|
17天前
|
程序员 C语言 索引
【️C语言-游戏设置】---三子棋(N满)
【️C语言-游戏设置】---三子棋(N满)
|
24天前
|
C语言
C语言小插曲——对图形库的初步探索(消除小球小游戏)
C语言小插曲——对图形库的初步探索(消除小球小游戏)
11 0
|
25天前
|
C语言
C语言结构体教程:从入门到实践(保姆式教学)
C语言结构体教程:从入门到实践(保姆式教学)
19 0
|
25天前
|
C语言
C语言中求x的n次方:从入门到实践(保姆式教学)
C语言中求x的n次方:从入门到实践(保姆式教学)
30 0

相关实验场景

更多