井字棋版本1.0(对抗人工智障)

简介: 井字棋版本1.0(对抗人工智障)

目录


前言

❤️ :热爱编程学习,期待一起交流!

🙏:博主水平有限,如有发现错误,求告知,多谢!


我们先认识一下本章涉及的英文单词。

row:一行; 一排; ;

col:一列;

Init:初始化

InitBoard:初始化棋盘

DisplayBoard:展览棋盘;展出棋盘;

井字棋又称三子棋。此游戏是对前面C语言知识学习的综合应用,主要包括 函数、数组、的应用。可以算是对前面所学知识的复习巩固,以及形成知识的输出。

相信大家也玩过井字棋,甚至熟练掌握井字棋的棋法并且百战百胜。是的,这就是我的1.0版本,对抗人工智障,你将百战百胜。由于博主知识暂时有限,不能写出一个具有战略头脑的电脑玩家与你斗智斗勇。只能设计出一个胡乱下棋的电脑玩家。没错,就是胡乱下的。但是经过我后期的学习一定会对这个游戏进行优化。




游戏设计思路

这里我们把这个游戏项目整体上分为三个模块


头文件(game.h)c语言中头文件中一般定义了函数的声明、结构体的定义、宏定义。(常量和全局变量最好放到源文件中)

源文件(game.c)在这个源文件中我们放置一些函数。来将游戏的具体实现。 源文件(test.c)里面放主函数和游戏的整体功能。

这样写的好处可以不至于一个游戏直接在一个源文件写几百行,不能及时检查错误,而导致bug频出。

把游戏分为一个个的模块就可以提高代码的可读性,减少错误率。

我们规定人下的棋子为 “x”,电脑下的棋子为 “o”。


为了照顾没有设计过的朋友,在这里我会讲的详细一些。

先按照我们正常的思维来设计。

一、工欲善其事,必先利其器。我们首先需要先设计一个3 * 3的一个棋盘,如上图所示。

二、然后玩家先手下棋。

三、电脑下棋。

四、我们需要在第三个回合判断输赢(就是判断三个棋子是否在一条线上)

五、如果没有分出胜负,我们需要继续进行循环 – 步骤三、四、五。直到判断出输赢,或者平局。

现在我们用程序员的话翻译以上句子是什么意思。

一、生成一个3*3的二维数组,并将二维数组初始化后用符号打印出来。

二、运用二维数组输入两个数字定位棋子落下的位置。

三、运用rand函数生成随机数。对二维数组(即3*3的棋盘)进行遍历。if有空位,就下棋 *

四、判断二维数组上的行,列,十字相交,的位置是否构成一条线。

五、运用循环语句对此进行判断输赢,或平局。

生成菜单界面(do while)


玩过超级玛丽,或者魂斗罗的都知道。我们进入游戏的时候都有一个菜单界面,来选择玩游戏,或者退出游戏。因此在我们进行玩游戏之前,需要用do语句先生成一个菜单来进行选择。

void menu()
{
  printf("————1.play————\n");
  printf("————2.exit————\n");
}

初始化棋盘

宏定义:

  • 将3用ROW,COL代替。
  • 提高扩展性,如果将来要修改棋盘尺寸,代码修改会很方便。
#define ROW 3
#define COL 3

运用循环嵌套,对3 *3的二维数组进行遍历,实现9个格子都是空格。

void DisplayBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;//i 控制行数
  int j = 0;//j 控制列数
  for (i = 0; i < row; i++)//控制打印的行数
  {
    for (j = 0; j < col; j++)//控制每行的列数
    {
      printf(" %c ", board[i][j]);
        if (j < col - 1)//col为3,if(j<2),意思就是只打印棋盘的第一列和第二列。
          printf("|");
    }
    printf("\n");//每打印一行就需要换行
    if (i < row - 1)
    {
      for (j = 0; j < col; j++)
      {
        printf("---");
        if (j < col - 1)
          printf("+");
      }
    }
    printf("\n");
  }
}
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;//i 控制行数
  int j = 0;//j 控制列数
  for (i = 0; i < row; i++)//控制打印的行数
  {
    for (j = 0; j < col; j++)//控制每行的列数
    {
      printf(" %c ", board[i][j]);
        if (j < col - 1)//col为3,if(j<2),意思就是只打印棋盘的第一列和第二列。
          printf("|");
    }
    printf("\n");//每打印一行就需要换行
    if (i < row - 1)
    {
      for (j = 0; j < col; j++)
      {
        printf("---");
        if (j < col - 1)
          printf("+");
      }
    }
    printf("\n");
  }
}

如图所示


玩家下棋

  • 运用if的嵌套
void Player_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("请玩家输入(x y)坐标下棋:");
  while (1)
  {
    scanf("%d%d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)//对下棋位置进行约定,只能下到3*3的棋盘内。
    {
      if (board[x - 1][y - 1] == ' ')//x-1和y-1的写法就是因为对我们程序员来说数组的元素下标识从0开始的。
      {//数组通过下标来访问元素。但是玩家却不懂这个。所以要这么写。
        board[x - 1][y - 1] = 'x';
        break;
      }
      else
      {
        printf("坐标已被占用,请重新输入\n");
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
}


电脑下棋(随机数生成)

  • 随机数的生成.要在主函数中使用 srand((unsigned int)time(0))
  • 将time作为种子,保证时间的随机性。从而使棋子随机生成。


void Computer_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  while (1)
  {
    x = rand() % ROW;
    y = rand() % COL;
    if (board[x][y] == ' ')
    {
      board[x][y] = 'o';
      break;
    }
  }
}

判断输赢


  • 规定:
  • 返回‘Q’是平局
  • 返回‘c’是继续
  • 下面是判断三行,三列,还有十字相交是否相同,然后还要继续判断棋盘是否满了,最后才能判断是否输赢。
  • 判断棋盘满不满需要调用is_full函数。
char is_win(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][0] == board[i][2] && board[i][0] != ' ')
    {
      return board[i][0];
    }
  }
  for (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[0][2] == board[2][0] && board[0][2] != ' ')
  {
    return board[0][2];
  }
  if (1 == is_full(board, row, col))
  {
    return 'Q';
  }
  return 'c';
}


判断是否棋格满了

  • 对棋盘进行遍历,如果没有空格,就返回1,为真,则是棋盘满了,然后就返回Q来跳出循环。
int is_full(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;
}

游戏全部代码

game.h

#include<stdio.h>
#include<stdlib.h>
#include<time.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 Player_move(char board[ROW][COL], int row, int col);
void Computer_move(char board[ROW][COL], int row, int col);
char is_win(char board[ROW][COL], int row, int col);


test.c

#include "game.h"
void game()
{
  char board[ROW][COL] = { 0 };
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  char ret = 0;
  while (1)
  {
    system("cls");
    DisplayBoard(board, ROW, COL);
    Player_move(board, ROW, COL);
    ret = is_win(board, ROW, COL);
    if (ret != 'c')
    {
      break;
    }
    Computer_move(board, ROW, COL);
    ret = is_win(board, ROW, COL);
    if (ret != 'c')
    {
      break;
    }
  }
  printf("对抗结果如下:\n");
  DisplayBoard(board, ROW, COL);
  if (ret == 'x')
  {
    printf("恭喜你对抗人工智障1.0成功!!!\n");
    printf("再来一盘吧?\n");
    printf("\n");
  }
  else if (ret == 'o')
  {
    printf("不会吧?不会还有人玩不过电脑吧?\n");
    printf("再来一盘吧?\n");
    printf("\n");
  }
  else
  {
    printf("你竟然和电脑旗鼓相当!!!\n");
    printf("再来一盘吧?\n");
    printf("\n");
  }
}
void menu()
{
  printf("————1.play————\n");
  printf("————2.exit————\n");
}
void test()
{ 
  srand((unsigned int)time(NULL));
  int n = 0;
  do 
  {
    printf("开始游戏请选择输入1\n");
    menu();
    scanf("%d", &n);
    switch (n)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误请重新选择:\n");
      break;
    }
  }while (n);
}
int main()
{
  test();
  return 0;
}

game. c

#define _CRT_SECURE_NO_WARNINGS
#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;//i 控制行数
  int j = 0;//j 控制列数
  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_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("请玩家输入(x y)坐标下棋:");
  while (1)
  {
    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] = 'x';
        break;
      }
      else
      {
        printf("坐标已被占用,请重新输入\n");
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
}
void Computer_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  while (1)
  {
    x = rand() % ROW;
    y = rand() % COL;
    if (board[x][y] == ' ')
    {
      board[x][y] = 'o';
      break;
    }
  }
}
int is_full(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 is_win(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][0] == board[i][2] && board[i][0] != ' ')
    {
      return board[i][0];
    }
  }
  for (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[0][2] == board[2][0] && board[0][2] != ' ')
  {
    return board[0][2];
  }
  if (1 == is_full(board, row, col))
  {
    return 'Q';
  }
  return 'c';
}

游戏效果图

胜利

失败

  • 失败的截图可以自己下去试试哦。



最后,如果你觉得我的文章对你有帮助🎉欢迎关注🔎点赞👍收藏⭐️留言📝。


相关文章
|
3月前
|
机器学习/深度学习 数据采集 自然语言处理
揭秘深度学习的幕后英雄:如何用智慧和策略战胜训练中的怪兽!
【8月更文挑战第16天】深度学习之路坎坷,如攀险峰,每一步都考验耐心与智慧。超参数调试、数据质量、计算资源、过拟合及收敛难题是常遇挑战。通过网格搜索找最优、数据增强平衡样本、混合精度与梯度累积节省资源、正则化及Dropout防过拟合、以及使用高级优化器助收敛,这些问题得以缓解。每克服一个难关,都是向成功迈进一大步,同时也深化了对深度学习的理解与掌握。
42 4
|
人工智能 自然语言处理 搜索推荐
ChatGPT之后性能怪兽来了?马库斯7大「黑暗」预测:GPT-4带不来AGI
ChatGPT之后性能怪兽来了?马库斯7大「黑暗」预测:GPT-4带不来AGI
132 0
|
机器学习/深度学习 人工智能 计算机视觉
AI破解脑电波,准确率超80%!高度还原你眼中最美的ta
最近的一项研究发现,人工智能可以解读大脑信号,并将脑机接口和生成的人脸模型相结合,还原出高度符合个人审美的人脸图像。原来你的审美也被AI猜透了!
181 0
AI破解脑电波,准确率超80%!高度还原你眼中最美的ta
|
传感器 云安全 人工智能
让自动驾驶撞墙,刷别人的脸付账:最新的AI安全漏洞让我们开了眼界
那些专家们曾经担心过的 AI 算法漏洞是可以实现的,没想到过的也可以实现。
179 0
让自动驾驶撞墙,刷别人的脸付账:最新的AI安全漏洞让我们开了眼界
现实版“奇异博士”?原来是这款神秘的“数学黑盒”
现实版“奇异博士”?原来是这款神秘的“数学黑盒”
现实版“奇异博士”?原来是这款神秘的“数学黑盒”
|
机器学习/深度学习 人工智能 Go
谷歌发布“怪兽生成器”!你画草图,GAN帮你生成幻想生物
谷歌发布“怪兽生成器”!你画草图,GAN帮你生成幻想生物
660 0
|
人工智能 算法 安全
训练AI吞食垃圾 瀚蓝环境探索破解垃圾围城难题
阿里云研究院高级战略专家王岳表示,越是看似离 AI 技术遥远的行业,一旦与其发生化学反应,所产生的能量将会是巨大的。在未来相当长的时间,行业内专家与行业外数据科学家的跨界组合将会是推动工业智能落地的关键力量。
668 0
训练AI吞食垃圾 瀚蓝环境探索破解垃圾围城难题
|
人工智能 算法 安全
案例酷 | 机器人瓦力来了:训练AI吞食垃圾 瀚蓝环境探索破解垃圾围城难题
为摆脱对经验的过度依赖,瀚蓝环境意识到更高效的数字化手段是可行办法。通过将经验与数据中的隐性知识转化为显性知识,并嵌入到机器中,让机器协助人类来完成复杂焚烧过程的复杂决策与控制。但摆在眼前的问题是,垃圾焚烧领域鲜有数据科学家,懂行业机理模型的数据科学家更是凤毛麟角,行业算法处于空白。于是,瀚蓝环境找到阿里云工业大脑团队,希望借助其在数据与算法上的优势,加之与瀚蓝环境专家经验结合,共同开发垃圾焚烧工艺优化算法,优化垃圾焚烧的稳定性。 工业大脑落地场景的选择至关重要。数据可用性、风险可控、可实施、高收益与可复用是选择优先场景需要考虑的关键因素。
874 0
案例酷 | 机器人瓦力来了:训练AI吞食垃圾 瀚蓝环境探索破解垃圾围城难题
|
机器学习/深度学习 人工智能 算法
“精灵鼠小弟”成真!AI破解小鼠表情密码,证明150年前达尔文之问
日前,Science刊登了来自马普神经生物学研究所科学家的新研究:首次利用机器学习算法破译了小鼠的面部表情。不仅成功区分小鼠高兴、恐惧、恶心、疼痛等表情,还测量出对应情绪的强度。这项研究对精确定位人脑中表达特定情绪的神经元有着重要意义。
下一篇
无影云桌面