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

C语言结构体数组洗牌异常:僵尸人类网格游戏回合顺序问题

洗牌Agent数组后ID大量为0的问题排查与修复

嘿,我看到你遇到的问题了——调用洗牌函数后打印Agent ID时大部分都是0,只有零星几个正确的ID。咱们来一步步拆解这个问题,找到根源再解决它。

问题根源分析

先看你传递给shuffle函数的参数:你把整个20x20的网格数组my_world.grid传了进去,同时传入的nagents是实际创建的有效Agent数量(大概40个左右,因为只有10%的概率生成Agent)。但这里有个致命的错误:有效Agent并不是连续存放在网格数组的前nagents个位置,而是随机分散在整个20x20的网格里,剩下的大部分位置都是None类型的Agent(它们的id默认是0)。

你的洗牌函数只会交换数组的前nagents个元素,而这些元素里绝大多数都是None类型的0-ID Agent,真正的有效Agent可能在数组后面的位置根本没被洗牌到,所以打印出来自然都是0,只有少数刚好落在前nagents位置的有效Agent能被显示出来。

另外还有个小问题:你在shuffle函数里又调用了srand(time(NULL)),但main函数里已经初始化过随机数种子了。如果程序运行速度快,time(NULL)返回的秒数相同,会导致随机数序列被重置,洗牌效果变差,但这不是你看到大量0的主要原因。

解决方案

我们需要先把所有**有效Agent(type不为None的)**收集到一个单独的数组里,再对这个数组进行洗牌——这样就能保证我们洗牌的都是真正有意义的Agent,不会混入大量0-ID的空Agent。

步骤1:修改主函数,收集有效Agent

在调用洗牌函数之前,先遍历整个网格,把有效Agent的指针收集到临时数组里(用指针的好处是修改Agent状态会直接同步到原网格,且更高效):

int main() {
    // ... 之前的代码保持不变 ...

    // 收集所有有效Agent的指针
    AGENT **valid_agents = malloc(nagents * sizeof(AGENT*));
    if (!valid_agents) {
        fprintf(stderr, "内存分配失败!\n");
        return 1;
    }
    int idx = 0;
    for (int i = 0; i < WORLD_X; ++i) {
        for (int j = 0; j < WORLD_Y; ++j) {
            if (agent_grid[i][j].type != None) {
                valid_agents[idx++] = &agent_grid[i][j];
            }
        }
    }

    // 对有效Agent的指针数组洗牌
    shuffle_pointers(valid_agents, nagents);

    // 后续可遍历洗牌后的数组处理Agent行动
    // for (int i = 0; i < nagents; ++i) {
    //     // 执行valid_agents[i]指向的Agent的行动逻辑
    // }

    // 用完临时数组后释放内存
    free(valid_agents);

    // ... 后续代码保持不变 ...
}

步骤2:编写针对指针数组的洗牌函数

因为我们现在要洗牌的是Agent指针数组,所以需要一个对应的洗牌函数:

#include "example.h"
#include <stdio.h>
#include <stdlib.h>

void shuffle_pointers(AGENT **agents, unsigned int nagents) {
    printf("%s\n\n", "------------- Shuffling agent pointers ----------------");
    unsigned int i, j;
    AGENT *temp;
    // 去掉重复的srand,main里已经初始化过随机数种子了
    for (i = nagents - 1; i > 0; i--) {
        // 标准Fisher-Yates洗牌:从0到i的范围随机选一个索引
        j = rand() % (i + 1);
        temp = agents[i];
        agents[i] = agents[j];
        agents[j] = temp;
    }
    // 打印洗牌后的ID
    for (i = 0; i < nagents; i++) {
        printf("\n\t%d", agents[i]->id);
    }
}

步骤3:清理原洗牌函数的冗余代码

如果你还是想用原来的Agent拷贝数组洗牌,记得把原shuffle函数里的srand(time(NULL))删掉,避免重置随机数种子影响随机性。

额外说明

这样修改后,我们洗牌的是所有有效Agent的指针数组,既不会修改原网格的位置(符合你的要求),又能得到正确的随机行动顺序。后续处理每个Agent的行动时,只需要遍历这个洗牌后的指针数组即可,每个指针都指向原网格里的Agent,修改它们的状态会直接同步到网格中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:10:10