A man has a rather old car being worth $2000. He saw a secondhand car being worth$8000. He wants to keep his old car until he can buy the secondhand one.

He thinks he can save \$1000 each month but the prices of his old car and of the new one decrease of 1.5 percent per month. Furthermore the percent of loss increases by a fixed 0.5percent at the end of every two months.

Example of percents lost per month:

If, for example, at the end of first month the percent of loss is 1, end of second month percent of loss is 1.5, end of third month still 1.5, end of 4th month 2 and so on ...

Can you help him? Our man finds it difficult to make all these calculations.

How many months will it take him to save up enough money to buy the car he wants, and how much money will he have left over?

Parameters and return of function:

parameter (positive int, guaranteed) startPriceOld (Old car price)
parameter (positive int, guaranteed) startPriceNew (New car price)
parameter (positive int, guaranteed) savingperMonth
parameter (positive float or int, guaranteed) percentLossByMonth

nbMonths(2000, 8000, 1000, 1.5) should return [6, 766] or (6, 766)

where 6 is the number of months at the end of which he can buy the new car and 766 is the nearest integer to '766.158...' .

Note: Selling, buying and saving are normally done at end of month. Calculations are processed at the end of each considered month but if, by chance from the start, the value of the old car is bigger than the value of the new one or equal there is no saving to be made, no need to wait so he can at the beginning of the month buy the new car:

nbMonths(12000, 8000, 1000, 1.5) should return [0, 4000]
nbMonths(8000, 8000, 1000, 1.5) should return [0, 0]

We don't take care of a deposit of savings in a bank.

1. 落地折舊價比例：題目中參數的 percentLossByMonth
2. 每兩個月的折舊比例：0.5 percent

1. startPriceOld：舊車目前的價格
2. startPriceNew：新車目前的價格
3. savingperMonth：每個月要存的錢
4. percentLossByMonth：落地折舊價比例

1. 幾個月之後可以買
2. 買完之後還剩下多少錢

Step 1, 新增測試案例，nbMonths_old_2000_new_8000_perMonthSave_1000_percentLoss_1point5

    [Test]
public void nbMonths_old_12000_new_8000_perMonthSave_1000_percentLoss_1point5()
{
int[] r = new int[] { 0, 4000 };
}

    internal class BuyCar
{
public static int[] nbMonths(int startPriceOld, int startPriceNew, int savingperMonth, float percentLossByMonth)
{
throw new NotImplementedException();
}
}

Step 2, hard-code 判斷式以通過測試案例

    internal class BuyCar
{
public static int[] nbMonths(int startPriceOld, int startPriceNew, int savingperMonth, float percentLossByMonth)
{
var month = 0;
var leftOverMoney = 0;
if (startPriceOld >= startPriceNew)
{
leftOverMoney = startPriceOld - startPriceNew;
}

return new int[] {month, leftOverMoney};
}
}

Step 5, 補上每兩個月折舊 0.5% 的測試案例，nbMonths_old_2000_new_8000_perMonthSave_1000_percentLoss_1point5

    [Test]
public void nbMonths_old_2000_new_8000_perMonthSave_1000_percentLoss_1point5()
{
int[] r = new int[] { 6, 766 };
//{ 0.985 , 0.98 , 0.98 , 0.975 , 0.975 , 0.97 }
//new one after 6 month: 6978.4558389
//old one after 6 month: 1744.613959725

}

1. 將每兩個月折舊遞減的 0.5% 抽到 const：LossRatioBiMonth
2. 去除一開始因應第一個測試案例的判斷式: if (startPriceOld >= startPriceNew) ，因為商業邏輯以被後面的 do while 迴圈涵蓋。
3. 將 do while 迴圈改成 while 迴圈，在這例子上更好懂一些。

    internal class BuyCar
{
private const double LossRatioBiMonth = 0.005d;

public static int[] nbMonths(int startPriceOld, int startPriceNew, int savingperMonth, float percentLossByMonth)
{
double oldOneValue = startPriceOld;
double newOneValue = startPriceNew;
var month = 0;
var savingAmount = 0;

double ratio = 1 - (double)((decimal)percentLossByMonth / 100);
while ((oldOneValue + savingAmount) < newOneValue)
{
month++;
savingAmount += savingperMonth;

ratio -= month % 2 == 0 ? LossRatioBiMonth : 0;

oldOneValue *= ratio;
newOneValue *= ratio;
}

var leftOverMoney = oldOneValue + savingAmount - newOneValue;

return new int[] { month, (int)Math.Round(leftOverMoney, 0) };
}
}

結論

GitHub commit history: Buying A Car
 想收到第一手公開培訓課程資訊，或想詢問企業內訓、顧問、教練、諮詢服務的，請加 Odd-e Line 帳號。