You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NEAT算法实现小行星躲避AI时出现列表索引越界问题求助

排查NEAT小行星游戏的列表索引越界问题

我帮你梳理下这个问题的核心原因,再给出适配你需求的解决方案——毕竟你是NEAT新手,还希望每次只运行单个genome,先把这个基础逻辑跑通会更省心。

核心问题分析

你怀疑的for x in range(len(players))确实是问题根源,具体有两个点:

  1. 动态列表的遍历冲突:你在循环内部的碰撞逻辑里执行了del players[x]、del nets[x]、del ge[x],这会直接缩短三个列表的长度。但循环的遍历范围是一开始的列表长度,当x递增到超过新的列表长度时,自然就会触发索引越界。
  2. 不符合单Genome运行需求:你想要每次只运行一个genome,但当前代码是一次性初始化所有genome对应的玩家、网络、基因组对象,再逐个循环运行,既违背了你的需求,又增加了索引管理的复杂度。

解决方案

1. 改成单Genome运行模式(最适合你的新手需求)

直接调整main函数的逻辑,不用维护三个关联列表,逐个处理每个genome即可,这样完全避免索引问题:

def main(genomes, config):
    # 逐个处理每个genome,每次只运行一个
    for genome_id, g in genomes:
        net = neat.nn.FeedForwardNetwork.create(g, config)
        current_player = player()
        g.fitness = 0
        game_over = False
        
        # 初始化小行星(去掉原列表里多余的0,直接存4个 asteroid 对象)
        asteroids = [
            asteroid(1, playable_height-39, 10.5, 35, 39, 0),
            asteroid(2, playable_height-25, 15, 25, 25, 10),
            asteroid(3, playable_height-30, 12.5, 30, 30, 15),
            asteroid(4, playable_height-35, 10, 35, 35, 20)
        ]
        
        while not game_over:
            # 处理退出事件
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
            
            # 神经网络决策输出
            output = net.activate((
                current_player.y / 169, 
                GetDistance(0, current_player, asteroids),  # 注意索引改成0,因为列表从0开始了
                GetDistance(1, current_player, asteroids),
                GetDistance(2, current_player, asteroids),
                GetDistance(3, current_player, asteroids)
            ))
            
            # 玩家移动逻辑
            if output[0] > 0:
                current_player.moveDOWN()
            elif output[0] < 0:
                current_player.moveUP()
            
            # 边界限制
            if current_player.y > playable_height - current_player.height:
                current_player.y = playable_height - current_player.height
            elif current_player.y < 0:
                current_player.y = 0
            
            # 画面绘制
            window.fill((0, 0, 0))
            window.blit(bg_img, (0, 0))
            current_player.draw()
            
            # 小行星逻辑处理
            collision_happened = False
            for ast in asteroids:
                if ast.x < 0:
                    current_player.score += 1
                    g.fitness += 5
                    ast.reset(asteroids)  # 重置已躲避的小行星
                ast.move(current_player)
                # 碰撞判定
                if ast.collision(current_player):
                    g.fitness -= 1
                    collision_happened = True
                    break  # 碰撞后直接跳出小行星循环
            
            if collision_happened:
                game_over = True
            
            # 文本显示
            Text_display("Score: " + str(current_player.score * 100), white, 0, 200)
            Text_display("Asteroid 1: " + str(GetDistance(0, current_player, asteroids)), white, 0, 220)
            Text_display("Asteroid 2: " + str(GetDistance(1, current_player, asteroids)), white, 0, 240)
            Text_display("Asteroid 3: " + str(GetDistance(2, current_player, asteroids)), white, 0, 260)
            Text_display("Asteroid 4: " + str(GetDistance(3, current_player, asteroids)), white, 0, 280)
            Text_display("Space Ship Position: " + str(current_player.y / 169), white, 0, 300)
            
            pygame.display.update()

2. 额外的细节优化

  • 原代码里asteroids列表第一个元素是0,导致你访问小行星时要从索引1开始,很容易混淆,改成直接存储4个asteroid对象的列表更合理。
  • 碰撞时的reset方法,建议确保它能独立重置当前小行星的位置,不要过度依赖外部列表参数。

3. 如果之后想尝试多Genome运行

要是你之后想让多个AI同时跑,那不能用for x in range(len(players))的正向遍历,应该用倒序遍历,这样删除元素不会影响未处理的索引:

# 倒序遍历列表索引,删除元素后不会打乱前面的索引
for x in range(len(players)-1, -1, -1):
    game_over = False
    while not game_over:
        # 你的原有逻辑(碰撞后删除元素的代码保留)

内容的提问来源于stack exchange,提问作者Zafirmk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:44:04