diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..24e7395d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +out +*.iml +.idea \ No newline at end of file diff --git a/Java/TollCalculator.java b/Java/TollCalculator.java index d239f327..6d70a7fa 100644 --- a/Java/TollCalculator.java +++ b/Java/TollCalculator.java @@ -1,4 +1,9 @@ +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalField; import java.util.*; import java.util.concurrent.*; @@ -12,25 +17,29 @@ public class TollCalculator { * @return - the total toll fee for that day */ public int getTollFee(Vehicle vehicle, Date... dates) { - Date intervalStart = dates[0]; - int totalFee = 0; + // I believe in this method the times 08:40 and 09:20 should consider as times of 2 different hours (i.e. hour of 8 and hour of 9. + // In the previous logic if the 08:40 was the first of the array then 09:20 was considered as same hour because it has considered the time gap + // Also the previous implementation was not updating the intervalStart correctly. + + int[] feeOfTheHour = new int[24]; + Arrays.fill(feeOfTheHour, 0); + + // calculate max fee for each hour for (Date date : dates) { - int nextFee = getTollFee(date, vehicle); - int tempFee = getTollFee(intervalStart, vehicle); - - TimeUnit timeUnit = TimeUnit.MINUTES; - long diffInMillies = date.getTime() - intervalStart.getTime(); - long minutes = timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS); - - if (minutes <= 60) { - if (totalFee > 0) totalFee -= tempFee; - if (nextFee >= tempFee) tempFee = nextFee; - totalFee += tempFee; - } else { - totalFee += nextFee; + int fee = getTollFee(date, vehicle); + int hour = Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).getHour(); + + if(feeOfTheHour[hour] < fee){ + feeOfTheHour[hour] = fee; } } + + // get the sum of hourly fee + int totalFee = Arrays.stream(feeOfTheHour).sum(); + + // cap the value if (totalFee > 60) totalFee = 60; + return totalFee; } @@ -56,9 +65,11 @@ public int getTollFee(final Date date, Vehicle vehicle) { else if (hour == 6 && minute >= 30 && minute <= 59) return 13; else if (hour == 7 && minute >= 0 && minute <= 59) return 18; else if (hour == 8 && minute >= 0 && minute <= 29) return 13; - else if (hour >= 8 && hour <= 14 && minute >= 30 && minute <= 59) return 8; + else if (hour == 8 && minute >= 30 && minute <= 59) return 8; + else if (hour >= 9 && hour <= 14 && minute >= 0 && minute <= 59) return 8; else if (hour == 15 && minute >= 0 && minute <= 29) return 13; - else if (hour == 15 && minute >= 0 || hour == 16 && minute <= 59) return 18; + else if (hour == 15 && minute >= 30 && minute <= 59) return 18; + else if (hour == 16 && minute >= 0 && minute <= 59) return 18; else if (hour == 17 && minute >= 0 && minute <= 59) return 13; else if (hour == 18 && minute >= 0 && minute <= 29) return 8; else return 0; @@ -74,6 +85,7 @@ private Boolean isTollFreeDate(Date date) { int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); if (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) return true; + //TODO - consider every year differently or remove the year validation if (year == 2013) { if (month == Calendar.JANUARY && day == 1 || month == Calendar.MARCH && (day == 28 || day == 29) || diff --git a/Java/ToolCalculatorTest.java b/Java/ToolCalculatorTest.java new file mode 100644 index 00000000..fdc2834e --- /dev/null +++ b/Java/ToolCalculatorTest.java @@ -0,0 +1,68 @@ +import java.time.LocalDateTime; +import java.time.Month; +import java.time.ZoneId; +import java.util.Date; + +public class ToolCalculatorTest { + public static void main(String[] args) { + TollCalculator tollCalculator = new TollCalculator(); + Date[] dateTimeArrayWeekDayLarge = new Date[]{ + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 7, 30).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 7, 52).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 17).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 39).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 48).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 11, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 13, 45).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 16, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 16, 40).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 17, 40).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 17, 48).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 18, 12).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 18, 27).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 18, 43).atZone(ZoneId.systemDefault()).toInstant()) + }; + + Date[] dateTimeArrayWeekDaySmall = new Date[]{ + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 17).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 39).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 8, 48).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 11, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 17, 40).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 17, 48).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 18, 12).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 18, 27).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 14, 18, 43).atZone(ZoneId.systemDefault()).toInstant()) + }; + + Date[] dateTimeArrayWeekEnd = new Date[]{ + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 8, 17).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 8, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 8, 39).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 8, 48).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 11, 25).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 17, 40).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 17, 48).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 18, 12).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 18, 27).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(LocalDateTime.of(2022, Month.MARCH, 12, 18, 43).atZone(ZoneId.systemDefault()).toInstant()) + }; + + test(tollCalculator, new Car(), dateTimeArrayWeekDayLarge, 60, "Weekday Fees on Car with Cap"); + test(tollCalculator, new Car(), dateTimeArrayWeekDaySmall, 42, "Weekday Fees on Car without Cap"); + test(tollCalculator, new Car(), dateTimeArrayWeekEnd, 0, "Weekend Fees on Car"); + test(tollCalculator, new Motorbike(), dateTimeArrayWeekEnd, 0, "Weekend Fees on Motorbike"); + test(tollCalculator, new Motorbike(), dateTimeArrayWeekDaySmall, 0, "Weekday Fees on Motorbike"); + } + + private static void test(TollCalculator tollCalculator, Vehicle vehicle, Date[] datesArray, int expectedFee, String testScenario){ + int tollFee = tollCalculator.getTollFee(vehicle, datesArray); + if(tollFee == expectedFee){ + System.out.printf("Test '%s' executed successfully.%n", testScenario); + } else { + System.out.printf("Test '%s' failed. Expected fee is %d SEK and actual fee returned is %d SEK.%n", testScenario, expectedFee, tollFee); + } + } +} diff --git a/README.md b/README.md index 37682baa..75de7470 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ A calculator for vehicle toll fees. * Make sure you read these instructions carefully * The current code base is in Java and C#, but please make sure that you do an implementation in a language **you feel comfortable** in like Javascript, Python, Assembler or [ModiScript](https://en.wikipedia.org/wiki/ModiScript) (please don't choose ModiScript). * No requirement but bonus points if you know what movie is in the gif + * This is taken from the Hackers movie directed by Iain Softly ## Background Our city has decided to implement toll fees in order to reduce traffic congestion during rush hours.