舌尖上的C——三子棋的慢烹细作

简介: 准备👏今晚是个大工程,但是咱不急,工欲善其事,必先利其器,先来看看需要哪些“器”:

准备👏

今晚是个大工程,但是咱不急,工欲善其事,必先利其器,先来看看需要哪些“器”:

1.一大饼函数(随机值rand函数,srand函数,自义定函数……);

2.一小撮头文件:<stdlib.h>,<time.h>,<stdio.h>;

3.格局打开:封装函数,提高可读性与逻辑感;test.c存放main函数,用来当作程序的入口,引用game.h头文件(引用自己写的头文件记得是双引号“game.h”),game.c中存放实现工程的主体函数,game.h中则存放各种函数的声明以及VS提供的头文件的包含;

4.一大堆二维数组的运用;

5.错综的分支与循环语句的嵌套使用;

6.善于分析的脑瓜子和勤快的小手手;

如果以上东西你都没有问题,那我们就不用废话,直接进入正题。


洋葱战略👏

对待问题就要像洋葱一样一层一层一层的剥开,接下来就带大家来剥洋葱

**


1.万金油开头少不了😎

int main()
{
  test();
  return 0;
}

2.上菜得先上菜单😎

先用一个test函数将菜单唤出来,之所以不写在main函数里面是方便食用。

void test()
{
  int input = 0;
  srand((unsigned int)time(NULL));//随机数发生器的初始化函数,利用时间戳生成伪随机数
    do//至少进行一次该过程
  {
    menu();
    printf("请选择菜单:>");
    scanf("%d", &input);//将值存入input以实现菜单选择功能
    switch (input)
    {
    case 1:
    {
      printf("三子棋\n");
        game();//进入游戏主体
      break;
    }
    case 0:
    {
      printf("即将退出……");
      break;
    }
    default:
    {
      printf("玩儿呢?\n");//防特殊情况防皮
      break;
    }   
    }
  } while (input);//实现游戏的重复游玩
}

3.游戏的入口——菜单😎

简简单单搞了一个菜单出来,诸君可肆意发挥,我懒惰的天性造就了它平庸的外表。

void menu()
{
printf("------------------------------------\n");
printf("------------------------------------\n");
printf("-------1.P    L    A    Y-----------\n");
printf("-------0.E    X    I    T-----------\n");
printf("------------------------------------\n");
printf("------------------------------------\n");
}

当你输入“ 1 ”时就正式开始了。


4.游戏主体😎

这里就需要动一下脑筋了,因为需要安排的东西突然就暴涨,制定规则就重在效率与目的并持。

首先在规则之下,需要实现的是三子棋的物质表达,即棋盘的设计,高大上一点就是在搭建游戏环境。棋盘是方的,那我们就用二维数组行列式的相似性来模拟棋盘,这里我设置一个名为 board 的数组。

**


1.棋盘初始化🎉

**

为了能搞出一个棋盘,我得用数据告诉编译器一个棋盘的轮廓:既然是三子棋,我们就先从最简单的3*3开始,分别用ROW(行),COL(列)来指定数组元素。

为了方便写也为了方便读,我们将ROW和COL在game.h头文件中宏定义使用:

# define ROW 3
# define COL 3

这样写也有一个好处,想要改变棋盘大小就会很简单,只需改变数字的大小,无需大费周章的到处去改这改那。

void Printboard(char board[ROW][COL], int row, int col)
{
  int i = 0;//数组下标从0开始
  int j = 0;
  for (i = 0; i < row; i++)
  {
    for (j = 0; j < col; j++)//嵌套循环来完成整个数组
    {
      board[i][j] = ' ';//将i行j列的数组初始化为空,用来布局和放入棋子
    }
  }
}

2.打印棋盘🎉

**

万事俱备只欠东风,代码直接上:

void Display(char board[ROW][COL], int row, int col)
{
  int i, j = 0;
  for (i = 0; i < row; i++)
  {
    for (j = 0; j < col; j++)
    {
      printf(" %c ", board[i][j]);//放入%c以作为棋子位存放棋子
      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");
  }
}

这里自定义的Display函数,效果如下:

image.png

棋手操作🎉

**

棋盘搞好了就可以下了嘛,这里要实现下的话,就需要我们玩家的下棋函数和一个24小时在线陪玩的憨憨人机,我们就用 player 函数和 X_MAN函数实现(取名是一种艺术):

void player(char board[ROW][COL], int row, int col)//玩家
{
  int x = 0;//模拟行数
  int y = 0;//模拟列数
  printf("玩家请输入棋子坐标:>");坐标模拟棋格
  scanf("%d%d", &x, &y);
  while (1)
  {
    if (row >= x && x >= 1 && y >= 1 && y <= col)//界定有效范围
    {
      if (board[x - 1][y - 1] == ' ')//人性化,按玩家眼中的棋盘设计
      {
        board[x - 1][y - 1] = '*';//如果本格为空,则将棋子*放入
        Display(board, row, col);//显示当前布局
        break;
      }
      else
      {
          printf("无效棋格,请重新输入\n");//防止占用
        break;
      }
      }
         else
    {
      printf("你下到棋盘外了!\n");//越界警告
    }
  }
}

相比之下,人机就好写一些了;

这里注意两个重点:1.伪随机数初始化函数记得放在上一级函数或者主函数里面;

2.电脑不需要像对玩家一样“ -1”操作,电脑自己是可以识别的;

void x_man(char board[ROW][COL], int row, int col)//人机
{
  int x = 0;
  int y = 0;
  printf("人机下:\n");
  while(1)
  {
    x = rand() % ROW;//ROW,COL范围0~2,得到0~2随机值
    y = rand() % COL;//同理
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      Display(board, row, col);
      break;
    } 
  } 
}

判断🎉

**

下棋要判断才有输赢对吧,不然咱就是在和电脑搞打字联谊。

我们就搞一个 winor函数来实现,基本思路是要实现三种情况:

1.玩家赢:

分为横三列赢,竖三列赢,对角线赢。实现条件判断我的思路简单粗暴,就是传递性连着三个元素俩俩相等,最后保证都不为空格就行(其中一个不为空就行);

2.五五开;我们又需要一个Full函数来满足平局的判断,即棋盘下满时并未满足输赢条件我们就给出平局的结果

3.电脑赢;

具体如下:

char winor(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][1];
    }
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//竖赢
    {
      return board[1][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 (1==Full(board, row, col))//Full函数判断平局
    {
      return  'p';
    }
    return 'c';
}

Full函数定义如下:

int Full(char board[ROW][COL], int row, int col)
{
  int i,j = 0;
  for (i = 0; i < ROW; i++)
  {
    for (j = 0; j < COL; j++)
    {
      if (board[i][j] == ' ')//有空格则不满足平局继续循环
      {
        return 0;
      }
    }
  }
  return 1;循环完未发现空格则返回1表示平局
}

当以上步骤完成时,我们代入主体的game函数中进行逻辑组装,如下:

void game()
{
  char board[ROW][COL] = { 0 };
  Printboard(board, ROW, COL); //初始化棋盘
  Display(board, ROW, COL);//打印棋盘
  char ret = 0;
  while (1)//循环以持续游戏进行
  {
    player(board, ROW, COL);//玩家先走
    ret = winor(board, ROW, COL);//进入结果判断
    if (ret != 'c')//非“继续”结果跳出
    {
      break;
    }
    x_man(board, ROW, COL);//人机后走
    ret = winor(board, ROW, COL);//再次判断
    if (ret != 'c')
    {
      break;
    }
  }
    if (ret == 'p')
      printf("平局!\n");
    else if (ret == '*')
      printf("你赢了!\n");
    else
      printf("你输了\n");//返回值对应判断三种游戏结果
}

战略总览👏

整个游戏到这里就完成了,给整理出来完整的工程如下:

test.c👏

# include"game.h"
void menu()
{
printf("------------------------------------\n");
printf("------------------------------------\n");
printf("-------1.P    L    A    Y-----------\n");
printf("-------0.E    X    I    T-----------\n");
printf("------------------------------------\n");
printf("------------------------------------\n");
}
void game()
{
  char board[ROW][COL] = { 0 };
  Printboard(board, ROW, COL); 
  Display(board, ROW, COL);
  char ret = 0;
  while (1)
  {
    player(board, ROW, COL);
    ret = winor(board, ROW, COL);
    if (ret != 'c')
    {
      break;
    }
    x_man(board, ROW, COL);
    ret = winor(board, ROW, COL);
    if (ret != 'c')
    {
      break;
    }
  }
    if (ret == 'p')
      printf("平局!\n");
    else if (ret == '*')
      printf("你赢了!\n");
    else
      printf("你输了\n");
}
void test()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu();
    printf("请选择菜单:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
    {
      printf("三子棋\n");
        game();
      break;
    }
    case 0:
    {
      printf("即将退出……");
      break;
    }
    default:
    {
      printf("玩儿呢?\n");
      break;
    }   
    }
  } while (input);
}
int main()
{
  test();
  return 0;
}

game.c👏

# define _CRT_SECURE_NO_WARNINGS 
# include"game.h"
void Printboard(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 Display(char board[ROW][COL], int row, int col)
{
  int i, 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 player(char board[ROW][COL], int row, int col)//玩家
{
  int x = 0;
  int y = 0;
  printf("玩家请输入棋子坐标:>");
  scanf("%d%d", &x, &y);
  while (1)
  {
    if (row >= x && x >= 1 && y >= 1 && y <= col)
    {
      if (board[x - 1][y - 1] == ' ')
      {
        board[x - 1][y - 1] = '*';
        Display(board, row, col);
        break;
      }
      else
      {
        printf("无效棋格,请重新输入\n");
        break;
      }
      }
         else
    {
      printf("你下到棋盘外了!\n");
    }
  }
}
void x_man(char board[ROW][COL], int row, int col)//人机
{
  int x = 0;
  int y = 0;
  printf("电脑走:\n");
  while(1)
  {
    x = rand() % ROW;
    y = rand() % COL;  //0~2
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      Display(board, row, col);
      break;
    } 
  } 
}
int Full(char board[ROW][COL], int row, int col)
{
  int i,j = 0;
  for (i = 0; i < ROW; i++)
  {
    for (j = 0; j < COL; j++)
    {
      if (board[i][j] == ' ')
      {
        return 0;
      }
    }
  }
  return 1;
}
char winor(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][1];
    }
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    {
      return board[1][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 (1==Full(board, row, col))
    {
      return  'p';
    }
    return 'c';
}

game.h👏

#pragma once
# define ROW 3
# define COL 3
# include<stdio.h>
# include<stdlib.h>
# include<time.h>
void game();
void Printboard(char board[ROW][COL], int row, int col);
void menu();
void Display(char board[ROW][COL], int row, int col);
void player(char board[ROW][COL], int row, int col);
void x_man(char board[ROW][COL], int row, int col);
char winor(char board[ROW][COL], int row, int col);

运行结果如下:


image.png


相关文章
|
C语言
从零到一快速学会三子棋
从零到一快速学会三子棋
67 1
|
C语言
C项目(三子棋BUG解决)
C项目(三子棋BUG解决)
55 0
|
C语言
【小朋友的三子棋】
【小朋友的三子棋】
71 0
设计一个三子棋游戏(下)
设计一个三子棋游戏(下)
|
算法
设计一个三子棋游戏(上)
设计一个三子棋游戏(上)
|
小程序 程序员 C++
超简单的三子棋,万字大文(保姆级讲解)上
超简单的三子棋,万字大文(保姆级讲解)
65 0
超简单的三子棋,万字大文(保姆级讲解)下
超简单的三子棋,万字大文(保姆级讲解)
45 0
|
程序员 C语言
趣味益智小游戏 三子棋+五子棋 优化版(可任意选择棋盘大小)
趣味益智小游戏 三子棋+五子棋 优化版(可任意选择棋盘大小)
117 0
自创三子棋,拓展版
自创三子棋,拓展版
42 0