Skip to content

Commit

Permalink
Implement the house refund calculation
Browse files Browse the repository at this point in the history
Fixes #268. Players will receive between 35% and 70% of their purchase
price, depending on how long they owned their house.
  • Loading branch information
RussellLVP committed Oct 20, 2016
1 parent 4c6b71f commit 03e36f7
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 8 deletions.
23 changes: 17 additions & 6 deletions javascript/features/economy/economy.js
Expand Up @@ -32,18 +32,29 @@ class Economy extends Feature {
} }


// Calculates the value of a house after it has been in possession of a particular player for // Calculates the value of a house after it has been in possession of a particular player for
// |ownershipSeconds| seconds. Different from normal economics, the value of a house increases // |ownershipDuration| seconds. Different from normal economics, the value of a house increases
// as the player owns it for a longer amount of time, to discourage players from switching // as the player owns it for a longer amount of time, to discourage players from switching
// houses very frequently (which will turn out expensive for them). // houses very frequently (which will turn out expensive for them).
calculateHouseValue(position, parkingLotCount, interiorValue, ownershipSeconds) { calculateHouseValue(position, parkingLotCount, interiorValue, ownershipDuration) {
// TODO: Implement this calculation. return this.economyCalculator_.calculateHouseValue(
return 25; /* purchasePrice */ this.calculateHousePrice(
position, parkingLotCount, interiorValue),
/* ownershipDuration */ ownershipDuration);
} }


// Calculates the price for the given |feature| for a house at |position|. // Calculates the price for the given |feature| for a house at |position|.
calculateHouseFeaturePrice(position, feature) { calculateHouseFeaturePrice(position, feature) {
// TODO: Enable having different prices for different |feature|s. let featureValue = null;
const featureValue = 2; // [0, 5]
switch (feature) {
case 'health': // health pickup
case 'armour': // armour pickup
featureValue = 2;
break;

default:
throw new Error('Unrecognized house feature: ' + feature);
}


return this.economyCalculator_.calculateHouseFeaturePrice( return this.economyCalculator_.calculateHouseFeaturePrice(
/* residentialValue */ this.residentialValueMap_.query(position), /* residentialValue */ this.residentialValueMap_.query(position),
Expand Down
30 changes: 28 additions & 2 deletions javascript/features/economy/economy_calculator.js
Expand Up @@ -28,7 +28,7 @@ class EconomyCalculator {
// |interiorValue| must be in range of [0, 9]. The variance factor will be included. This value // |interiorValue| must be in range of [0, 9]. The variance factor will be included. This value
// is being calculated based on the following spreadsheet: // is being calculated based on the following spreadsheet:
// //
// https://docs.google.com/spreadsheets/d/1rgydvkX5DEX7tXH8pvQggIOTg2RQpvfqzJEH6ZsKbyE/edit // https://docs.google.com/spreadsheets/d/1R01tp9WF_lHS3JP2DDqsLKhZOM7illJa3DF4gK3t3yY/edit
// //
calculateHousePrice(residentialValue, parkingLotCount, interiorValue) { calculateHousePrice(residentialValue, parkingLotCount, interiorValue) {
if (residentialValue < 0 || residentialValue > 5) { if (residentialValue < 0 || residentialValue > 5) {
Expand Down Expand Up @@ -78,11 +78,37 @@ class EconomyCalculator {
return fixedPrice * varianceFactor; return fixedPrice * varianceFactor;
} }


// Calculates the current house value based on the |purchasePrice| and the |ownershipDuration|.
// The value will be influenced by the variance factor by up to 5%.
//
// https://docs.google.com/spreadsheets/d/1R01tp9WF_lHS3JP2DDqsLKhZOM7illJa3DF4gK3t3yY/edit
//
calculateHouseValue(purchasePrice, ownershipDuration) {
const BaseRefundPercentage = 35;
const MaximumRefundPercentage = 70;

const MaximizeRefundPeriod = 30 /* days */ * 86400;

// Determine the refund percentage based on the |ownershipDuration|.
const refundPercentage =
Math.min(MaximumRefundPercentage,
BaseRefundPercentage + ((MaximumRefundPercentage - BaseRefundPercentage) *
(ownershipDuration / MaximizeRefundPeriod)));

// Calculate the refund based on the |purchasePrice| and the |refundPercentage|.
const refund = purchasePrice * (refundPercentage / 100);

// The variance will either decrease or increase the refund by, at most, 5%.
const varianceFactor = 1 + ((-50 + this.varianceValue_) / 1000);

return refund * varianceFactor;
}

// Calculates the price for a feature of value |featureValue|, which must be in range of [0, 5], // Calculates the price for a feature of value |featureValue|, which must be in range of [0, 5],
// at a location having |residentialValue|, which must be in range of [0, 5] as well. The // at a location having |residentialValue|, which must be in range of [0, 5] as well. The
// variance factor will be included in the feature's price as well. // variance factor will be included in the feature's price as well.
// //
// https://docs.google.com/spreadsheets/d/1rgydvkX5DEX7tXH8pvQggIOTg2RQpvfqzJEH6ZsKbyE/edit // https://docs.google.com/spreadsheets/d/1R01tp9WF_lHS3JP2DDqsLKhZOM7illJa3DF4gK3t3yY/edit
// //
calculateHouseFeaturePrice(residentialValue, featureValue) { calculateHouseFeaturePrice(residentialValue, featureValue) {
if (residentialValue < 0 || residentialValue > 5) { if (residentialValue < 0 || residentialValue > 5) {
Expand Down
27 changes: 27 additions & 0 deletions javascript/features/economy/economy_calculator.test.js
Expand Up @@ -82,6 +82,33 @@ describe('EconomyCalculator', (it, beforeEach, afterEach) => {
}); });
}); });


it('should be able to determine the value for a house appropriately', assert => {
// Returns the value for a house based on its purchase price and ownership days,
const calculateHousePrice = (purchasePrice, ownershipDays, varianceValue) => {
calculator.setVarianceValueForTests(varianceValue);
return calculator.calculateHouseValue(purchasePrice, ownershipDays * 86400);
};

const PurchasePrice = 80643816.73;
const MaximumRefundValue = 0.7 * PurchasePrice;

// Change detector tests against the spreadsheet.
assert.closeTo(calculateHousePrice(PurchasePrice, 0.5, 50), 28695758.12, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 1, 50), 29166180.38, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 3, 50), 31047869.44, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 7, 50), 34811247.56, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 14, 50), 41397159.25, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 30.25, 50), 56450671.71, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 60.50, 50), 56450671.71, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 90.75, 50), 56450671.71, 1);

// Verify that the variance is no more than 5% of the total house price.
assert.closeTo(calculateHousePrice(PurchasePrice, 100, 0), 0.95 * MaximumRefundValue, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 100, 50), MaximumRefundValue, 1);
assert.closeTo(calculateHousePrice(PurchasePrice, 100, 100), 1.05 * MaximumRefundValue, 1);

});

it('should be able to price features for houses appropriately', assert => { it('should be able to price features for houses appropriately', assert => {
// Returns the house price that has been determined for the three input values. // Returns the house price that has been determined for the three input values.
const calculateFeaturePrice = (residentialValue, featureValue, varianceValue) => { const calculateFeaturePrice = (residentialValue, featureValue, varianceValue) => {
Expand Down

0 comments on commit 03e36f7

Please sign in to comment.