智能蛇

无AI版:

#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
//游戏窗口
#define FrameX 4   //游戏窗口左上角的X轴坐标
#define FrameY 4   //游戏窗口左上角的Y轴坐标
#define Frame_height  20 //游戏窗口的高度
#define Frame_width   20 //游戏窗口的宽度
//定义全局变量
int i,j;
int a[2];     //用于记住蛇尾坐标,其中a[0]、a[1]分别表示横、竖坐标
//声明蛇的结构体
struct Snake
{
 int x[100];    //蛇的横坐标,其中x[0]表示蛇尾的横坐标,x[N-1]表示蛇头的横坐标
 int y[100];    //蛇的竖坐标,其中y[0]表示蛇尾的竖坐标,y[N-1]表示蛇头的竖坐标
 int count;    //蛇吃食物的个数
 int length;    //蛇的长度
 int speed;    //蛇的速度
};
//声明食物的结构体
struct Food
{
 int x;     //食物的横坐标
 int y;     //食物的竖坐标
};

 void main()
{
 system("color 0D");  //设置文本为粉红色
 start_game();   //开始游戏
 over_game();   //结束游戏
}
/******光标移到指定位置**************************************************************/
void gotoxy(HANDLE hOut, int x, int y)
{
 COORD pos;
 pos.X = x;  //横坐标
 pos.Y = y;  //纵坐标
 SetConsoleCursorPosition(hOut, pos);
}
/******设置文本为绿色*****************************************************************/
void Set_TextColor_Green (void)
{ 
 HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);

 SetConsoleTextAttribute(Handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
}
/******制作游戏窗口******************************************************************/
void make_frame()
{
 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);  //定义显示器句柄变量
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+13);  //打印选择菜单
 printf("Esc 退出游戏");
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+15);
 printf("长按方向键:加速");
 gotoxy(hOut,FrameX,FrameY);       //打印框角
 printf("╔");
 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY);
 printf("╗");
 gotoxy(hOut,FrameX,FrameY+Frame_height);
 printf("╚");
 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+Frame_height);
 printf("╝");
 for(i=2;i<2*Frame_width-2;i+=2)
 {
  gotoxy(hOut,FrameX+i,FrameY);
  printf("═");         //打印上横框
 }
 for(i=2;i<2*Frame_width-2;i+=2)
 {
  gotoxy(hOut,FrameX+i,FrameY+Frame_height);
  printf("═");         //打印下横框
 }
 for(i=1;i<Frame_height;i++)
 {
  gotoxy(hOut,FrameX,FrameY+i); 
  printf("║");         //打印左竖框
 }
 for(i=1;i<Frame_height;i++)
 {
  gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+i); 
  printf("║");         //打印右竖框
 }
 gotoxy(hOut,FrameX+Frame_width-5,FrameY-2);   //打印游戏名称 
 Set_TextColor_Green ();        //设置蛇为绿色
 printf("贪吃蛇游戏");
}
/******结束菜单*******************************************************************/
void over_game()
{
 system("cls");
 printf("\n\n\n\n\n\n\n\n\t\t\t\t游戏结束\n\n\n");
 Sleep(2000);
 getch();
}
/******菜单信息***************************************************************/
print_information(HANDLE hOut,struct Snake *snake,struct Food *food)
{
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+1);
 printf("level : %d",snake->count/5+1);    //打印游戏等级
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+3);
 printf("score : %d",10*snake->count);    //打印游戏得分
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+5);
 printf("eat food : %d",snake->count);    //打印产生食物个数 
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+7);
 printf("speed : %dms",snake->speed);    //打印游戏速度
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+9);
 printf("foodX : %d",food->x);      //打印食物的横坐标
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+11);
 printf("foodY : %d",food->y);      //打印食物的竖坐标
}
/******初始化蛇**********************************************************************/
void init_snake(struct Snake *snake)
{
 snake->x[0]=FrameX+2;     //初始化蛇的横坐标 
 snake->y[0]=FrameY+Frame_height/2;  //初始化蛇的竖坐标 
 snake->speed=300;      //初始化蛇的速度为300ms
 snake->length=3;      //初始化蛇的长度为3节
 snake->count=0;       //初始化蛇吃的个数为0
 for(i=1;i<snake->length;i++)
 {/* 依次得到蛇身、蛇头的坐标 */
  snake->x[i]=snake->x[i-1]+2;
  snake->y[i]=snake->y[i-1];
 } 
}
/******移动蛇*************************************************************************/
void move_snake(HANDLE hOut,struct Snake *snake)
{
 gotoxy(hOut,snake->x[0],snake->y[0]);
 printf("  ");       /* 清除蛇尾*/
 for(i=1;i<snake->length;i++)
 {/* 后一节的坐标依次取代前一节的坐标 */
  snake->x[i-1]=snake->x[i];
  snake->y[i-1]=snake->y[i];
 }
}
/******打印蛇*************************************************************************/
void print_snake(HANDLE hOut,struct Snake *snake)
{
 for(i=0;i<snake->length;i++)
 {
  gotoxy(hOut,snake->x[i],snake->y[i]);
  if(i==0)
  {
   printf("○");       //打印蛇尾
  }
  else if(i==snake->length-1)
  {
   printf("¤");       //打印蛇头
  }
  else
  {
   printf("⊙");       //打印蛇身
  }
 }
}
/******随机产生食物*******************************************************************/
void get_food(HANDLE hOut,struct Snake *snake,struct Food *food)
{
 srand((unsigned)time(NULL));       //初始化随机数
 while(1)
 {/* 产生食物的条件:1.在游戏窗口内 2.不在蛇的身上 */ 
  food->x = rand() % (Frame_width-1);
  food->y = rand() % Frame_height;
  if( food->x==0 || food->y==0 )
  {
   continue;
  }
  food->x = 2*food->x + FrameX;      //得到食物的横坐标
  food->y+=FrameY;         //得到食物的竖坐标
  for(i=0;i<snake->length;i++)
  {/* 判断食物是否在蛇的身上,如果在蛇身上,则重新产生;否则,打印蛇身 */
   if( food->x==snake->x[i] && food->y==snake->y[i] )
   {
    break;
   }
  }
  if(i==snake->length)
  {
   gotoxy(hOut,food->x,food->y);
   printf("⊙");
   break;
  } 
 }
}
/******吃食物***************************************************************************/
void eat_food(HANDLE hOut,struct Snake *snake,struct Food *food)
{
 if( snake->x[snake->length-1]==food->x && snake->y[snake->length-1]==food->y )
 {/* 如果蛇头位置与食物位置相同,吃食物 */
  snake->length++;      //吃一个食物,蛇身增长一节
  for(i=snake->length-1;i>=1;i--)
  {/* 蛇后节坐标依次赋值给蛇前一节的坐标,依次得到蛇身及蛇头的坐标 */
   snake->x[i]=snake->x[i-1];
   snake->y[i]=snake->y[i-1];
  } 
  snake->x[0]=a[0];      //得到蛇尾移动前的横坐标
  snake->y[0]=a[1];      //得到蛇尾移动前的竖坐标  
  get_food(hOut,snake,food);    //重新产生食物
  snake->count++;       //食物的个数增1
  if( snake->count%5==0 )
  {/* 当蛇吃Up_level个食物时,速度加快Up_speed毫秒并且升一级 */
   snake->speed-=50;
  }
 }
}
/******穿墙**********************************************************************************/
void through_wall(HANDLE hOut,struct Snake *snake,char ch)
{
 if( ch==72 && snake->y[snake->length-1]==FrameY)
 {
  snake->y[snake->length-1] = FrameY+Frame_height-1; //如果蛇在上框且向上移动,穿墙
 }
 if( ch==80 && snake->y[snake->length-1]==FrameY+Frame_height )
 {
  snake->y[snake->length-1] = FrameY+1;    //如果蛇在下框且向下移动,穿墙
 }
 if( ch==75 && snake->x[snake->length-1]==FrameX )
 {
  snake->x[snake->length-1] = FrameX+2*Frame_width-4; //如果蛇在左框且向左移动,穿墙
 }
 if( ch==77 && snake->x[snake->length-1]==FrameX+2*Frame_width-2 )
 {
  snake->x[snake->length-1] = FrameX+2;    //如果蛇在右框且向右移动,穿墙
 }
}
/******判断蛇是否死**************************************************************************/
int if_die(struct Snake *snake)
{/* 当蛇头碰到自身时,蛇死 ,返回值为0 */
 for(i=0;i<snake->length-1;i++)
 {
  if( snake->x[snake->length-1]==snake->x[i] && snake->y[snake->length-1]==snake->y[i] )
  {
   return 0;
  }
 }
 return 1;
}
/******开始游戏*******************************************************************************/
void start_game()
{
 unsigned char ch=77;        //定义用于接收键盘输入的字符变量
 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量
 struct Snake s,*snake=&s;      //定义蛇的结构体指针并指向蛇的结构体
 struct Food f,*food=&f;       //定义食物的结构体指针并指向食物的结构体

 make_frame();         //制作游戏窗口 
 init_snake(snake);        //初始化蛇
 get_food(hOut,snake,food);      //随机产生食物
 while(1)
 {
  print_information(hOut,snake,food);   //打印菜单信息
  a[0]=snake->x[0];       //记住蛇尾的横坐标
  a[1]=snake->y[0];       //记住蛇尾的竖坐标
  j=0;
  if(kbhit())
  {/* 判断是否按下键盘,如果按下,ch接收键盘输入 */
   ch=getch();
   if(kbhit())
   {/* 如果长按键盘,则加速 */
    Sleep(20);
    j=1;
   }
  }
  switch(ch)
  {
   case 72:
    {/* 向上移动 */
     move_snake(hOut,snake);   //移动蛇
     snake->y[snake->length-1]-=1; //蛇头的竖坐标向上移,即减1 
     break;
    }
   case 80:
    {/* 向下移动 */
     move_snake(hOut,snake);   //移动蛇
     snake->y[snake->length-1]+=1; //蛇头的竖坐标向下移,即加1
     break;
    }
   case 75:
    {/* 向左移动 */
     move_snake(hOut,snake);   //移动蛇
     snake->x[snake->length-1]-=2; //蛇头的横坐标向左移,即减2
     break;
    }    
   case 77:
    {/* 向右移动 */
     move_snake(hOut,snake);   //移动蛇
     snake->x[snake->length-1]+=2; //蛇头的横坐标向右移,即加2
     break;
    }
  }
  through_wall(hOut,snake,ch);    //穿墙   
  eat_food(hOut,snake,food);     //吃食物
  print_snake(hOut,snake);     //打印蛇
  if( if_die(snake)==0 || ch==27 || snake->speed==50 )
  {/* 游戏结束条件:1.蛇碰到自身 2.按Esc键 3.速度为50ms */
   gotoxy(hOut,FrameX+Frame_width-2,FrameY+Frame_height/2-1);
   printf("Game Over");
   Sleep(2000);
   break;
  }
  if(j==0)
  {
   Sleep(snake->speed);      //延迟时间
  }
  else
  {
   Sleep(10);
  } 
 }
}

无脑操作:蛇沿一条固定路线,留一空行,然后不断弯曲前进,最后沿预设空行返回原点,从头再来。
A star寻路算法:
参考以下链接:
贪吃蛇AI实现
A star寻路算法
这里写图片描述

<think>我们使用Pygame来编写一个简单的贪吃游戏,并加入一些智能元素,比如自动寻路(使用A*算法)来让自动寻找食物。 由于贪吃游戏本身逻辑较为复杂,我们分步骤实现: 1. 初始化游戏和Pygame。 2. 定义和食物的类。 3. 实现手动控制和自动控制(智能)两种模式。 4. 实现A*算法用于自动寻找食物(注意:贪吃的寻路问题有其特殊性,因为的身体是障碍物,而且在移动时身体也会移动,因此传统的A*可能不是最优,我们可以考虑使用一些启发式方法,或者使用寻路到食物的路径,同时避免走入死胡同)。 考虑到时间,我们将实现一个基础版本,其中可以自动寻找食物,但可能不是完美的(因为完美的贪吃AI是一个复杂问题)。我们将使用A*算法来寻找从头到食物的最短路径,但是要注意的身体是动态障碍物。 注意:在贪吃中,如果直接使用A*找到的路径,可能会在路径中出现身移动后变成障碍物的情况。因此,我们这里采用一个简化版:只考虑当前帧的障碍物(身),不考虑未来移动时身体的变化。这样在不长的情况下可以工作,但当很长时可能会陷入死胡同。 我们将实现: - 游戏循环 - 的移动(包括自动和手动) - 食物的随机生成 - 碰撞检测(与边界、与自身) - 使用A*算法自动寻路 由于代码较长,我们将逐步构建。 步骤: 1. 初始化pygame,设置窗口大小等。 2. 定义颜色。 3. 创建类,包含身体(列表),方向,以及移动方法。 4. 创建食物类,随机位置生成。 5. 游戏主循环:处理事件,更新的位置,检查是否吃到食物,检查碰撞,绘制。 6. 在自动模式下,每一步都计算从头到食物的路径(使用A*),然后设置的方向为路径的第一步。 注意:A*算法需要网格地图,我们将游戏区域划分为网格(比如每个格子20x20像素)。 我们先实现手动模式,然后再加入自动模式。 由于贪吃游戏代码较长,我们将分块实现。 注意:由于我们使用A*,我们需要定义网格地图,每个格子可以是障碍(身)或自由(空或食物)。食物所在位置也是自由的,因为头可以到达。 这里我们假设网格大小为20x20,但实际游戏区域大小由窗口大小和网格大小决定。 我们设定窗口大小为800x600,网格大小为20,那么网格列数为40,行数为30。 下面开始写代码。 </think>### Python实现智能贪吃游戏 下面是一个使用Python和Pygame库实现的智能贪吃游戏。这个版本包含自动寻路算法,会自动寻找食物并避开障碍物。 ```python import pygame import sys import random import heapq import math # 初始化pygame pygame.init() # 游戏常量 WIDTH, HEIGHT = 600, 600 GRID_SIZE = 20 GRID_WIDTH = WIDTH // GRID_SIZE GRID_HEIGHT = HEIGHT // GRID_SIZE FPS = 10 # 颜色定义 BLACK = (0, 0, 0) WHITE = (255, 255, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) BLUE = (0, 120, 255) YELLOW = (255, 255, 0) BACKGROUND = (40, 40, 40) # 方向常量 UP = (0, -1) DOWN = (0, 1) LEFT = (-1, 0) RIGHT = (1, 0) class Node: """A*算法节点类""" def __init__(self, position, parent=None): self.position = position self.parent = parent self.g = 0 # 从起点到当前节点的实际代价 self.h = 0 # 从当前节点到终点的估计代价 self.f = 0 # 总代价 (g + h) def __eq__(self, other): return self.position == other.position def __lt__(self, other): return self.f < other.f class Snake: """贪吃类""" def __init__(self): self.reset() def reset(self): """重置的状态""" self.length = 3 self.positions = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)] self.direction = random.choice([UP, DOWN, LEFT, RIGHT]) self.score = 0 self.grow_to = 3 def get_head_position(self): """获取头位置""" return self.positions[0] def update(self): """更新的位置""" head = self.get_head_position() x, y = self.direction new_position = ((head[0] + x) % GRID_WIDTH, (head[1] + y) % GRID_HEIGHT) # 检查是否撞到自己 if new_position in self.positions[1:]: self.reset() return False self.positions.insert(0, new_position) # 检查是否需要增长 if len(self.positions) > self.grow_to: self.positions.pop() return True def render(self, surface): """绘制""" for i, p in enumerate(self.positions): color = GREEN if i == 0 else BLUE # 头绿色,身蓝色 rect = pygame.Rect((p[0] * GRID_SIZE, p[1] * GRID_SIZE), (GRID_SIZE, GRID_SIZE)) pygame.draw.rect(surface, color, rect) pygame.draw.rect(surface, BLACK, rect, 1) class Food: """食物类""" def __init__(self, snake): self.position = (0, 0) self.randomize_position(snake) def randomize_position(self, snake): """随机生成食物位置""" while True: self.position = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1)) if self.position not in snake.positions: break def render(self, surface): """绘制食物""" rect = pygame.Rect((self.position[0] * GRID_SIZE, self.position[1] * GRID_SIZE), (GRID_SIZE, GRID_SIZE)) pygame.draw.rect(surface, RED, rect) pygame.draw.rect(surface, BLACK, rect, 1) def heuristic(a, b): """A*算法的启发式函数(曼哈顿距离)""" return abs(a[0] - b[0]) + abs(a[1] - b[1]) def a_star_search(snake, food, obstacles): """A*寻路算法实现""" start = snake.get_head_position() end = food.position # 创建开始和结束节点 start_node = Node(start) end_node = Node(end) # 初始化开放列表和关闭列表 open_list = [] closed_list = [] # 添加起始节点 heapq.heappush(open_list, (start_node.f, start_node)) # 循环直到找到路径 while open_list: # 获取当前节点 current_node = heapq.heappop(open_list)[1] closed_list.append(current_node) # 找到目标 if current_node == end_node: path = [] current = current_node while current is not None: path.append(current.position) current = current.parent return path[::-1] # 反转路径 # 生成邻居节点 neighbors = [] for new_direction in [UP, DOWN, LEFT, RIGHT]: node_position = ( (current_node.position[0] + new_direction[0]) % GRID_WIDTH, (current_node.position[1] + new_direction[1]) % GRID_HEIGHT ) # 检查是否在障碍物中(身或边界障碍) if node_position in obstacles: continue new_node = Node(node_position, current_node) neighbors.append(new_node) # 遍历所有邻居 for neighbor in neighbors: # 邻居在关闭列表中则跳过 if any(neighbor.position == closed_node.position for closed_node in closed_list): continue # 计算新的g值 neighbor.g = current_node.g + 1 neighbor.h = heuristic(neighbor.position, end) neighbor.f = neighbor.g + neighbor.h # 如果已经在开放列表中且有更低的g值则跳过 if any(neighbor.f > open_node[1].f and neighbor.position == open_node[1].position for open_node in open_list): continue heapq.heappush(open_list, (neighbor.f, neighbor)) return [] # 未找到路径 def draw_grid(surface): """绘制网格线""" for x in range(0, WIDTH, GRID_SIZE): pygame.draw.line(surface, (60, 60, 60), (x, 0), (x, HEIGHT)) for y in range(0, HEIGHT, GRID_SIZE): pygame.draw.line(surface, (60, 60, 60), (0, y), (WIDTH, y)) def draw_score(surface, score): """绘制分数""" font = pygame.font.SysFont('Arial', 20) text = font.render(f'Score: {score}', True, YELLOW) surface.blit(text, (5, 5)) def main(): """主游戏函数""" screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption('AI贪吃') clock = pygame.time.Clock() snake = Snake() food = Food(snake) manual_mode = False while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: pygame.quit() sys.exit() elif event.key == pygame.K_m: manual_mode = not manual_mode elif manual_mode: # 手动模式控制 if event.key == pygame.K_UP and snake.direction != DOWN: snake.direction = UP elif event.key == pygame.K_DOWN and snake.direction != UP: snake.direction = DOWN elif event.key == pygame.K_LEFT and snake.direction != RIGHT: snake.direction = LEFT elif event.key == pygame.K_RIGHT and snake.direction != LEFT: snake.direction = RIGHT # 如果是自动模式,使用A*算法寻找路径 if not manual_mode: obstacles = snake.positions[1:] # 身作为障碍物 path = a_star_search(snake, food, obstacles) # 如果有有效路径,设置方向 if path and len(path) > 1: next_pos = path[1] head_pos = snake.get_head_position() snake.direction = ( (next_pos[0] - head_pos[0]) % GRID_WIDTH, (next_pos[1] - head_pos[1]) % GRID_HEIGHT ) # 更新的位置 if not snake.update(): food.randomize_position(snake) # 检查是否吃到食物 if snake.get_head_position() == food.position: snake.grow_to += 1 snake.score += 10 food.randomize_position(snake) # 绘制游戏界面 screen.fill(BACKGROUND) draw_grid(screen) snake.render(screen) food.render(screen) draw_score(screen, snake.score) # 显示当前模式 font = pygame.font.SysFont('Arial', 18) mode_text = font.render(f'Mode: {"Manual" if manual_mode else "AI"} (Press M to toggle)', True, YELLOW) screen.blit(mode_text, (WIDTH - mode_text.get_width() - 10, 5)) pygame.display.update() clock.tick(FPS) if __name__ == "__main__": main() ``` ### 代码解释 1. **游戏结构**: - `Snake`类:管理的位置、方向和增长逻辑 - `Food`类:负责食物的生成和绘制 - `Node`类:A*算法使用的节点结构 2. **核心功能**: - **A*寻路算法**:`a_star_search()`函数实现了智能寻路 - 使用曼哈顿距离作为启发函数 - 考虑身作为动态障碍物 - 支持边界穿越(可以从一边穿到另一边) - **双模式控制**: - AI模式:自动寻找食物 - 手动模式:使用方向键控制(按M键切换) - **碰撞检测**: - 检测头是否撞到自身 - 吃到食物后身增长 3. **游戏特性**: - 网格化游戏区域(20×20网格) - 头为绿色,身为蓝色 - 实时显示分数和当前模式 - 可以穿越边界(从一边到另一边) 4. **控制方式**: - 方向键:手动控制的方向 - M键:切换手动/AI模式 - ESC键:退出游戏 ### 运行说明 1. 需要安装Pygame库:`pip install pygame` 2. 运行后默认为AI模式,会自动寻找食物 3. 按M键切换手动控制模式 4. 在手动模式下使用方向键控制的移动方向 游戏界面会实时显示当前分数和操作模式。吃到食物后分数增加,身变长。当撞到自己时,游戏会自动重置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值