大富翁(Monopoly)下一个建筑升级计算函数优化需求
大富翁(Monopoly)建筑升级逻辑优化问题
核心规则
每条街道包含2或3个独立地产(property),升级时可在对应地产上建造以下三种建筑之一:
- House(房屋):价值最低,默认建造,单地产最多可建16个
- Hotel(酒店):建造需消耗对应地产上的3个House,单地产最多可建8个
- Sky scraper(摩天大楼):价值最高,建造需消耗对应地产上的2个Hotel,单地产最多可建1个
均匀分布要求
所有建筑必须在地产间均匀升级,例如2个地产的升级顺序示例:
- 地产1建House
- 地产2建House
- 地产1建House
- 地产2建House
- 地产1建House
- 地产2建House
- 地产1建Hotel(同时移除该地产上的3个House)
- 地产2建Hotel(同时移除该地产上的3个House)
- 地产1建House
堆叠限制
仅当某地产的Sky scraper和Hotel均达到上限后,该地产的House才可继续堆叠至16个。
需求
编写一个函数,参数为numOfProperties(地产数量)、numOfSkyScrapers(已建摩天大楼总数)、numOfHotels(已建酒店总数)、numOfHouses(已建房屋总数),输出下一个应建造的建筑类型。要求不可使用循环,可使用模运算符。
现有问题
现有代码在单地产场景下正常,但在2地产场景的第8次升级时错误返回House,实际应为Hotel。原因是建造第一个Hotel后移除了对应地产的3个House,导致总House数回到3,函数错误判断应建造House。
现有代码
function nextBuilding(numProperties, numHouses, numHotels, numSkyscrapers) { // 单地产上限 const maxHousesPerProperty = 16; const maxHotelsPerProperty = 8; const maxSkyscrapersPerProperty = 1; // 转换比例 const housesPerHotel = 3; const hotelsPerSkyscraper = 2; // 计算平均每个地产的建筑数量 const housesPerProperty = Math.floor(numHouses / numProperties); const hotelsPerProperty = Math.floor(numHotels / numProperties); const skyscrapersPerProperty = Math.floor(numSkyscrapers / numProperties); // 计算余数用于平衡地产间的建筑分布 const housesRemainder = numHouses % numProperties; const hotelsRemainder = numHotels % numProperties; const skyscrapersRemainder = numSkyscrapers % numProperties; // 计算下一个要升级的地产索引 const nextPropertyIndex = (numHouses + (numHotels * housesPerHotel) + (numSkyscrapers * hotelsPerSkyscraper * housesPerHotel)) % numProperties; // 判断下一个建造的建筑类型 if ((skyscrapersPerProperty < maxSkyscrapersPerProperty) && (numHotels >= hotelsPerSkyscraper)) { // 检查是否有足够酒店建造摩天大楼 return "skyscraper"; } if ((hotelsPerProperty < maxHotelsPerProperty) && (numHouses >= housesPerHotel)) { // 检查是否有足够房屋建造酒店 return "hotel"; } if (housesPerProperty < maxHousesPerProperty) { return "house"; } return "No building needed"; }
优化后的解决方案
问题根源在于现有代码仅通过全局总数判断是否满足建造条件,而非针对下一个要升级的地产的当前状态判断。我们需要计算目标地产的实际建筑数量,再根据规则判断下一步操作:
function nextBuilding(numProperties, numHouses, numHotels, numSkyscrapers) { // 单地产上限 const maxHouses = 16; const maxHotels = 8; const maxSkyscrapers = 1; // 转换比例 const housesPerHotel = 3; const hotelsPerSkyscraper = 2; // 计算每个地产的累计"等效房屋数"(用于确定下一个升级的地产) // 每个Hotel等效3个House,每个Skyscraper等效2*3=6个House const totalEquivalentHouses = numHouses + numHotels * housesPerHotel + numSkyscrapers * hotelsPerSkyscraper * housesPerHotel; const nextPropIdx = totalEquivalentHouses % numProperties; // 计算目标地产的实际建筑数量 // 摩天大楼:先算平均,再看余数是否覆盖当前索引 const skyscrapersOnProp = Math.floor(numSkyscrapers / numProperties) + (nextPropIdx < numSkyscrapers % numProperties ? 1 : 0); // 酒店:排除已经用来建摩天大楼的酒店后,计算当前地产的数量 const availableHotels = numHotels - skyscrapersOnProp * hotelsPerSkyscraper; const hotelsOnProp = Math.floor(availableHotels / numProperties) + (nextPropIdx < availableHotels % numProperties ? 1 : 0); // 房屋:排除用来建酒店和摩天大楼的房屋后,计算当前地产的数量 const consumedHouses = (hotelsOnProp * housesPerHotel * numProperties) + (skyscrapersOnProp * hotelsPerSkyscraper * housesPerHotel); const availableHouses = numHouses - consumedHouses; const housesOnProp = Math.floor(availableHouses / numProperties) + (nextPropIdx < availableHouses % numProperties ? 1 : 0); // 按优先级判断下一个建筑:摩天大楼 > 酒店 > 房屋 if (skyscrapersOnProp < maxSkyscrapers && hotelsOnProp >= hotelsPerSkyscraper) { return "skyscraper"; } if (hotelsOnProp < maxHotels && housesOnProp >= housesPerHotel) { return "hotel"; } // 仅当摩天大楼和酒店都达上限时,才允许房屋堆到16;否则最多先建到3个 const canBuildHouse = (skyscrapersOnProp === maxSkyscrapers && hotelsOnProp === maxHotels) ? housesOnProp < maxHouses : housesOnProp < housesPerHotel; if (canBuildHouse) { return "house"; } return "No building needed"; }
优化说明
- 精准定位目标地产:通过等效房屋数计算下一个要升级的地产索引,确保均匀分布逻辑正确。
- 计算地产实际状态:扣除已用于升级更高建筑的消耗,准确算出目标地产当前拥有的House、Hotel、Skyscraper数量。
- 规则严格匹配:按照摩天大楼→酒店→房屋的优先级判断,并且严格遵循"仅当高等级建筑达上限后,才允许房屋堆叠至16"的限制。
内容的提问来源于stack exchange,提问作者Will
相关产品推荐
相关产品推荐

