当前位置:首页 > 工具 > 正文内容

基于远程桌面的Python贪吃蛇双智能体实现

访客 工具 2026年8月24日 1

实验背景与目标

本实验旨在通过华为云EularOS服务器搭建Python运行环境,实现一个支持人机对战的双智能体贪吃蛇游戏。游戏包含一个由玩家控制的蓝色蛇,以及一个基于坐标决策的AI控制绿色蛇,两者共同竞争食物资源。通过远程X11转发技术,实现在无图形界面的云服务器上可视化运行pygame游戏。

环境部署与配置

在EularOS系统中,系统默认使用Python 2.7,需明确指定Python 3环境。首先确认Python 3与pip3的安装状态:

whereis python3
whereis pip3
python3 -V
pip3 -V

若pip3缺失或版本异常,需手动安装最新版pip:

wget https://files.pythonhosted.org/packages/ae/e8/2340d46ecadb1692a1e455f13f75e596d4eab3d11a57446f08259dee8f02/pip-10.0.1.tar.gz
tar -xzf pip-10.0.1.tar.gz
cd pip-10.0.1
python3 setup.py install

随后安装pygame依赖库:

pip3 install pygame

为支持图形界面远程显示,安装X11转发组件:

yum install xterm xauth -y

编辑SSH配置文件以启用X11转发:

vi /etc/ssh/sshd_config

确保以下行存在且未被注释:

X11Forwarding yes
X11UseLocalhost no

重启SSH服务并退出会话:

systemctl restart sshd

本地电脑需安装Xming(Windows)或XQuartz(macOS),启动后通过PuTTY连接服务器,并在Session → SSH → X11中启用"Enable X11 forwarding"。连接后输入xterm验证窗口能否弹出。

双智能体贪吃蛇实现

游戏逻辑分为两个独立控制模块:玩家通过WASD控制蓝色蛇,AI通过坐标比较自动决策绿色蛇的移动方向。

核心变量定义:

  • head:玩家蛇头坐标
  • thead:AI蛇头坐标
  • snacks:玩家蛇身列表
  • other:AI蛇身列表
  • foods:食物坐标集合
  • want:当前目标食物
  • which:AI方向选择器(0=x轴,1=y轴)
  • run:AI移动速度(±V)

AI决策逻辑采用"逐轴逼近"策略:

  • 优先沿which轴移动,当蛇头与目标食物在该轴上距离超过食物半径时,朝目标方向匀速移动
  • 当距离小于阈值时,切换至另一轴继续逼近
  • 该策略避免了复杂的路径规划,仅依靠局部坐标判断实现简单智能

关键代码片段:

if thead[which] < want[which] - R:
    run = V
elif thead[which] > want[which] + R:
    run = -V
else:
    which = 1 - which
thead[which] += run

食物被任一蛇体触及时,立即移除并随机生成新食物。若被AI吃掉,目标食物want更新为剩余食物中的随机一项,确保AI持续追踪有效目标。

蛇身增长机制:每次进食后,在蛇尾后方追加一个新方块,实现长度增长。

完整核心代码

import pygame as pg
from random import randint, choice

# 初始化参数
SCREEN = pg.display.set_mode([800, 600])
pg.display.set_caption('双智能体贪吃蛇')
V = 21      # 移动步长
A = 20      # 方块尺寸
R = 20      # 食物半径

# 玩家蛇
direct = "右"
head = [500, 500]
snacks = [head]

# AI蛇
thead = [200, 300]
other = [thead]
which = 0   # 控制轴向:0为x,1为y
run = V     # 当前移动方向
want = (220, 350)  # 初始目标食物

# 食物池
foods = [(220, 350), (450, 250), (390, 340), (690, 400)]

going = True
clock = pg.time.Clock()

while going:
    SCREEN.fill((255, 255, 255))

    # 玩家输入处理
    for event in pg.event.get([pg.KEYDOWN, pg.QUIT]):
        if event.type == pg.QUIT:
            going = False
        elif event.key == pg.K_w: direct = "上"
        elif event.key == pg.K_s: direct = "下"
        elif event.key == pg.K_a: direct = "左"
        elif event.key == pg.K_d: direct = "右"
    pg.event.clear()

    # 玩家蛇移动
    if direct == "上": head[1] -= V
    elif direct == "下": head[1] += V
    elif direct == "左": head[0] -= V
    elif direct == "右": head[0] += V

    # 边界环绕
    if head[0] < 0: head[0] = 800
    if head[0] > 800: head[0] = 0
    if head[1] < 0: head[1] = 600
    if head[1] > 600: head[1] = 0

    snacks.insert(0, head.copy())
    snacks.pop()

    # AI蛇决策与移动
    if thead[which] < want[which] - R:
        run = V
    elif thead[which] > want[which] + R:
        run = -V
    else:
        which = 1 - which
    thead[which] += run
    other.insert(0, thead.copy())
    other.pop()

    # 食物绘制与碰撞检测
    for food in foods:
        pg.draw.circle(SCREEN, (238, 180, 34), food, R)
        
        # 玩家吃到食物
        if (food[0]-R-A <= head[0] <= food[0]+R and 
            food[1]-R-A <= head[1] <= food[1]+R):
            foods.remove(food)
            snacks.append([head[0]-A, head[1]])
            if food == want:
                want = choice(foods)

        # AI吃到食物
        elif (food[0]-R-A <= thead[0] <= food[0]+R and 
              food[1]-R-A <= thead[1] <= food[1]+R):
            foods.remove(food)
            other.append([thead[0]-A, thead[1]])
            if food == want:
                want = choice(foods)

    # 补充食物数量
    if len(foods) < 4:
        foods.append((randint(0, 750), randint(0, 550)))

    # 绘制蛇体
    for segment in snacks[1:]: 
        pg.draw.rect(SCREEN, (100, 200, 200), (segment[0], segment[1], A, A))
    pg.draw.rect(SCREEN, (0, 255, 255), (head[0], head[1], A, A))

    for segment in other[1:]: 
        pg.draw.rect(SCREEN, (0, 238, 118), (segment[0], segment[1], A, A))
    pg.draw.rect(SCREEN, (0, 139, 69), (thead[0], thead[1], A, A))

    pg.display.update()
    clock.tick(20)

pg.quit()

问题与解决方案

问题1:Python版本混淆
EularOS默认调用Python 2.7,导致pip与库安装错位。解决方案:始终使用python3pip3指令,避免使用pythonpip

问题2:无图形界面报错
pygame启动时提示"Unable to open display"。通过配置X11转发并启用Xming解决,确保SSH连接中勾选"Enable X11 forwarding"。

问题3:AI路径震荡
初期AI在边界处反复切换方向。通过引入which轴切换机制,强制交替控制x/y轴,有效稳定了移动轨迹。

实验总结

本实验不仅完成了云服务器环境搭建与远程图形化运行的完整流程,更通过极简AI逻辑实现了双智能体交互。AI不依赖复杂算法,仅靠坐标差值与轴向轮换,便能实现高效觅食行为,体现了"简单机制产生复杂行为"的计算思维。在实践过程中,深刻体会到Python在教育与原型开发中的强大适应性——无需复杂框架,即可构建可交互的可视化系统。同时,远程开发的调试过程极大提升了对Linux系统与网络协议的理解深度。

返回列表

上一篇:手动实现Promise对象

没有最新的文章了...

相关文章

Trojan服务器搭建与配置

一、整体架构(先对齐认知)Clash Meta (PC / iOS / Android)        ↓ TLS   Trojan Server (443)        ↓     InternetTrojan 的核心是: TLS + HTTPS 流量伪装 看起来像正常网站 非常适合...

Tailscale 的详细用法

Tailscale 是一种基于 WireGuard 协议 的 零配置 VPN(虚拟私有网络)服务,让设备之间能够 安全、加密地直接连接,就像它们在同一个本地网络一样。它的核心特点是 简单、安全、跨平台。Tailscale 非常适合 没有公网 IP、两台电脑不在同一局域网 的场景。 简单来说,Tailscale 是什么?Tailscale 是一款让你的各种设备(电脑、服务器、手机...

Clash Tun 模式 导致 爱快(iKuai SD-Wan)内网域名无法访问

一、Clash  DNS 配置dns:  enable: true  listen: 0.0.0.0:53  ipv6: true  enhanced-mode: redir-host  nameserver:    - 223.5.5.5    - 223.6.6.6iKuai 内网域名 ...

深入解析Node.js运行环境与异步I/O架构

深入解析Node.js运行环境与异步I/O架构

核心定义与价值Node.js本质上是一个JavaScript运行环境,而非编程语言或应用框架。它赋予了JavaScript脱离浏览器在服务端、命令行工具及网络应用中执行的能力。其核心意义在于:用单一语言打通前后端开发壁垒。基于事件驱动与非阻塞I/O的架构特性,Node.js在处理API网关、实时通信及微服务等I/O密集型场景时表现卓越,已成为现代后端工程的主流选择。浏览器沙箱限制1995年Java...

ADO.NET SQL参数化查询的最佳实践

在 ADO.NET 中执行 SQL 查询时,参数化查询是一种关键的安全措施和性能优化手段。它通过将 SQL 命令和用户提供的数据分开处理,有效防止了 SQL 注入攻击,并有助于数据库缓存执行计划。下面总结了几种常用的参数化查询方式。 1. 使用 SqlParameter 对象(推荐) 这是最推荐的参数化查询方式。通过显式创建 SqlParameter 对象,您可以精确控制参数的类...

基于ELK的日志集中化分析系统搭建

构建统一日志管理平台的必要性 在分布式架构中,各服务节点独立运行,日志分散存储于不同主机。传统通过命令行工具如grep、awk逐个检索日志的方式,在数据量庞大时效率极低,难以实现快速定位问题。为提升运维效率,需建立集中式日志处理体系,具备日志采集、传输、存储、分析与告警能力。 ELK技术栈核心组件解析 Elasticsearch:分布式搜索引擎,支持全文检索、实时数据分析和高可用集群部署,...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。