热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

C语言手把手教你实现贪吃蛇AI(上)

这篇文章主要介绍了C语言手把手教你实现贪吃蛇AI,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了手把手教你实现贪吃蛇AI的具体步骤,供大家参考,具体内容如下

1. 目标

        编写一个贪吃蛇AI,也就是自动绕过障碍,去寻找最优路径吃食物。

2. 问题分析

        为了达到这一目的,其实很容易,总共只需要两步,第一步抓一条蛇,第二步给蛇装一个脑子。具体来说就是,首先我们需要有一条普通的贪吃蛇,也就是我们常玩儿的,手动控制去吃食物的贪吃蛇;然后给这条蛇加入AI,也就是通过算法控制,告诉蛇怎么最方便的绕开障碍去吃食物。为了讲清楚这个问题,文章将分为三部分:上,写一个贪吃蛇程序;中,算法基础(需要运用到什么算法);下,运用算法基础中的算法编写一个贪吃蛇AI。

        在动手写贪吃蛇之前,我们需要想清楚以下几个问题,就非常容易了:
        a. 蛇身。由于蛇在吃食物的过程中会不断的长大,所以很适合用单链表表示,并且吃食物的过程就是用头插法插入元素的过程
        b. 食物。食物直接用随机生成函数,随机生成食物,但是需要检查,所生成的食物的位置不可以和蛇身重合
        c. 显示。我们需要实时的显示出蛇身的移动,但事实上,我们不用每次都打印整个蛇身,因为蛇身每走一步,仅仅是蛇头和蛇尾的位置移动一格,其他的地方都没有变化,所以只需要打印一个新的蛇头,并把蛇尾的位置抹掉,那么视觉效果就是蛇身先前移动了一格,这个过程中,我们需要用到SetConsoleCursorPosition(),将光标移到到指定的位置(比如蛇尾),完成相应的操作(比如打印空格抹掉蛇尾)
        d.控制。我们需要用键盘来控制蛇身的移动,这个程序中是利用上下左右方向键来实现的,这里需要用到GetAsyncKeyState(),来实时监测按键的状态

3. 运行效果

 

4. 源代码

        总共由三个文件组成gluttonous.h,source.c & main.cpp。由于这个贪吃蛇是用于后面加AI,所以并没有加入一些错误检测,比如是否撞到边界,是否撞到蛇身等。
需要注意的是,这个程序中用到了比较特殊的字符('■')来表示游戏空间的边界,在VS2013中可以正常编译,但是在codeblock中会乱码。
        另外还有一点容易混淆的是,我们通常都是用(x,y)坐标表示第x行,第y列,但是在SetConsoleCursorPosition(x,y)中,表示把光标移动到第y行,第x列

4.1 gluttonous.h

#ifndef SNAKE_H_ 
#define SNAKE_H_ 
#include 
#include //SetConsoleCursorPosition, sleep函数的头函数 
#include //time()的头函数 
#include  //malloc()的头函数 
#define N 32 //地图大小 
#define snake_mark '#'//表示蛇身 
#define food_mark '$' 
#define sleeptime 500 
 
/*表示蛇身坐标的结构体*/ 
typedef struct SNAKE{ 
  int x; //行坐标 
  int y; //列坐标 
  struct SNAKE* next; 
}snake_body, *psnake; 
extern psnake food; 
 
typedef enum Direction{ 
  U,D,L,R} direction;//蛇头的朝向 
extern direction snake_direction; 
 
void set_cursor_position(int x, int y); 
void initial_map(); 
psnake initial_snake(); 
void create_food(psnake snake,psnake food); 
void printe_map(psnake snake, psnake food); 
int is_food(psnake snake_head, psnake food); 
int is_boundary(psnake snake_head, psnake food); 
int is_snakebody(psnake snake_head, psnake food); 
psnake snake_move(psnake sanke, psnake food); 
void control_snake(); 
#endif 

4.2 source.cpp

#include"gluttonous.h" 
 
void set_cursor_position(int x, int y) 
{ 
  COORD coord = { x, y };//x表示列,y表示行。 
  SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); 
} 
 
/*初始化后的地图为 N列 N/2行*/ 
/*游戏的空间为2至N+1列,1至N/2行*/ 
void initial_map() 
{ 
  int i = 0; 
   
  //打印上下边框(每个■占用一行两列) 
  for (i = 0; ix = i; 
  (snake)->y = j; 
  (snake)->next = NULL; 
  tsnake = snake; 
 
  for (i = 4; i >2; i--) 
  { 
    temp = (psnake)malloc(sizeof(snake_body)); 
    (temp)->x = i; 
    (temp)->y = j; 
    (temp)->next = NULL; 
    (tsnake)->next = (temp); 
    (tsnake) = (tsnake)->next; 
  } 
  return snake; 
} 
 
void create_food(psnake snake, psnake food) 
{ 
  static int i=1; 
  psnake head = snake; 
  srand((unsigned)time(NULL)); 
  food->x = rand() % N + 2; 
  food->y = rand() % (N/2) + 1; 
 
  //检查食物是否和蛇身重回 
  while (head) 
  { 
    if (head->x == food->x && head->y == food->y) 
    { 
      free(food); 
      food = NULL; 
      create_food(snake,food); 
    } 
    else 
    { 
      head = head->next; 
    } 
  } 
} 
 
void printe_map(psnake snake, psnake food) 
{ 
  psnake temp=snake; 
  while (temp) 
  { 
    set_cursor_position(temp->x, temp->y); 
    printf("%c",snake_mark); 
    temp = temp->next; 
  } 
  if (food) 
    set_cursor_position(food->x,food->y ); 
  printf("%c",food_mark); 
  set_cursor_position(0, N/2+2); 
} 
 
//判断是否吃到食物,吃到食物返回 1,否则返回 0; 
int is_food(psnake snake_head, psnake food) 
{ 
  if (snake_head->x == food->x && snake_head->y == food->y) 
    return 1; 
  return 0; 
} 
 
//判断是否撞到墙,撞到墙返回 1,否则返回 0; 
int is_boundary(psnake snake_head) 
{ 
  if (snake_head->y <= 0 || snake_head->y >= N / 2 + 1 || snake_head->x <= 1 || snake_head->x >= N + 1) 
    return 1; 
  return 0; 
} 
 
//判断是否撞到自己,撞到自己返回 1,否则返回 0; 
int is_snakebody(psnake snake_head) 
{ 
  psnake temp=snake_head->next; 
  while (temp) 
  { 
    if (snake_head->x == temp->x && snake_head->y == temp->y) 
      return 1; 
    else 
      temp = temp->next; 
  } 
  return 0; 
} 
 
//将蛇身移动到合适的位置,并打印出来 
psnake snake_move(psnake snake, psnake food) 
{ 
  psnake snake_head = (psnake)malloc(sizeof(snake_body)); 
  if (snake_direction == U) 
  { 
    snake_head->y = snake->y-1; 
    snake_head->x = snake->x; 
    snake_head->next = snake; 
  } 
  else if (snake_direction == D) 
  { 
    snake_head->y = snake->y + 1; 
    snake_head->x = snake->x; 
    snake_head->next = snake; 
  } 
  else if (snake_direction == L) 
  { 
    snake_head->y = snake->y; 
    snake_head->x = snake->x - 1; 
    snake_head->next = snake; 
  } 
  else if (snake_direction == R) 
  { 
    snake_head->y = snake->y; 
    snake_head->x = snake->x + 1; 
    snake_head->next = snake; 
  } 
 
  if (is_food(snake_head, food))//如果是食物 
  { 
    create_food(snake_head, food); 
    printe_map(snake_head, food); 
  } 
  else if (is_boundary(snake_head) == 0 && is_snakebody(snake_head) == 0)//不是食物,不是边界,也不是蛇身 
  { 
    psnake temp = snake_head; 
    while (temp->next->next)//寻找蛇尾 
    { 
      temp = temp->next; 
    } 
    set_cursor_position(temp->next->x, temp->next->y); 
    printf(" ");//把蛇尾用空格消掉 
    free(temp->next);//释放蛇尾的内存空间 
    temp->next = NULL;//将temp的next置成NULL 
    printe_map(snake_head, food); 
  } 
  else 
  { 
    free(snake_head); 
    snake_head = NULL; 
  } 
  return snake_head; 
} 
 
void control_snake() 
{ 
  if (GetAsyncKeyState(VK_UP) && snake_direction != D) 
  { 
    snake_direction = U; 
  } 
  else if (GetAsyncKeyState(VK_DOWN) && snake_direction != U) 
  { 
    snake_direction = D; 
  } 
  else if (GetAsyncKeyState(VK_LEFT) && snake_direction != R) 
  { 
    snake_direction = L; 
  } 
  else if (GetAsyncKeyState(VK_RIGHT) && snake_direction != L) 
  { 
    snake_direction = R; 
  } 
}

4.3 main.cpp

#include"gluttonous.h" 
direction snake_direction; 
psnake food; 
 
int main(void) 
{ 
  psnake snake; 
 
  initial_map(); 
  snake=initial_snake(); 
  food = (psnake)malloc(sizeof(snake_body)); 
  food->next = NULL; 
  create_food(snake, food); 
  printe_map(snake, food); 
  snake_direction = R; 
  while (1) 
  { 
    Sleep(sleeptime); 
    control_snake(); 
    snake=snake_move(snake, food); 
  } 
  return 0; 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 非公版RTX 3080显卡的革新与亮点
    本文深入探讨了图形显卡的进化历程,重点介绍了非公版RTX 3080显卡的技术特点和创新设计。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • Valve 发布 Steam Deck 的新版 Windows 驱动程序
    Valve 最新发布了针对 Steam Deck 掌机的 Windows 驱动程序,旨在提升其在 Windows 环境下的兼容性、安全性和性能表现。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 在 Windows 10 中,F1 至 F12 键默认设置为快捷功能键。本文将介绍几种有效方法来禁用这些快捷键,并恢复其标准功能键的作用。请注意,部分笔记本电脑的快捷键可能无法完全关闭。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
author-avatar
本来就是哦
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有