专栏首页编程学习基地程序员是怎么玩贪吃蛇的?

程序员是怎么玩贪吃蛇的?

前言

看别人玩贪吃蛇永远牛逼,自己玩永远菜鸡... http://mpvideo.qpic.cn/0bf224aayaaaoiah2vnkefqfbv6dbtlqadaa.f10002.mp4?dis_k=a12775a0d9e7c95e27a3c88acebf9ab7&dis_t=1622533515&spec_id=MzU5NjI2NzM5OA%3D%3D1622533515&vid=wxv_1882247247656976387&format_id=10002&support_redirect=1&mmversion=false

好久了,久到我都忘了我是怎么走过来的了...

正文

01 背景

设计的人工智能贪吃蛇是我初学寻路算法的时候胡乱捣鼓改的贪吃蛇代码,主要思路就是通过广度寻路算法,查找蛇头和食物之间是否有路,从而达到自动寻找食物的目的。

某次小学妹要做贪吃蛇的课题大作业,问我要贪吃蛇的代码我才想起还有个半成品的人工智能贪吃蛇。

向下滑动查看

当时奇思妙想的半成品,深度寻路算法学过数据结构都应该知道原理,就是实现的问题,如果没有需求我应该不会继续完善这个半成品了,吃力不讨好,要是谁能完善下就好了。

另外这是一个半成品,不是残次品,VS,VC6.0装Easyx能跑通的,可能就是这条蛇比较蠢,容易迷路...

此外,代码使用需谨慎,我加Sleep睡眠是有原因的,不要瞎改,出现任何无厘头状况一概与我无关...

代码如下: 或者发送关键字【人工智能贪吃蛇】获取

#include<iostream>
#include<easyx.h>
#include<time.h>
#include<vector>
#define MAP_ROW 48
#define MAP_COL 60

using namespace std;

enum sense  //场景
{
 SPACE, WALL, BODY, HEAD, FOOD
};

enum DIR    //方向
{
 UP, LEFT, DOWN, RIGHT
};

struct PathDate   //辅助数组
{
 bool isFind;
 int val;
 DIR dir;
};

struct MyPathNode    //做数据     构造 树
{
 COORD pos;                  //坐标
 MyPathNode* parent;           //父指针
 vector<MyPathNode*> child;    //子指针
};

vector<COORD> snack;  //蛇

sense map[MAP_ROW][MAP_COL];//地图

size_t score;

void init();      //初始化
void drawMap();   //画图
void addFood();   //添加食物
void search();    //寻找路
void clear(MyPathNode* &root);//清空树
void move(COORD point);   //移动到point处
bool isMove(PathDate arr[][MAP_COL],COORD pos);  //是否可以移动
int main()
{
 initgraph(640, 500);
 init();
 while (true)
 {
  drawMap();
  search();
 }
 getchar();
 closegraph();
 return 0;
}
void init()
{
 //设置随机种子
 srand((unsigned)time(NULL));
 //初始化地图数据
 memset(map, SPACE, sizeof(sense)*MAP_ROW*MAP_COL);
 for (int i = 0; i < MAP_ROW; i++)
 {
  map[i][0] = WALL;
  map[i][MAP_COL - 1] = WALL;
 }
 for (int i = 1; i < MAP_COL - 1; i++)
 {
  map[0][i] = WALL;
  map[MAP_ROW - 1][i] = WALL;
 }
 map[3][5] = map[3][4] = BODY;
 map[3][6] = HEAD;

 //添加 蛇 节点
 snack.push_back({ 3, 6 });
 snack.push_back({ 3, 5 });
 snack.push_back({ 3, 4 });
 //添加食物
 addFood();

 score = 0;
}
void drawMap()
{
 //开始批量绘图
 BeginBatchDraw();
 //设置背景颜色为白色
 setbkcolor(WHITE);
 //清屏
 cleardevice();

 WCHAR arr[10];
 wsprintf(arr, L"%d", score);
 settextcolor(BLACK);
 outtextxy(0, 0, L"Score:");
 outtextxy(50, 0, arr);

 //根据map[i][j]数值分类画图
 for (int x = 0; x < MAP_ROW; x++)
 {
  for (int y = 0; y < MAP_COL; y++)
  {
   switch (map[x][y])
   {
   case SPACE:
    break;
   case WALL:
    setlinecolor(BLACK);
    setfillcolor(RGB(238, 233, 233));
    fillrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
    break;
   case BODY:
    setlinecolor(RGB(0, 245, 255));//绿色 
    setfillcolor(WHITE);
    fillrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
    break;
   case HEAD:
    //画七彩蛇头
    switch (rand() % 7)
    {
    case 0:
     setfillcolor(RGB(255, 0, 0));//红色 255 0 0
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    case 1:
     setfillcolor(RGB(255, 165, 0));//橙  255 165 0 
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    case 2:
     setfillcolor(RGB(255, 255, 0));//黄  255 255 0
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    case 3:
     setfillcolor(RGB(0, 255, 0));//绿色  0, 255, 0
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    case 4:
     setfillcolor(RGB(0, 255, 255));//青  0 255 255
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    case 5:
     setfillcolor(RGB(0, 0, 255));//蓝  0 0 255
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    case 6:
     setfillcolor(RGB(160, 32, 240));//紫  160 32 240
     solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
     break;
    default:
     break;
    }
    break;
   case FOOD:
    setfillcolor(RGB(255, 0, 0));//红色
    solidrectangle(y * 10, x * 10 + 20, y * 10 + 10, x * 10 + 30);
    break;
   default:
    break;
   }
  }
 }
 EndBatchDraw();
}
void addFood()
{
 int row, col;
 do
 {
  row = rand() % (MAP_ROW - 1) + 1;     //1 ~ (MAP_ROW-1)
  col = rand() % (MAP_COL - 1) + 1;     //1 ~ (MAP_COL-1)
 } while (map[row][col] != SPACE);         //知道条件map[row][col]为空地
 map[row][col] = FOOD;                 
}
void search()
{
 //进行辅助数组初始化 及 起点终点设置
 COORD beginPoint, endPoint, tailPoint;
 PathDate pathMap[MAP_ROW][MAP_COL];
 for (int i = 0; i < MAP_ROW; i++)
 {
  for (int j = 0; j < MAP_COL; j++)
  {
   //由于广度搜索是从终点找起点 所以起点设置成终点
   if (map[i][j] == HEAD)
   {
    endPoint.X = i;     
    endPoint.Y = j;
   }
   if (map[i][j] == FOOD)
   {
    beginPoint.X = i;
    beginPoint.Y = j;
   }
   pathMap[i][j].val = map[i][j];
   pathMap[i][j].isFind = false;
   pathMap[i][j].dir = UP;
  }
 }
 //尾部坐标
 tailPoint = snack[snack.size() - 1];
 //表示起点已搜索
 pathMap[endPoint.X][endPoint.Y].isFind = true;
 //做数据  建立一个数据结构  设置根节点及其初始化
 MyPathNode*pRood = new MyPathNode;
 pRood->pos = beginPoint;
 pRood->parent = nullptr;

 vector<MyPathNode*> list;      //当前搜索层  
 vector<MyPathNode*> tempList;  //待搜索层

 list.push_back(pRood);         //根节点插入当前搜索层
 COORD tempPoint;               //搜索节点
 while (true)
 {
  for (int i = 0; i < (int)list.size(); i++)
  {
   for (int j = 0; j < 4; j++)
   {
    tempPoint = list[i]->pos;  //  搜索节点赋初值 根据该值确定搜索节点
    switch (j)
    {
    case UP:
     tempPoint.X--;
     break;
    case DOWN:
     tempPoint.X++;
     break;
    case LEFT:
     tempPoint.Y--;
     break;
    case RIGHT:
     tempPoint.Y++;
     break;
    default:
     break;
    }
    //如果待搜索节点是SPACE(空地)或者FOOD(食物)那么可以前进
    if (isMove(pathMap, tempPoint))
    {
     //初始化一个树节点
     MyPathNode*pNode = new MyPathNode;
     //初始化节点数据
     pNode->pos = tempPoint;
     //链接节点的辈分
     pNode->parent = list[i];
     list[i]->child.push_back(pNode);
     //已搜索该搜索节点
     pathMap[tempPoint.X][tempPoint.Y].isFind = true;
     //已搜索的节点放入待搜索层
     tempList.push_back(pNode);
     if (tempPoint.X == endPoint.X&&tempPoint.Y == endPoint.Y)
     {
      //表示找到终点
      MyPathNode *tempNode = pNode;
      while (tempNode)
      {
       tempNode = tempNode->parent;
       if (tempNode)
       {
        move(tempNode->pos);
       }  
      }
      addFood();
      goto LABLE;
     }
    }
   }
  }
  if (tempList.size() == 0)
  {
   MessageBox(GetHWnd(), L"寻路失败", L"提示", MB_OK | MB_ICONEXCLAMATION);
   exit(0);
   break;
  }
  list = tempList;
  tempList.clear();
 }
LABLE:
 return;
}
void clearTree(MyPathNode* &root)
{
 if (root)
 {
  for (size_t i = 0; i < root->child.size(); i++)
   clearTree(root->child[i]);
  delete root;
  root = nullptr;
 }
}
void move(COORD point)
{
 if (map[point.X][point.Y] == FOOD)
 {
  score++;
  snack.push_back(point);
  map[snack[0].X][snack[0].Y] = BODY;
  for (int i = snack.size() - 1; i > 0; i--)
  {
   snack[i].X = snack[i - 1].X;
   snack[i].Y = snack[i - 1].Y;
  }
  snack[0] = point;
  map[snack[0].X][snack[0].Y] = HEAD;
  drawMap();
  Sleep(100); //睡眠0.1s,不然吃的太快了
 }
 else if (map[point.X][point.Y] == SPACE)
 {
  map[snack[snack.size() - 1].X][snack[snack.size() - 1].Y] = SPACE;
  map[snack[0].X][snack[0].Y] = BODY;
  for (int i = snack.size() - 1; i > 0; i--)
  {
   snack[i].X = snack[i - 1].X;
   snack[i].Y = snack[i - 1].Y;
  }
  snack[0] = point;
  map[snack[0].X][snack[0].Y] = HEAD;
 } 
 drawMap();
 Sleep(10);
}
bool isMove(PathDate arr[][MAP_COL], COORD pos)
{
 if (pos.X >= 0 && pos.Y >= 0 && pos.X < MAP_ROW&&pos.Y < MAP_COL)
 {
  if (arr[pos.X][pos.Y].isFind == false && arr[pos.X][pos.Y].val == SPACE)
  {
   return true;
  }
  else if (arr[pos.X][pos.Y].val == FOOD || arr[pos.X][pos.Y].val == HEAD)
  {
   return true;
  } 
 }
 return false;
}

本文分享自微信公众号 - 编程学习基地(LearnBase),作者:DeRoy

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-05-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 程序员式贪吃蛇,URL贪吃蛇和源码贪吃蛇你值得一玩

    版权声明:本文为博主原创文章,未经博主允许不得转载。 ...

    业余草
  • 10分钟用 Python 编写一个贪吃蛇小游戏

    贪吃蛇,大家应该都玩过。当初第一次接触贪吃蛇的时候 ,还是能砸核桃的诺基亚上,当时玩的不亦乐乎。今天,我们用Python编程一个贪吃蛇游戏,下面我们先看看效果:

    逆锋起笔
  • 数据结构 第10讲 好玩贪吃蛇——数字矩阵

    rainchxy
  • 面向 python 小白的贪吃蛇游戏

    作为 python 小白,总是觉得自己要做好百分之二百的准备,才能开始写程序。以至于常常整天在那看各种语法教程,学了几个月还是只会print('hello wo...

    Python进阶者
  • 一步步教你怎么用python写贪吃蛇游戏

    前几天,星球有人提到贪吃蛇,一下子就勾起了我的兴趣,毕竟在那个Nokia称霸的年代,这款游戏可是经典中的经典啊!而用Python(蛇)玩Snake(贪吃蛇),那...

    诸葛青云
  • 牛得一批!10分钟用Python编写一个贪吃蛇小游戏

    贪吃蛇,大家应该都玩过。当初第一次接触贪吃蛇的时候 ,还是能砸核桃的诺基亚上,当时玩的不亦乐乎。今天,我们用Python编程一个贪吃蛇游戏,下面我们先看看效果:...

    龙哥
  • 算法应用实践:如何用Python写一个贪吃蛇AI

    这两天在网上看到一张让人涨姿势的图片,图片中展示的是贪吃蛇游戏, 估计大部分人都玩过。但如果仅仅是贪吃蛇游戏,那么它就没有什么让人涨姿势的地方了。 问题的关键在...

    IT派
  • 如何用Python写一个贪吃蛇AI

    这两天在网上看到一张让人涨姿势的图片,图片中展示的是贪吃蛇游戏, 估计大部分人都玩过。但如果仅仅是贪吃蛇游戏,那么它就没有什么让人涨姿势的地方了。 问题的关键在...

    哲洛不闹
  • 一步步教你怎么用python写贪吃蛇游戏

    前几天,星球有人提到贪吃蛇,一下子就勾起了我的兴趣,毕竟在那个Nokia称霸的年代,这款游戏可是经典中的经典啊!而用Python(蛇)玩Snake(贪吃蛇),那...

    Python进击者

扫码关注云+社区

领取腾讯云代金券