Permalink
Browse files

Implement the house refund calculation

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 03e36f7247d53b960355e1b2e1ce3125c5c640b3
@@ -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
// |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
// houses very frequently (which will turn out expensive for them).
calculateHouseValue(position, parkingLotCount, interiorValue, ownershipSeconds) {
// TODO: Implement this calculation.
return 25;
calculateHouseValue(position, parkingLotCount, interiorValue, ownershipDuration) {
return this.economyCalculator_.calculateHouseValue(
/* purchasePrice */ this.calculateHousePrice(
position, parkingLotCount, interiorValue),
/* ownershipDuration */ ownershipDuration);
}
// Calculates the price for the given |feature| for a house at |position|.
calculateHouseFeaturePrice(position, feature) {
// TODO: Enable having different prices for different |feature|s.
const featureValue = 2; // [0, 5]
let featureValue = null;
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(
/* residentialValue */ this.residentialValueMap_.query(position),
@@ -28,7 +28,7 @@ class EconomyCalculator {
// |interiorValue| must be in range of [0, 9]. The variance factor will be included. This value
// 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) {
if (residentialValue < 0 || residentialValue > 5) {
@@ -78,11 +78,37 @@ class EconomyCalculator {
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],
// 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.
//
// https://docs.google.com/spreadsheets/d/1rgydvkX5DEX7tXH8pvQggIOTg2RQpvfqzJEH6ZsKbyE/edit
// https://docs.google.com/spreadsheets/d/1R01tp9WF_lHS3JP2DDqsLKhZOM7illJa3DF4gK3t3yY/edit
//
calculateHouseFeaturePrice(residentialValue, featureValue) {
if (residentialValue < 0 || residentialValue > 5) {
@@ -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 => {
// Returns the house price that has been determined for the three input values.
const calculateFeaturePrice = (residentialValue, featureValue, varianceValue) => {

0 comments on commit 03e36f7

Please sign in to comment.