智能三子棋——保姆级教学。

简介: 智能三子棋——保姆级教学。

序言:

想必三子棋大家都玩过吧,回想起小时候在地上用石头画上线,有的用石子儿,有的用树枝,下三子棋,都能玩一天。现在回想起来都是满满的回忆呀。今天带着大家来用C语言,来实现模拟实现一下三子棋游戏,来帮大家找一找童年的记忆。下面进入正题:


一.整体思路

我们三子棋主要实现的原理是,利用字符打印出一个棋盘,用二维数组存储我们下的棋子。先给大家看看什么样的。


f3b5f37be82746a5bd2ca0b634aeed43.png


大致就是这个样子。


然后一步一步下棋,每下一步,我们就把棋盘打印一边。


二.加载逻辑

首先每次游戏开始我们都需要一个菜单:


bd1c3e97eb444d97842a85c4746dab3c.png


菜单代码:

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

游戏的加载逻辑,我们希望可以选择游戏开始或者退出,也不是玩完一局就没有了,而是玩完一局以后还可以继续选择玩或者不玩,只有我们选组退出时,程序才会结束。

代码:

void game()
{
    printf("三子棋\n");
}
int main()
{
  int input = 0;
  do
  {
    menu();
    printf("请输入选项:>\n");
    scanf("%d", &input);
    printf("\n");
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入错误,请重新输入:>\n");
      break;
    }
  } while (input);
  return 0;
}

运行效果:



设置好游戏的加载逻辑以后,后面的游戏内容就全部在game()函数里面完成。并且我们为了是程序模块化,我们将主函数放到main.c文件里面,函数声明,头文件,宏等,我们就放在game.h文件里面,函数的具体实现我们统统放在,game.c文件里面。这样我们的整体程序就会非常有序,可读性提高。


三.棋盘布置



我们使用宏常量来,规定棋盘的大小 :

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 3
#define LIN 3
#include<stdio.h>
void menu();
void game();
void game()
{
  //创建二维数组
  char chess[ROW][LIN] = { 0 };
  //初始化用来装棋子的二维数组
  init_board(chess,ROW,LIN);
  //打印棋盘
  print_board(chess,ROW,LIN);
}
void init_board(char chess[ROW][LIN], int row, int lin)
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < lin; j++)
    {
      //二维数组全部初始化位空格
      chess[i][j] = ' ';
    }
  }
}
void print_board(char chess[ROW][LIN],int row,int lin)
{
  for (int i = 0; i <  row; i++)
  {
    for (int j = 0; j < lin; j++)
    {
      //空格 + 棋子 + 空格 + | ,为一组,一共
      //需要 lin 组,但是最后一组不需要 |
      printf(" %c ",chess[i][j]);
      //控制最后一个 | 不打印
      if (j < row - 1)
      {
        printf("|");
      }
    }
    //换行
    printf("\n");
    //   |   |   
    //---|---|---
    //为一组,一共需要 row 组,但是最后一组,不需要 ---|---|---
    if (i < lin - 1)
    {
      for (int j = 0; j < row; j++)
      {
        // ---| 为一组,一共 row 组,最后一组不需要打印 |
        printf("---");
        if (j < row - 1)
        {
          printf("|");
        }
      }
    }
    printf("\n");
  }
}

运行效果:



四.下棋

下棋的主要逻辑实现就是,封装两个函数player_chess()用来表示玩家下棋和电脑下棋computer_board(),玩家输入坐标,并将玩家代表的棋子存入棋盘的二维数组里面,电脑下棋先给他设置成随机下棋,然后每次下完一颗棋子我们就打印一下整个棋盘。我们需要一直下棋,每下一颗棋子都有可能出现胜利的一方,封装一个函数is_win()用来判断是否又人赢了,所以需要每下一颗棋子就需要判断一下是否又赢得玩家,如果又赢得玩家就直接is_win直接返回胜利者的棋子,如果没有人赢就返回‘C’代表继续,如果棋盘已经满了,就返回‘Q’代表平局。

void game()
{
  char set;
    //随机数生成器
  srand((unsigned int)time(NULL));
  //创建二维数组
  char chess[ROW][LIN] = { 0 };
  //初始化用来装棋子的二维数组
  init_board(chess,ROW,LIN);
  //打印棋盘
  print_board(chess,ROW,LIN);
  while (1)//一直循环,直到结果出现输赢,或者平局
  {
        //玩家下棋
    player_chess(chess, ROW, LIN );
        //打印棋盘
    print_board(chess, ROW, LIN);
        //判断结果
    set=is_win(chess,ROW,LIN);
    if ('C' != set)
    {
      break;
    }
        //电脑下棋
    computer_board(chess, ROW, LIN);
        //打印棋盘
    print_board(chess, ROW, LIN);
        //判断结果
    set = is_win(chess, ROW, LIN);
    if ('C' != set)
    {
      break;
    }
  }
    //如果返回的是玩家代表的棋子,
  if (set == '*')
  {
    printf("恭喜你,你赢了!!\n");
  }
    //如果返回的是电脑代表的棋子
  else if ('#' == set)
  {
    printf("电脑赢了!!\n");
  }
    //如果是平局
  else if ('Q' == set)
  {
    printf("平局\n");
  }
}
void player_chess(char chess[ROW][LIN], int row, int lin)
{
    //计数玩家棋子数量
  count_board++;
    //坐标
  int x = 0;
  int y = 0;
  while (1)
  {
    printf("请输入棋子坐标:>");
    scanf("%d %d", &x, &y);
        //判断坐标合理性,是否在棋盘内
    if (x >= 1 && x <= row && y >= 1 && y <= lin)
    {
            //坐标位置是否为空
      if (chess[x-1][y-1] == ' ')
      {
        chess[x-1][y-1] = '*';
        break;
      }
      else
      {
        printf("该位置已有棋子\n");
      }
    }
    else
    {
      printf("棋子坐标错误,请重新输入\n");
    }
  }
}
void computer_board(char chess[ROW][LIN], int row, int lin)
{
  while (1)//直到找好位置循环结束。
  {
        //随机数生成,0~2
    int x = rand()%row;
    int y = rand()%lin;
        //判断是否该位置为空,
    if (chess[x][y] == ' ')
    {
      chess[x][y] = '#';
      break;
    }
  }
}

判断是否有玩家赢is_win()

//判断棋盘是否满了
int is_full(char chess[ROW][LIN], int row, int lin)
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < lin; j++)
    {
      if (chess[i][j] == ' ')
      {
        return 0;
      }
    }
  }
  return 1;
}
char is_win(char chess[ROW][LIN], int row, int lin)
{
    //横着判断是否有三个一样的
  for (int i = 0; i < row; i++)
  {
    if (chess[i][0] == chess[i][1] && 
            chess[i][1] == chess[i][2] &&
            chess[i][0]!=' ')
    {
      return chess[i][0];
    }
  }
    //竖着判断是否有三个一样的
  for (int i = 0; i < lin; i++)
  {
    if (chess[0][i] == chess[1][i] && 
            chess[1][i] == chess[2][i] && 
            chess[0][i] != ' ')
    {
      return chess[0][i];
    }
  }
    //斜着判断是否有三个一样的
  if (chess[0][0] == chess[1][1] && 
        chess[1][1] == chess[2][2] && 
        chess[0][0] != ' ')
  {
    return chess[0][0];
  }
    //斜着判断是否有三个一样的
  if (chess[0][2] == chess[1][1] && 
        chess[1][1] == chess[2][0] && 
        chess[0][2] != ' ')
  {
    return chess[0][2];
  }
    //判断棋盘是否满了
  int tmp = is_full(chess, ROW, LIN);
  if (tmp == 1)
  {
    return 'Q';
  }
  return 'C';
}

这样我们三子棋的主要逻辑就实现了



五.智能化

但是大家发现这电脑傻了吧唧的,现在我们就给他智能化,但是智能化的程度取决于设计者。分析那些情况优先的,就像当你电脑还差一颗棋子就可以赢了,这就是最先考虑的情况,其次是当对手还差一颗棋子赢了,还有电脑下一颗可以达成两颗棋子的领先情况,等等还有一些情况小编不好分析,就不多介绍了。


void computer_board(char chess[ROW][LIN], int row, int lin)
{
  //差一棋子,优先下(1)
  for (int i = 0; i < row; i++)
  {
    if (chess[i][0] == chess[i][1] && chess[i][0] == '#'&& chess[i][2] == ' ')
    {
      chess[i][2] = '#';
      return;
    }
    if (chess[i][0] == chess[i][2] && chess[i][0] == '#'&& chess[i][1] == ' ')
    {
      chess[i][1] = '#';
      return;
    }
    if (chess[i][1] == chess[i][2] && chess[i][1] == '#'&& chess[i][0] == ' ')
    {
      chess[i][0] = '#';
      return;
    }
  }
  //差一棋子,优先下(2)
  for (int i = 0; i < lin; i++)
  {
    if (chess[0][i] == chess[1][i] && chess[0][i] == '#'&& chess[2][i]==' ')
    {
      chess[2][i] = '#';
      return;
    }
    if (chess[0][i] == chess[2][i] && chess[0][i] == '#'&&chess[1][i] == ' ')
    {
      chess[1][i] = '#';
      return;
    }
    if (chess[1][i] == chess[2][i] && chess[1][i] == '#'&& chess[0][i] == ' ')
    {
      chess[0][i] = '#';
      return;
    }
  }
  //差一棋子,优先下(3)
  if (chess[0][0] == chess[1][1] && chess[0][0] == '#' && chess[2][2] == ' ')
  {
    chess[2][2] = '#';
    return;
  }
  if (chess[0][0] == chess[2][2] && chess[0][0] == '#' && chess[1][1] == ' ')
  {
    chess[1][1] = '#';
    return;
  }
  if (chess[2][2] == chess[1][1] && chess[1][1] == '#' && chess[0][0] == ' ')
  {
    chess[0][0] = '#';
    return;
  }
  //差一棋子,优先下(4)
  if (chess[0][2] == chess[1][1] && chess[0][2] == '#' && chess[2][0] == ' ')
  {
    chess[2][0] = '#';
    return;
  }
  if (chess[0][2] == chess[2][0] && chess[0][2] == '#' && chess[1][1] == ' ')
  {
    chess[1][1] = '#';
    return;
  }
  if (chess[2][0] == chess[1][1] && chess[1][1] == '#' && chess[0][2] == ' ')
  {
    chess[0][2] = '#';
    return;
  }
  //对方差一棋子胜利,优先下(5)
  for (int i = 0; i < row; i++)
  {
    if (chess[i][0] == chess[i][1] && chess[i][0] == '*' && chess[i][2] == ' ')
    {
      chess[i][2] = '#';
      return;
    }
    if (chess[i][0] == chess[i][2] && chess[i][0] == '*' && chess[i][1] == ' ')
    {
      chess[i][1] = '#';
      return;
    }
    if (chess[i][1] == chess[i][2] && chess[i][1] == '*' && chess[i][0] == ' ')
    {
      chess[i][0] = '#';
      return;
    }
  }
  //对方差一棋子胜利,优先下(6)
  for (int i = 0; i < lin; i++)
  {
    if (chess[0][i] == chess[1][i] && chess[0][i] == '*' && chess[2][i] == ' ')
    {
      chess[2][i] = '#';
      return;
    }
    if (chess[0][i] == chess[2][i] && chess[0][i] == '*' && chess[1][i] == ' ')
    {
      chess[1][i] = '#';
      return;
    }
    if (chess[1][i] == chess[2][i] && chess[1][i] == '*' && chess[0][i] == ' ')
    {
      chess[0][i] = '#';
      return;
    }
  }
  //对方差一棋子胜利,优先下(7)
  if (chess[0][0] == chess[1][1] && chess[0][0] == '*' && chess[2][2] == ' ')
  {
    chess[2][2] = '#';
    return;
  }
  if (chess[0][0] == chess[2][2] && chess[0][0] == '*' && chess[1][1] == ' ')
  {
    chess[1][1] = '#';
    return;
  }
  if (chess[2][2] == chess[1][1] && chess[1][1] == '*' && chess[0][0] == ' ')
  {
    chess[0][0] = '#';
    return;
  }
  //对方差一棋子胜利,优先下(8)
  if (chess[0][2] == chess[1][1] && chess[0][2] == '*' && chess[2][0] == ' ')
  {
    chess[2][0] = '#';
    return;
  }
  if (chess[0][2] == chess[2][0] && chess[0][2] == '*' && chess[1][1] == ' ')
  {
    chess[1][1] = '#';
    return;
  }
  if (chess[2][0] == chess[1][1] && chess[1][1] == '*' && chess[0][2] == ' ')
  {
    chess[0][2] = '#';
    return;
  }
  //抢占先机,下完这一棋子,差一步胜利;(1)
  for (int i = 0; i < lin; i++)
  {
    if (chess[0][i] == '#' && chess[1][i] == ' ' && chess[2][i] == ' ')
    {
      chess[1][i] = '#';
      return;
    }
    if (chess[1][i] == '#' && chess[0][i] == ' ' && chess[2][i] == ' ')
    {
      chess[0][i] = '#';
      return;
    }
    if (chess[2][i] == '#' && chess[0][i] == ' ' && chess[1][i] == ' ')
    {
      chess[0][i] = '#';
      return;
    }
  }
  //抢占先机,下完这一棋子,差一步胜利;(2)
  for (int i = 0; i < row; i++)
  {
    if (chess[i][0] == '#' && chess[i][1] == ' ' && chess[i][2] == ' ')
    {
      chess[i][1] = '#';
      return;
    }
    if (chess[i][1] == '#' && chess[i][0] == ' ' && chess[i][2] == ' ')
    {
      chess[i][0] = '#';
      return;
    }
    if (chess[i][2] == '#' && chess[i][0] == ' ' && chess[i][1] == ' ')
    {
      chess[i][0] = '#';
      return;
    }
  }
  //抢占先机,下完这一棋子,差一步胜利;(3)
  if (chess[0][0] == '#' && chess[1][1] == ' ' && chess[2][2] == ' ')
  {
    chess[1][1] = '#';
    return;
  }
  if (chess[0][0] == ' ' && chess[1][1] == '#' && chess[2][2] == ' ')
  {
    chess[2][2] = '#';
    return;
  }
  if (chess[0][0] == ' ' && chess[1][1] == ' ' && chess[2][2] == '#')
  {
    chess[0][0] = '#';
    return;
  }
  //抢占先机,下完这一棋子,差一步胜利;(4)
  if (chess[0][2] == '#' && chess[1][1] == ' ' && chess[2][0] == ' ')
  {
    chess[1][1] = '#';
    return;
  }
  if (chess[0][2] == ' ' && chess[1][1] == '#' && chess[2][0] == ' ')
  {
    chess[0][2] = '#';
    return;
  }
  if (chess[0][2] == ' ' && chess[1][1] == ' ' && chess[2][0] == '#')
  {
    chess[0][2] = '#';
    return;
  }
  //第一步棋子,针对
  if (count_board == 1 && chess[0][0] == '*')
  {
    chess[2][2] = '#';
    return;
  }
  if (count_board == 1 && chess[0][2] == '*')
  {
    chess[2][0] = '#';
    return;
  }
  if (count_board == 1 && chess[2][0] == '*')
  {
    chess[0][2] = '#';
    return;
  }
  if (count_board == 1 && chess[2][2] == '*')
  {
    chess[0][0] = '#';
    return;
  }
  while (1)
  {
    int x = rand()%row;
    int y = rand()%lin;
    if (chess[x][y] == ' ')
    {
      chess[x][y] = '#';
      break;
    }
  }
}

最后展示成果:




这里我就已经输了,哈哈哈。


最后:

坚守之心就是不为苦难所惧。苦难是成功的磨刀石,是对人的胆识、智慧和毅力的考验。生活的道 路不是一帆风顺的,往往荆棘丛生。不少人就是迈不过这道坎,害怕、退缩、放弃、变向,结果只 能与成功失之交臂。努力成为你最喜欢的那种人,就算不成功,至少你会喜欢这样努力的自己。加油,诸君,山顶见!!!


相关文章
|
8月前
三子棋(井字棋) 保姆级详解
三子棋(井字棋) 保姆级详解
|
1月前
|
安全 C语言
C语言设计扫雷(保姆级教学)
C语言设计扫雷(保姆级教学)
C语言设计扫雷(保姆级教学)
|
1月前
|
人工智能 算法 机器人
Scratch3.0——助力新进程序员理解程序(难度案例三、五子棋双人对战-电脑需要AI写不出来)
Scratch3.0——助力新进程序员理解程序(难度案例三、五子棋双人对战-电脑需要AI写不出来)
85 0
|
1月前
|
存储
扫雷游戏的实现以及具体分析(保姆级教学)
扫雷游戏的分析和设计、扫雷游戏的文字描述、开始前的准备---多文件的创建、开始实操、扫雷游戏的扩展
|
8月前
|
机器学习/深度学习
【扫雷】初级版保姆级教学
【扫雷】初级版保姆级教学
|
8月前
|
人工智能
多子棋游戏的玩法设计
多子棋游戏的玩法设计
|
10月前
|
小程序 C语言
超详细三子棋(保姆级教学)
三子棋是一款古老的民间传统游戏,又被称为黑白棋、圈圈叉叉棋、井字棋、一条龙、九宫棋等,想必大家都有玩过吧。没玩过的话也可以试着玩一玩,这样对写三子棋这个小游戏的化是会有一个很好的思路的。那么本篇博客就来介绍如何用C语言来实现三子棋小游戏的具体步骤。(编译器用的是VS2019)
|
11月前
|
C语言
头歌c语言实训项目-综合案例课外练习:火柴游戏
头歌c语言实训项目-综合案例课外练习:火柴游戏
111 0
|
11月前
超简单的三子棋,万字大文(保姆级讲解)下
超简单的三子棋,万字大文(保姆级讲解)
29 0
|
11月前
|
小程序 程序员 C++
超简单的三子棋,万字大文(保姆级讲解)上
超简单的三子棋,万字大文(保姆级讲解)
43 0