javascriptmathlogicformulapseudocode

Determine next building upgrade in Monopoly


Each street in Monopoly is comprised of 2 or 3 different properties.

When a user upgrades a street, it will build 1 of 3 buildings on the appropriate property.

Each type of building needs to be spread evenly. For example if there's 2 properties, the order of upgrades would be:

  1. House on property 1
  2. House on property 2
  3. House on property 1
  4. House on property 2
  5. House on property 1
  6. House on property 2
  7. Hotel on property 1 (also delete 3 houses)
  8. Hotel on property 2 (also delete 3 houses)
  9. House on property 1

The only time there would be more than 3 houses on a property is after the skyscrapers and hotels are both maxed out, then the houses would stack up until 16 on each property.

I need a function that will calculate this. The parameters of this function are numOfProperties, numOfSkyScrapers, numOfHotels, numOfHouses and it needs to output which building should be next.

This function cannot use looping. I think the mod operator would be useful.

My code below works when there is 1 property. But with 2 properties, upgrade 8 is a house when it should be a hotel. It's because after the first hotel upgrade, it deletes that properties 3 houses, so the total number is 3 again and builds another house.

I'm not sure how I can make this dynamic and work for all amount of properties

function nextBuilding(numProperties, numHouses, numHotels, numSkyscrapers) {
    // Maximum limits per property
    const maxHousesPerProperty = 16;
    const maxHotelsPerProperty = 8;
    const maxSkyscrapersPerProperty = 1;

    // Conversion ratios
    const housesPerHotel = 3;
    const hotelsPerSkyscraper = 2;

    // Calculate the number of buildings per property
    const housesPerProperty = Math.floor(numHouses / numProperties);
    const hotelsPerProperty = Math.floor(numHotels / numProperties);
    const skyscrapersPerProperty = Math.floor(numSkyscrapers / numProperties);

    // Calculate remainders to help balance the properties
    const housesRemainder = numHouses % numProperties;
    const hotelsRemainder = numHotels % numProperties;
    const skyscrapersRemainder = numSkyscrapers % numProperties;

    // Determine the position for the next building
    const nextPropertyIndex = (numHouses + (numHotels * housesPerHotel) + (numSkyscrapers * hotelsPerSkyscraper * housesPerHotel)) % numProperties;

    // Determine the next building to construct
    if ((skyscrapersPerProperty < maxSkyscrapersPerProperty) && (numHotels >= hotelsPerSkyscraper)) {
        // Check if there are enough hotels for the next skyscraper
        return "skyscraper";
    }
    if ((hotelsPerProperty < maxHotelsPerProperty) && (numHouses >= housesPerHotel)) {
        // Check if there are enough houses for the next hotel
        return "hotel";
    }
    if (housesPerProperty < maxHousesPerProperty) {
        return "house";
    }

    return "No building needed";
}

Solution

  • Ruby code (IDK javascript; read as pseudocode):

    def f(numOfHouses, numOfHotels, numOfSkyScrapers, numOfProperties)
      return "skyScraper" if numOfSkyScrapers % numOfProperties != 0
      return "skyScraper" if numOfSkyScrapers == 0 && numOfHotels == numOfProperties * 2
      return "hotel" if numOfHotels % numOfProperties != 0
      return "hotel" if numOfHotels < 8 * numOfProperties && numOfHouses == numOfProperties * 3
      return "house" if numOfHouses < 16
      return "no building needed"
    end
    

    Is this clear? We build skyscrapers if either we're not maxed out and we have the right number of hotels, or we're in the process of building a set of skyscrapers (so count mod properties isn't zero).

    If we're not building skyscrapers, we build hotels following the same logic.

    Otherwise we build houses if we have capacity.

    Sample output:

    > f(0,0,0,2)
    => "house"
    > f(1,0,0,2)
    => "house"
    > f(2,0,0,2)
    => "house"
    > f(3,0,0,2)
    => "house"
    > f(4,0,0,2)
    => "house"
    > f(5,0,0,2)
    => "house"
    > f(6,0,0,2)
    => "hotel"
    > f(3,1,0,2)
    => "hotel"
    > f(0,2,0,2)
    => "house"
    > f(1,2,0,2)
    => "house"
    > f(2,2,0,2)
    => "house"
    > f(6,2,0,2)
    => "hotel"
    > f(3,3,0,2)
    => "hotel"
    > f(0,4,0,2)
    => "skyScraper"