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

我的物品堆叠算法异常:所有堆叠数量归零问题排查

背包堆叠合并功能故障排查

需求描述

实现背包物品堆叠合并:将同ID物品堆叠至最大99数量,把其他堆叠的物品转移到第一个同ID堆叠中,扣除对应数量,最后移除数量≤0的堆叠。但运行后所有堆叠数量均变为0。

已尝试的方案:

  • 让每个堆叠检查除自身外的所有堆叠
  • 让每个堆叠检查列表中自身上方的所有堆叠
  • 当前代码为最新尝试

当前代码

private void UpdateInventory()
{
    List<byte> indexes = new();
    for (int x = 0; x < Inventory.Count; x++)
    {
        if (!indexes.Contains(Inventory[x].ID))
        {
            indexes.Add(Inventory[x].ID);
            for (int i = x + 1; i < Inventory.Count; i++)
            {
                if (x != i && Inventory[x].ID == 
                    Inventory[i].ID && Inventory[x].amount < 99)
                {
                    if (Inventory[x].amount + Inventory[i].amount > 99)
                    {
                        Inventory[i].amount -= 99 - Inventory[x].amount;
                        Inventory[x].amount = 99;
                    }
                    else
                    {
                        Inventory[x].amount += Inventory[i].amount;
                        Inventory[i].amount = 0;
                    }
                }
            }
        }
    }

    Inventory.RemoveAll(item => item.amount <= 0);
}

问题分析与修复

核心问题

  1. 引用类型意外修改:如果背包中的物品是引用类型,多个堆叠引用同一个对象实例时,修改其中一个的amount会同步影响所有引用该对象的堆叠,导致所有同ID物品数量被错误清零。
  2. 循环逻辑冗余与遗漏:原始代码中x != i判断完全冗余(i从x+1开始,永远不等于x);且堆叠填满后未正确处理剩余数量的后续堆叠。

修复方案

方案1:优化循环逻辑(贴合原始思路)

简化合并逻辑,明确计算剩余空间,只转移可容纳的数量,避免复杂条件判断:

private void UpdateInventory()
{
    List<byte> processedIds = new();
    for (int x = 0; x < Inventory.Count; x++)
    {
        var currentItem = Inventory[x];
        // 跳过已处理ID或数量为0的物品
        if (currentItem.amount <= 0 || processedIds.Contains(currentItem.ID))
            continue;

        processedIds.Add(currentItem.ID);
        int remainingSpace = 99 - currentItem.amount;

        // 合并后续同ID物品到当前堆叠
        for (int i = x + 1; i < Inventory.Count; i++)
        {
            var targetItem = Inventory[i];
            if (targetItem.ID != currentItem.ID || targetItem.amount <= 0)
                continue;

            if (remainingSpace <= 0)
                break; // 当前堆叠已满,停止合并

            // 计算可转移的最大数量
            int transferAmount = Math.Min(remainingSpace, targetItem.amount);
            currentItem.amount += transferAmount;
            targetItem.amount -= transferAmount;
            remainingSpace -= transferAmount;
        }
    }

    Inventory.RemoveAll(item => item.amount <= 0);
}

方案2:按ID分组合并(更简洁可靠)

先按ID分组,再对每组进行堆叠合并,逻辑更清晰:

private void UpdateInventory()
{
    // 按ID分组,保留原始出现顺序
    var groupedItems = Inventory.GroupBy(item => item.ID).ToList();
    Inventory.Clear();

    foreach (var group in groupedItems)
    {
        var items = group.ToList();
        if (items.Count == 0) continue;

        // 以第一个堆叠为主堆叠
        var mainItem = items[0];
        int remainingCapacity = 99 - mainItem.amount;

        // 合并后续堆叠的数量
        for (int i = 1; i < items.Count; i++)
        {
            var subItem = items[i];
            if (subItem.amount <= 0) continue;

            if (remainingCapacity <= 0)
            {
                // 主堆叠已满,保留当前剩余堆叠
                Inventory.Add(subItem);
                continue;
            }

            int transfer = Math.Min(remainingCapacity, subItem.amount);
            mainItem.amount += transfer;
            subItem.amount -= transfer;
            remainingCapacity -= transfer;
        }

        // 添加主堆叠(数量>0才保留)
        if (mainItem.amount > 0)
        {
            Inventory.Add(mainItem);
        }
    }

    Inventory.RemoveAll(item => item.amount <= 0);
}

额外注意事项

如果物品是引用类型,添加到背包时务必创建独立实例,避免多个堆叠引用同一个对象,否则会出现修改一个影响全部的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:05:18