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

如何用JavaScript实现卡坦岛资源建筑组合计算功能?

卡坦岛建筑组合计算方案优化(含交易规则与扩展性支持)

针对你遇到的优先级遗漏组合、扩展性、交易规则及剩余资源展示问题,以下是一套完整的JavaScript实现方案:

核心问题解决:无优先级全组合枚举

之前的函数因固定建造优先级(比如先建城市再建道路)遗漏组合,这里采用递归回溯遍历所有可能的建筑数量组合,确保不遗漏任何可行方案:

  1. 先计算每种建筑的最大可建造数量(基于初始资源+极端兑换场景),缩小枚举范围
  2. 递归遍历所有建筑的数量组合(从0到最大数量)
  3. 对每个组合计算总消耗,结合交易规则验证是否可行,可行则记录组合及剩余资源

扩展性设计:配置化管理建筑与港口

把建筑消耗和港口规则做成可配置的对象,新增扩展建筑或修改港口规则无需改动核心逻辑:

建筑配置示例

const buildings = [
  { name: 'City(城市)', cost: { wheat: 2, ore: 3 } },
  { name: 'Settlement(定居点)', cost: { wood: 1, brick: 1, wool: 1, ore: 1 } },
  { name: 'Road(道路)', cost: { wood: 1, brick: 1 } },
  { name: 'Dev. Card(发展卡)', cost: { wool: 1, wheat: 1, ore: 1 } },
  // 新增扩展建筑直接添加配置项即可
  { name: 'Ship(扩展:船只)', cost: { wood: 1, wool: 1 } }
];

港口配置示例

// key为资源类型(专属港口)或'general'(通用港口),value为兑换比例
const ports = {
  ore: 2,    // 矿石专属港口:2个矿石换1个任意资源
  general: 3 // 通用港口:3个任意资源换1个任意资源
};

资源交易规则实现

实现一个函数,计算初始资源能否通过交易满足建造需求,并返回交易后的剩余资源:

  • 先计算每种资源的盈余/缺口
  • 按最优兑换优先级(专属港口>通用港口>默认4换1)将盈余资源转换为可兑换额度
  • 验证额度是否覆盖缺口,同时精准计算剩余资源

完整实现代码

// 建筑配置
const buildings = [
  { name: 'City(城市)', cost: { wheat: 2, ore: 3 } },
  { name: 'Settlement(定居点)', cost: { wood: 1, brick: 1, wool: 1, ore: 1 } },
  { name: 'Road(道路)', cost: { wood: 1, brick: 1 } },
  { name: 'Dev. Card(发展卡)', cost: { wool: 1, wheat: 1, ore: 1 } }
];

// 港口配置
const ports = { general: 3, ore: 2 };

// 验证资源(含交易)是否满足需求,返回剩余资源或null
function canAffordWithTrade(initialResources, requiredResources) {
  const resourceTypes = ['wood', 'brick', 'wool', 'wheat', 'ore'];
  const surplus = {};
  const deficit = {};
  let totalTradeable = 0;

  // 计算盈余与缺口
  resourceTypes.forEach(type => {
    const has = initialResources[type] || 0;
    const need = requiredResources[type] || 0;
    if (has > need) {
      surplus[type] = has - need;
      // 计算该资源可兑换的额度
      const exchangeRate = ports[type] || ports.general || 4;
      totalTradeable += Math.floor(surplus[type] / exchangeRate);
    } else if (has < need) {
      deficit[type] = need - has;
    }
  });

  // 总缺口大于可兑换额度,无法满足
  const totalDeficit = Object.values(deficit).reduce((sum, val) => sum + val, 0);
  if (totalTradeable < totalDeficit) return null;

  // 计算剩余资源
  const remaining = {...initialResources};
  // 先扣除直接消耗的资源
  resourceTypes.forEach(type => {
    if (requiredResources[type]) {
      remaining[type] = Math.max((remaining[type] || 0) - requiredResources[type], 0);
    }
  });

  // 处理交易消耗的盈余资源
  let remainingDeficit = totalDeficit;
  resourceTypes.forEach(type => {
    if (!surplus[type] || remainingDeficit <= 0) return;
    const rate = ports[type] || ports.general || 4;
    // 计算最多能用来交易的数量
    const tradeAmount = Math.min(surplus[type], remainingDeficit * rate);
    remaining[type] -= tradeAmount;
    remainingDeficit -= Math.floor(tradeAmount / rate);
  });

  // 缺口资源已通过交易覆盖,剩余为0
  resourceTypes.forEach(type => {
    if (deficit[type]) remaining[type] = 0;
  });

  return remaining;
}

// 枚举所有可行建筑组合
function findAllValidBuilds(initialResources) {
  const validCombos = [];

  // 计算每种建筑的最大可能建造数量(极端场景:所有资源兑换为该建筑所需资源)
  const maxCounts = buildings.map(building => {
    return Object.entries(building.cost).reduce((minCount, [resource, costPer]) => {
      const owned = initialResources[resource] || 0;
      // 计算所有其他资源能兑换成该资源的最大数量
      const totalPossible = owned + Math.floor(
        Object.entries(initialResources)
          .filter(([r]) => r !== resource)
          .reduce((sum, [, cnt]) => sum + cnt, 0) / (ports[resource] || ports.general || 4)
      );
      return Math.min(minCount, Math.floor(totalPossible / costPer));
    }, Infinity);
  });

  // 递归回溯遍历所有组合
  function backtrack(buildingIndex, currentCounts, currentTotalCost) {
    if (buildingIndex === buildings.length) {
      const remainingResources = canAffordWithTrade(initialResources, currentTotalCost);
      if (remainingResources) {
        validCombos.push({
          buildings: buildings.map((b, idx) => ({ name: b.name, count: currentCounts[idx] })).filter(item => item.count > 0),
          remainingResources
        });
      }
      return;
    }

    // 遍历当前建筑的所有可能建造数量(0到maxCounts[buildingIndex])
    for (let count = 0; count <= maxCounts[buildingIndex]; count++) {
      const newTotalCost = {...currentTotalCost};
      // 累加当前建筑count数量的消耗
      Object.entries(buildings[buildingIndex].cost).forEach(([res, cost]) => {
        newTotalCost[res] = (newTotalCost[res] || 0) + cost * count;
      });
      backtrack(buildingIndex + 1, [...currentCounts, count], newTotalCost);
    }
  }

  backtrack(0, [], {});
  return validCombos;
}

// 使用示例
const playerResources = { wood: 3, brick: 3, wool: 2, wheat: 2, ore: 3 };
const validBuilds = findAllValidBuilds(playerResources);

// 输出结果示例
validBuilds.forEach((combo, index) => {
  console.log(`=== 可行组合 ${index + 1} ===`);
  console.log('建造清单:', combo.buildings);
  console.log('剩余资源:', combo.remainingResources);
});

方案优势

  • 无遗漏组合:递归遍历所有可能的建筑数量组合,彻底解决优先级导致的遗漏问题
  • 高扩展性:新增建筑/修改港口规则只需调整配置,核心逻辑无需改动
  • 完整交易支持:覆盖卡坦岛所有交易规则,优先使用最优兑换比例
  • 精准剩余资源:不仅验证可行性,还会输出交易和建造后的剩余资源详情

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 08:03:33