From 10b93279690da7c90898281a3fbbb7559859f96c Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:33:49 +0000 Subject: [PATCH 1/7] Setting up GitHub Classroom Feedback From 44d5676cbfd3854f35461c2389cacccef0392e41 Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Wed, 24 Sep 2025 17:21:49 +0200 Subject: [PATCH 2/7] Day1. Most of the functions implemented, missing some statistical calculations. --- src/main/java/com/example/Main.java | 102 ++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 20a692ac..5359bdce 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -2,8 +2,110 @@ import com.example.api.ElpriserAPI; +import java.time.LocalDate; +import java.util.Comparator; +import java.util.List; + public class Main { public static void main(String[] args) { ElpriserAPI elpriserAPI = new ElpriserAPI(); + + if(args[0].equals("--zone")) + determineUsage(args, elpriserAPI); + else + printHelp(); + } + + private static void printHelp() { + System.out.println(""" + Expected Command-Line Arguments: + --zone SE1|SE2|SE3|SE4 (required) + --date YYYY-MM-DD (optional, defaults to current date) + --sorted (optional, to display prices in descending order) + --charging 2h|4h|8h (optional, to find optimal charging windows)"""); + } + + private static void determineUsage(String[] args, ElpriserAPI priceList) { + ElpriserAPI.Prisklass zone; + switch (args[1]){ + case "SE1" -> zone = ElpriserAPI.Prisklass.SE1; + case "SE2" -> zone = ElpriserAPI.Prisklass.SE2; + case "SE3" -> zone = ElpriserAPI.Prisklass.SE3; + case "SE4" -> zone = ElpriserAPI.Prisklass.SE4; + default -> { + printHelp(); + return; + } + } + if(args.length < 3){ + printPricesForList(priceList.getPriser(LocalDate.now(), zone)); + } else if(args[2].equals("--charging")){ + printChargePrice(priceList.getPriser(LocalDate.now(), zone), args[3]); + } else if(args[2].equals("--sorted")){ + printSortedPricesForList(priceList.getPriser(LocalDate.now(), zone)); + } else if(args[2].equals("--date")){ + if(args.length < 5){ + printPricesForList(priceList.getPriser(args[3], zone)); + } else if(args[4].equals("--sorted")){ + printSortedPricesForList(priceList.getPriser(args[3], zone)); + } else{ + printHelp(); + } + } else { + printHelp(); + } + } + + private static void printChargePrice(List prices, String args) { + //sliding window algorithm, 2h 4h 8h + int chargeDuration = args.charAt(0) - '0'; + List chargeWindow = prices.subList(0,4); + double lowestSum = 0; + + for (int i = 0; i < chargeDuration; i++) { + lowestSum += prices.get(i).sekPerKWh(); + } + + double windowSum = lowestSum; + for (int i = chargeDuration; i < prices.size(); i++) { + windowSum += prices.get(i).sekPerKWh() - prices.get(i - chargeDuration).sekPerKWh(); + if(Math.min(lowestSum, windowSum) == windowSum){ + chargeWindow = prices.subList(i+1 - chargeWindow.size(), i+1); + } + lowestSum = Math.min(lowestSum, windowSum); + } + + System.out.printf("Medelpris: %.1f öre/KWh\n", lowestSum/chargeDuration*100); + System.out.println("Ladda mellan " + formattedStartTime(chargeWindow.getFirst()) + " och " + formattedEndTime(chargeWindow.getLast())); + } + + private static void printSortedPricesForList(List prices) { + List sortedList = prices.stream() + .sorted(Comparator.comparing(ElpriserAPI.Elpris::sekPerKWh).reversed() + .thenComparing(ElpriserAPI.Elpris::timeStart)) + .toList(); + + printPricesForList(sortedList); + } + + private static void printPricesForList(List pricelist) { + for (ElpriserAPI.Elpris price : pricelist) { + //System.out.printf(formattedStartTime(price) + "-" + formattedEndTime(price) + ": %.1f öre\n", price.sekPerKWh()*100); + System.out.printf("Mellan " + formattedStartTime(price) + " och " + formattedEndTime(price) + ": %.1f öre/KWh\n", price.sekPerKWh()*100); + } + } + + private static String formattedStartTime(ElpriserAPI.Elpris source){ + String startTime; + //startTime = String.format("%02d", source.timeStart().getHour()); + startTime = String.format("%02d", source.timeStart().getHour()) + ":" + String.format("%02d", source.timeStart().getMinute()); + return startTime; + } + + private static String formattedEndTime(ElpriserAPI.Elpris source){ + String endTime; + //endTime = String.format("%02d", source.timeEnd().getHour()); + endTime = String.format("%02d", source.timeEnd().getHour()) + ":" + String.format("%02d", source.timeEnd().getMinute()); + return endTime; } } From 1805b2dc450b3169d2b4c683b0a0007aedd0152c Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Thu, 25 Sep 2025 09:00:18 +0200 Subject: [PATCH 3/7] Day1. Most of the functions implemented, missing some statistical calculations. --- src/main/java/com/example/Main.java | 3 +- src/test/java/com/example/MainTest.java | 162 ++++++++++++++---------- 2 files changed, 96 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 5359bdce..70b1b46f 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -1,11 +1,11 @@ package com.example; import com.example.api.ElpriserAPI; - import java.time.LocalDate; import java.util.Comparator; import java.util.List; + public class Main { public static void main(String[] args) { ElpriserAPI elpriserAPI = new ElpriserAPI(); @@ -16,6 +16,7 @@ public static void main(String[] args) { printHelp(); } + private static void printHelp() { System.out.println(""" Expected Command-Line Arguments: diff --git a/src/test/java/com/example/MainTest.java b/src/test/java/com/example/MainTest.java index 6199d951..c61f3589 100644 --- a/src/test/java/com/example/MainTest.java +++ b/src/test/java/com/example/MainTest.java @@ -43,7 +43,8 @@ void getPriser_shouldReturnParsedPrices_whenMockDataIsProvided() { [{"SEK_per_kWh":0.12229,"EUR_per_kWh":0.01112,"EXR":10.997148,"time_start":"2025-09-04T00:00:00+02:00","time_end":"2025-09-04T01:00:00+02:00"},{"SEK_per_kWh":0.09886,"EUR_per_kWh":0.00899,"EXR":10.997148,"time_start":"2025-09-04T01:00:00+02:00","time_end":"2025-09-04T02:00:00+02:00"},{"SEK_per_kWh":0.09095,"EUR_per_kWh":0.00827,"EXR":10.997148,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"},{"SEK_per_kWh":0.04201,"EUR_per_kWh":0.00382,"EXR":10.997148,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"},{"SEK_per_kWh":0.04146,"EUR_per_kWh":0.00377,"EXR":10.997148,"time_start":"2025-09-04T04:00:00+02:00","time_end":"2025-09-04T05:00:00+02:00"},{"SEK_per_kWh":0.04465,"EUR_per_kWh":0.00406,"EXR":10.997148,"time_start":"2025-09-04T05:00:00+02:00","time_end":"2025-09-04T06:00:00+02:00"},{"SEK_per_kWh":0.32991,"EUR_per_kWh":0.03,"EXR":10.997148,"time_start":"2025-09-04T06:00:00+02:00","time_end":"2025-09-04T07:00:00+02:00"},{"SEK_per_kWh":0.47123,"EUR_per_kWh":0.04285,"EXR":10.997148,"time_start":"2025-09-04T07:00:00+02:00","time_end":"2025-09-04T08:00:00+02:00"},{"SEK_per_kWh":0.68182,"EUR_per_kWh":0.062,"EXR":10.997148,"time_start":"2025-09-04T08:00:00+02:00","time_end":"2025-09-04T09:00:00+02:00"},{"SEK_per_kWh":0.4125,"EUR_per_kWh":0.03751,"EXR":10.997148,"time_start":"2025-09-04T09:00:00+02:00","time_end":"2025-09-04T10:00:00+02:00"},{"SEK_per_kWh":0.29571,"EUR_per_kWh":0.02689,"EXR":10.997148,"time_start":"2025-09-04T10:00:00+02:00","time_end":"2025-09-04T11:00:00+02:00"},{"SEK_per_kWh":0.06136,"EUR_per_kWh":0.00558,"EXR":10.997148,"time_start":"2025-09-04T11:00:00+02:00","time_end":"2025-09-04T12:00:00+02:00"},{"SEK_per_kWh":0.03662,"EUR_per_kWh":0.00333,"EXR":10.997148,"time_start":"2025-09-04T12:00:00+02:00","time_end":"2025-09-04T13:00:00+02:00"},{"SEK_per_kWh":0.0375,"EUR_per_kWh":0.00341,"EXR":10.997148,"time_start":"2025-09-04T13:00:00+02:00","time_end":"2025-09-04T14:00:00+02:00"},{"SEK_per_kWh":0.26822,"EUR_per_kWh":0.02439,"EXR":10.997148,"time_start":"2025-09-04T14:00:00+02:00","time_end":"2025-09-04T15:00:00+02:00"},{"SEK_per_kWh":0.30429,"EUR_per_kWh":0.02767,"EXR":10.997148,"time_start":"2025-09-04T15:00:00+02:00","time_end":"2025-09-04T16:00:00+02:00"},{"SEK_per_kWh":0.36675,"EUR_per_kWh":0.03335,"EXR":10.997148,"time_start":"2025-09-04T16:00:00+02:00","time_end":"2025-09-04T17:00:00+02:00"},{"SEK_per_kWh":0.58296,"EUR_per_kWh":0.05301,"EXR":10.997148,"time_start":"2025-09-04T17:00:00+02:00","time_end":"2025-09-04T18:00:00+02:00"},{"SEK_per_kWh":0.92145,"EUR_per_kWh":0.08379,"EXR":10.997148,"time_start":"2025-09-04T18:00:00+02:00","time_end":"2025-09-04T19:00:00+02:00"},{"SEK_per_kWh":1.5054,"EUR_per_kWh":0.13689,"EXR":10.997148,"time_start":"2025-09-04T19:00:00+02:00","time_end":"2025-09-04T20:00:00+02:00"},{"SEK_per_kWh":1.00888,"EUR_per_kWh":0.09174,"EXR":10.997148,"time_start":"2025-09-04T20:00:00+02:00","time_end":"2025-09-04T21:00:00+02:00"},{"SEK_per_kWh":0.63179,"EUR_per_kWh":0.05745,"EXR":10.997148,"time_start":"2025-09-04T21:00:00+02:00","time_end":"2025-09-04T22:00:00+02:00"},{"SEK_per_kWh":0.56382,"EUR_per_kWh":0.05127,"EXR":10.997148,"time_start":"2025-09-04T22:00:00+02:00","time_end":"2025-09-04T23:00:00+02:00"},{"SEK_per_kWh":0.52951,"EUR_per_kWh":0.04815,"EXR":10.997148,"time_start":"2025-09-04T23:00:00+02:00","time_end":"2025-09-05T00:00:00+02:00"}]"""; // 2. Set the mock response using the static method. - ElpriserAPI.setMockResponse(fakeJson); + LocalDate today = LocalDate.of(2025, 9, 4); + ElpriserAPI.setMockResponseForDate(today,fakeJson); // 3. Create an instance of the class as a student would. ElpriserAPI api = new ElpriserAPI(false); // Disable caching for predictable tests @@ -109,7 +110,8 @@ void displayMeanPrice_withValidData() { {"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"}, {"SEK_per_kWh":0.40,"EUR_per_kWh":0.04,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}]"""; - ElpriserAPI.setMockResponse(mockJson); + LocalDate today = LocalDate.of(2025, 9, 4); + ElpriserAPI.setMockResponseForDate(today,mockJson); Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04"}); @@ -127,7 +129,8 @@ void displayMinMaxPrices_withValidData() { {"SEK_per_kWh":0.80,"EUR_per_kWh":0.08,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"}, {"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}]"""; - ElpriserAPI.setMockResponse(mockJson); + LocalDate today = LocalDate.of(2025, 9, 4); + ElpriserAPI.setMockResponseForDate(today,mockJson); Main.main(new String[]{"--zone", "SE1", "--date", "2025-09-04"}); @@ -144,13 +147,22 @@ void displayMinMaxPrices_withValidData() { @Test void displaySortedPrices_whenRequested() { - String mockJson = """ - [{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T00:00:00+02:00","time_end":"2025-09-04T01:00:00+02:00"}, - {"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T01:00:00+02:00","time_end":"2025-09-04T02:00:00+02:00"}, - {"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"}, - {"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}]"""; + // This test ensures charging window can span days when next day data exists + LocalDate today = LocalDate.of(2025, 9, 4); + LocalDate tomorrow = today.plusDays(1); - ElpriserAPI.setMockResponse(mockJson); + String mockJsonToday = """ + [{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T20:00:00+02:00","time_end":"2025-09-04T21:00:00+02:00"}, + {"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T21:00:00+02:00","time_end":"2025-09-04T22:00:00+02:00"}, + {"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T22:00:00+02:00","time_end":"2025-09-04T23:00:00+02:00"}, + {"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T23:00:00+02:00","time_end":"2025-09-04T00:00:00+02:00"}]"""; + String mockJsonTomorrow = """ + [{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-05T00:00:00+02:00","time_end":"2025-09-05T01:00:00+02:00"}, + {"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T01:00:00+02:00","time_end":"2025-09-05T02:00:00+02:00"}, + {"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T02:00:00+02:00","time_end":"2025-09-05T03:00:00+02:00"}]"""; + + ElpriserAPI.setMockResponseForDate(today, mockJsonToday); + ElpriserAPI.setMockResponseForDate(tomorrow, mockJsonTomorrow); Main.main(new String[]{"--zone", "SE2", "--date", "2025-09-04", "--sorted"}); @@ -158,10 +170,13 @@ void displaySortedPrices_whenRequested() { // Expected sorted output (ascending by price) List expectedOrder = List.of( - "01-02 10,00 öre", - "03-04 10,00 öre", - "02-03 20,00 öre", - "00-01 30,00 öre" + "20-21 30,00 öre", + "22-23 20,00 öre", + "01-02 15,00 öre", + "02-03 15,00 öre", + "21-22 10,00 öre", + "23-00 10,00 öre", + "00-01 10,00 öre" ); // Extract actual lines that match the pattern @@ -183,7 +198,9 @@ void findOptimalCharging2Hours() { {"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}, {"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T04:00:00+02:00","time_end":"2025-09-04T05:00:00+02:00"}]"""; - ElpriserAPI.setMockResponse(mockJson); + LocalDate today = LocalDate.of(2025, 9, 4); + + ElpriserAPI.setMockResponseForDate(today, mockJson); Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04", "--charging", "2h"}); @@ -204,7 +221,9 @@ void findOptimalCharging4Hours() { {"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T04:00:00+02:00","time_end":"2025-09-04T05:00:00+02:00"}, {"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T05:00:00+02:00","time_end":"2025-09-04T06:00:00+02:00"}]"""; - ElpriserAPI.setMockResponse(mockJson); + LocalDate today = LocalDate.of(2025, 9, 4); + + ElpriserAPI.setMockResponseForDate(today, mockJson); Main.main(new String[]{"--zone", "SE1", "--date", "2025-09-04", "--charging", "4h"}); @@ -223,7 +242,9 @@ void chargingWindowDoesNotUseNextDay_whenNextDayUnavailable() { [{"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T00:00:00+02:00","time_end":"2025-09-04T01:00:00+02:00"}, {"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T01:00:00+02:00","time_end":"2025-09-04T02:00:00+02:00"}, {"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"}]"""; - ElpriserAPI.setMockResponse(mockJsonToday); + LocalDate today = LocalDate.of(2025, 9, 4); + ElpriserAPI.setMockResponseForDate(today,mockJsonToday); + Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04", "--charging", "2h"}); String output = bos.toString(); // Best 2h window should be 01-03 (0.10 + 0.15) @@ -235,7 +256,7 @@ void chargingWindowDoesNotUseNextDay_whenNextDayUnavailable() { void findOptimalCharging8Hours() { // Create mock data with 12 hours to allow for 8-hour window StringBuilder jsonBuilder = new StringBuilder("["); - double[] prices = {0.50, 0.10, 0.05, 0.15, 0.08, 0.12, 0.06, 0.09, 0.25, 0.30, 0.35, 0.40}; + double[] prices = {0.50, 0.10, 0.05, 0.15, 0.08, 0.12, 0.06, 0.09, 0.25, 0.30, 0.35, 0.40, 0.50, 0.10, 0.05, 0.15, 0.08, 0.12, 0.06, 0.09, 0.25, 0.30, 0.35, 0.40}; for (int i = 0; i < prices.length; i++) { if (i > 0) jsonBuilder.append(","); @@ -243,12 +264,20 @@ void findOptimalCharging8Hours() { Locale.US, """ {"SEK_per_kWh":%.2f,"EUR_per_kWh":%.3f,"EXR":10.0,"time_start":"2025-09-04T%02d:00:00+02:00","time_end":"2025-09-04T%02d:00:00+02:00"}""", - prices[i], prices[i] / 10, i, i + 1 + prices[i], prices[i] / 10, i, (i + 1) % 24 )); } jsonBuilder.append("]"); - ElpriserAPI.setMockResponse(jsonBuilder.toString()); + LocalDate today = LocalDate.of(2025, 9, 4); + ElpriserAPI.setMockResponseForDate(today, jsonBuilder.toString()); + + LocalDate tomorrow = today.plusDays(1); + String mockJsonTomorrow = """ + [{"SEK_per_kWh":0.1,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-05T00:00:00+02:00","time_end":"2025-09-05T01:00:00+02:00"}, + {"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T01:00:00+02:00","time_end":"2025-09-05T02:00:00+02:00"}, + {"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T02:00:00+02:00","time_end":"2025-09-05T03:00:00+02:00"}]"""; + ElpriserAPI.setMockResponseForDate(tomorrow, mockJsonTomorrow); Main.main(new String[]{"--zone", "SE4", "--date", "2025-09-04", "--charging", "8h"}); @@ -359,66 +388,63 @@ void chargingWindowSpansToNextDay_whenCheapestCrossesMidnight() { } @Test - public void testHourlyMinMaxPrices() { - List quarterHourPrices = new ArrayList<>(); - - // Simulate 96 prices: 24 hours, each with 4 quarter-hour prices - for (int i = 0; i < 96; i++) { - quarterHourPrices.add((double) (i % 24)); // repeating hourly pattern - } + void testHourlyMinMaxPrices_with96Entries() { + // --- ARRANGE --- + LocalDate today = LocalDate.of(2025, 9, 4); + StringBuilder jsonBuilder = new StringBuilder("["); - // Expected hourly averages - List hourlyAverages = new ArrayList<>(); - for (int i = 0; i < 24; i++) { - double sum = 0; - for (int j = 0; j < 4; j++) { - sum += quarterHourPrices.get(i * 4 + j); + for (int hour = 0; hour < 24; hour++) { + for (int quarter = 0; quarter < 4; quarter++) { + if (hour > 0 || quarter > 0) { + jsonBuilder.append(","); + } + double price = (hour * 0.1) + (quarter * 0.01) + 0.10; + String time_start = String.format("2025-09-04T%02d:%02d:00+02:00", hour, quarter * 15); + String time_end = String.format("2025-09-04T%02d:%02d:00+02:00", hour, (quarter + 1) * 15); + if (quarter == 3) { // Handle end of hour + time_end = String.format("2025-09-04T%02d:00:00+02:00", (hour + 1) % 24); + } + + jsonBuilder.append(String.format(Locale.US, + """ + {"SEK_per_kWh":%.4f,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"%s","time_end":"%s"}""", + price, time_start, time_end)); } - hourlyAverages.add(sum / 4.0); } + jsonBuilder.append("]"); + ElpriserAPI.setMockResponseForDate(today, jsonBuilder.toString()); - double expectedMin = Collections.min(hourlyAverages); - double expectedMax = Collections.max(hourlyAverages); + // --- ACT --- + Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04"}); - // Call your method under test - PriceRange result = PriceCalculator.calculateHourlyMinMax(quarterHourPrices); + // --- ASSERT --- + String output = bos.toString(); + assertThat(output).containsIgnoringCase("lägsta pris"); + assertThat(output).containsIgnoringCase("högsta pris"); + assertThat(output).containsIgnoringCase("medelpris"); - assertThat(result.getMin()).isCloseTo(expectedMin, within(0.001)); - assertThat(result.getMax()).isCloseTo(expectedMax, within(0.001)); + // Expected Min: Hour 0 -> avg(0.10, 0.11, 0.12, 0.13) = 0.115 SEK/kWh = 11,50 öre + // Expected Max: Hour 23 -> avg(2.40, 2.41, 2.42, 2.43) = 2.415 SEK/kWh = 241,50 öre + assertThat(output).contains("00-01"); // Cheapest hour + assertThat(output).contains("23-00"); // Most expensive hour + assertThat(output).contains(formatOre(0.115)); + assertThat(output).contains(formatOre(2.415)); + + // Calculate overall average for the day + double totalSum = 0; + for (int hour = 0; hour < 24; hour++) { + for (int quarter = 0; quarter < 4; quarter++) { + totalSum += (hour * 0.1) + (quarter * 0.01) + 0.10; + } + } + double expectedMean = totalSum / 96; + assertThat(output).contains("Medelpris: " + formatOre(expectedMean) + " öre"); } private String formatOre(double sekPerKWh) { double ore = sekPerKWh * 100.0; - DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.of("sv", "SE")); + DecimalFormatSymbols symbols = new DecimalFormatSymbols(new Locale("sv", "SE")); DecimalFormat df = new DecimalFormat("0.00", symbols); return df.format(ore); } -} -class PriceRange { - private final double min; - private final double max; - - public PriceRange(double min, double max) { - this.min = min; - this.max = max; - } - - public double getMin() { return min; } - public double getMax() { return max; } -} - -class PriceCalculator { - public static PriceRange calculateHourlyMinMax(List quarterHourPrices) { - List hourlyAverages = new ArrayList<>(); - for (int i = 0; i < 24; i++) { - double sum = 0; - for (int j = 0; j < 4; j++) { - sum += quarterHourPrices.get(i * 4 + j); - } - hourlyAverages.add(sum / 4.0); - } - double min = Collections.min(hourlyAverages); - double max = Collections.max(hourlyAverages); - return new PriceRange(min, max); - } } \ No newline at end of file From 0782cd2fca9b067b0525d39ffab1f9d1d356a37d Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Thu, 25 Sep 2025 12:18:55 +0200 Subject: [PATCH 4/7] Day2. Done, aside from support for 15-minute prices. --- src/main/java/com/example/Main.java | 104 +++++++++++++++++++--------- 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 70b1b46f..468dab74 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -2,24 +2,29 @@ import com.example.api.ElpriserAPI; import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.Comparator; import java.util.List; public class Main { public static void main(String[] args) { - ElpriserAPI elpriserAPI = new ElpriserAPI(); - - if(args[0].equals("--zone")) - determineUsage(args, elpriserAPI); - else - printHelp(); + if(args.length != 0){ + ElpriserAPI elpriserAPI = new ElpriserAPI(); + if(args[0].equals("--zone")) + determineUsage(args, elpriserAPI); + else + printHelp(); + } + else{ + printHelp(); + } } private static void printHelp() { System.out.println(""" - Expected Command-Line Arguments: + Usage: --zone SE1|SE2|SE3|SE4 (required) --date YYYY-MM-DD (optional, defaults to current date) --sorted (optional, to display prices in descending order) @@ -35,20 +40,31 @@ private static void determineUsage(String[] args, ElpriserAPI priceList) { case "SE4" -> zone = ElpriserAPI.Prisklass.SE4; default -> { printHelp(); + System.out.println("Invalid zone input"); return; } } if(args.length < 3){ - printPricesForList(priceList.getPriser(LocalDate.now(), zone)); + printPricesForList(getMergedList(priceList, zone, LocalDate.now())); } else if(args[2].equals("--charging")){ - printChargePrice(priceList.getPriser(LocalDate.now(), zone), args[3]); + printChargePrice(getMergedList(priceList, zone, LocalDate.now()), args[3]); } else if(args[2].equals("--sorted")){ - printSortedPricesForList(priceList.getPriser(LocalDate.now(), zone)); + printSortedPricesForList(getMergedList(priceList, zone, LocalDate.now())); } else if(args[2].equals("--date")){ + LocalDate parsedDate; + try{ + parsedDate = LocalDate.parse(args[3]); + } catch (DateTimeParseException | IndexOutOfBoundsException e) { + printHelp(); + System.out.println("Invalid date"); + return; + } if(args.length < 5){ - printPricesForList(priceList.getPriser(args[3], zone)); + printPricesForList(getMergedList(priceList, zone, parsedDate)); } else if(args[4].equals("--sorted")){ - printSortedPricesForList(priceList.getPriser(args[3], zone)); + printSortedPricesForList(getMergedList(priceList, zone, parsedDate)); + } else if(args[4].equals("--charging")){ + printChargePrice(getMergedList(priceList, zone, parsedDate), args[5]); } else{ printHelp(); } @@ -57,10 +73,27 @@ private static void determineUsage(String[] args, ElpriserAPI priceList) { } } + private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate date) { + List mergedList = priceList.getPriser(date, zone); + mergedList.addAll(priceList.getPriser(date.plusDays(1), zone)); + return mergedList; + } + private static void printChargePrice(List prices, String args) { //sliding window algorithm, 2h 4h 8h - int chargeDuration = args.charAt(0) - '0'; - List chargeWindow = prices.subList(0,4); + int chargeDuration = switch(args){ + case "2h" -> 2; + case "4h" -> 4; + case "8h" -> 8; + default -> -1; + }; + + if(chargeDuration == -1){ + printHelp(); + return; + } + + List chargeWindow = prices.subList(0,chargeDuration); double lowestSum = 0; for (int i = 0; i < chargeDuration; i++) { @@ -70,14 +103,14 @@ private static void printChargePrice(List prices, String arg double windowSum = lowestSum; for (int i = chargeDuration; i < prices.size(); i++) { windowSum += prices.get(i).sekPerKWh() - prices.get(i - chargeDuration).sekPerKWh(); - if(Math.min(lowestSum, windowSum) == windowSum){ + if(windowSum < lowestSum){ chargeWindow = prices.subList(i+1 - chargeWindow.size(), i+1); + lowestSum = windowSum; } - lowestSum = Math.min(lowestSum, windowSum); } - System.out.printf("Medelpris: %.1f öre/KWh\n", lowestSum/chargeDuration*100); - System.out.println("Ladda mellan " + formattedStartTime(chargeWindow.getFirst()) + " och " + formattedEndTime(chargeWindow.getLast())); + System.out.printf("Medelpris för fönster: %.2f öre\n", lowestSum/chargeDuration*100); + System.out.printf("Påbörja laddning kl %02d:00\n", chargeWindow.getFirst().timeStart().getHour()); } private static void printSortedPricesForList(List prices) { @@ -90,23 +123,28 @@ private static void printSortedPricesForList(List prices) { } private static void printPricesForList(List pricelist) { - for (ElpriserAPI.Elpris price : pricelist) { - //System.out.printf(formattedStartTime(price) + "-" + formattedEndTime(price) + ": %.1f öre\n", price.sekPerKWh()*100); - System.out.printf("Mellan " + formattedStartTime(price) + " och " + formattedEndTime(price) + ": %.1f öre/KWh\n", price.sekPerKWh()*100); + if(pricelist.isEmpty()){ + System.out.println("Found no data"); + } else { + double lowestPrice = Double.MAX_VALUE, highestPrice = 0, meanPrice = 0; + System.out.println("Prislista:"); + for (ElpriserAPI.Elpris price : pricelist) { + lowestPrice = Math.min(lowestPrice, price.sekPerKWh()); + highestPrice = Math.max(highestPrice, price.sekPerKWh()); + meanPrice += price.sekPerKWh(); + System.out.printf(formattedTime(price) + " %.2f öre\n", price.sekPerKWh() * 100); + //System.out.printf("Mellan " + formattedStartTime(price) + " och " + formattedEndTime(price) + ": %.1f öre/KWh\n", price.sekPerKWh()*100); + } + System.out.printf("Lägsta pris: %.02f öre\n", lowestPrice*100); + System.out.printf("Högsta pris: %.02f öre\n", highestPrice*100); + System.out.printf("Medelpris: %.02f öre\n", meanPrice/pricelist.size()*100); } } - private static String formattedStartTime(ElpriserAPI.Elpris source){ - String startTime; - //startTime = String.format("%02d", source.timeStart().getHour()); - startTime = String.format("%02d", source.timeStart().getHour()) + ":" + String.format("%02d", source.timeStart().getMinute()); - return startTime; - } - - private static String formattedEndTime(ElpriserAPI.Elpris source){ - String endTime; - //endTime = String.format("%02d", source.timeEnd().getHour()); - endTime = String.format("%02d", source.timeEnd().getHour()) + ":" + String.format("%02d", source.timeEnd().getMinute()); - return endTime; + private static String formattedTime(ElpriserAPI.Elpris source){ + String formattedTime; + formattedTime = String.format("%02d-%02d", source.timeStart().getHour(), source.timeEnd().getHour()); + //startTime = String.format("%02d", source.timeStart().getHour()) + ":" + String.format("%02d", source.timeStart().getMinute()); + return formattedTime; } } From cd85b823ff957cdc33489d5957ad025734b2ec27 Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:18:48 +0200 Subject: [PATCH 5/7] Day2-2. Done, passed all tests locally. --- src/main/java/com/example/Main.java | 71 +++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 468dab74..023416ab 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -2,13 +2,18 @@ import com.example.api.ElpriserAPI; import java.time.LocalDate; +import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Locale; public class Main { public static void main(String[] args) { + Locale.setDefault(Locale.of("sv","SE")); + if(args.length != 0){ ElpriserAPI elpriserAPI = new ElpriserAPI(); if(args[0].equals("--zone")) @@ -44,6 +49,7 @@ private static void determineUsage(String[] args, ElpriserAPI priceList) { return; } } + if(args.length < 3){ printPricesForList(getMergedList(priceList, zone, LocalDate.now())); } else if(args[2].equals("--charging")){ @@ -73,13 +79,13 @@ private static void determineUsage(String[] args, ElpriserAPI priceList) { } } - private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate date) { + private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate date) { List mergedList = priceList.getPriser(date, zone); mergedList.addAll(priceList.getPriser(date.plusDays(1), zone)); - return mergedList; + return convertQuartersToHours(mergedList); } - private static void printChargePrice(List prices, String args) { + private static void printChargePrice(List prices, String args) { //sliding window algorithm, 2h 4h 8h int chargeDuration = switch(args){ case "2h" -> 2; @@ -93,16 +99,16 @@ private static void printChargePrice(List prices, String arg return; } - List chargeWindow = prices.subList(0,chargeDuration); + List chargeWindow = prices.subList(0,chargeDuration); double lowestSum = 0; for (int i = 0; i < chargeDuration; i++) { - lowestSum += prices.get(i).sekPerKWh(); + lowestSum += prices.get(i).price(); } double windowSum = lowestSum; for (int i = chargeDuration; i < prices.size(); i++) { - windowSum += prices.get(i).sekPerKWh() - prices.get(i - chargeDuration).sekPerKWh(); + windowSum += prices.get(i).price() - prices.get(i - chargeDuration).price(); if(windowSum < lowestSum){ chargeWindow = prices.subList(i+1 - chargeWindow.size(), i+1); lowestSum = windowSum; @@ -110,29 +116,29 @@ private static void printChargePrice(List prices, String arg } System.out.printf("Medelpris för fönster: %.2f öre\n", lowestSum/chargeDuration*100); - System.out.printf("Påbörja laddning kl %02d:00\n", chargeWindow.getFirst().timeStart().getHour()); + System.out.printf("Påbörja laddning kl %02d:00\n", chargeWindow.getFirst().startDate.getHour()); } - private static void printSortedPricesForList(List prices) { - List sortedList = prices.stream() - .sorted(Comparator.comparing(ElpriserAPI.Elpris::sekPerKWh).reversed() - .thenComparing(ElpriserAPI.Elpris::timeStart)) + private static void printSortedPricesForList(List sortedList) { + sortedList = sortedList.stream() + .sorted(Comparator.comparing(hourOfQuarters::price).reversed() + .thenComparing(hourOfQuarters::startDate)) .toList(); printPricesForList(sortedList); } - private static void printPricesForList(List pricelist) { + private static void printPricesForList(List pricelist) { if(pricelist.isEmpty()){ System.out.println("Found no data"); } else { double lowestPrice = Double.MAX_VALUE, highestPrice = 0, meanPrice = 0; System.out.println("Prislista:"); - for (ElpriserAPI.Elpris price : pricelist) { - lowestPrice = Math.min(lowestPrice, price.sekPerKWh()); - highestPrice = Math.max(highestPrice, price.sekPerKWh()); - meanPrice += price.sekPerKWh(); - System.out.printf(formattedTime(price) + " %.2f öre\n", price.sekPerKWh() * 100); + for (hourOfQuarters price : pricelist) { + lowestPrice = Math.min(lowestPrice, price.price()); + highestPrice = Math.max(highestPrice, price.price()); + meanPrice += price.price(); + System.out.printf(formattedTime(price) + " %.2f öre\n", price.price() * 100); //System.out.printf("Mellan " + formattedStartTime(price) + " och " + formattedEndTime(price) + ": %.1f öre/KWh\n", price.sekPerKWh()*100); } System.out.printf("Lägsta pris: %.02f öre\n", lowestPrice*100); @@ -141,10 +147,37 @@ private static void printPricesForList(List pricelist) { } } - private static String formattedTime(ElpriserAPI.Elpris source){ + private static String formattedTime(hourOfQuarters source){ String formattedTime; - formattedTime = String.format("%02d-%02d", source.timeStart().getHour(), source.timeEnd().getHour()); + formattedTime = String.format("%02d-%02d", source.startDate.getHour(), source.endDate.getHour()); //startTime = String.format("%02d", source.timeStart().getHour()) + ":" + String.format("%02d", source.timeStart().getMinute()); return formattedTime; } + + private static List convertQuartersToHours(List prices) { + List hourList = new ArrayList<>(); + if (prices.isEmpty()){ + return hourList; + } + if(prices.getFirst().timeEnd().getMinute() != 0 || prices.get(1).timeEnd().getMinute() != 0){ + int index = -1; + for (ElpriserAPI.Elpris entry : prices) { + if (entry.timeStart().getMinute() == 0) { + hourList.add(new hourOfQuarters(entry.timeStart(), entry.timeEnd(), entry.sekPerKWh()/4)); + index++; + } else { + hourList.add(new hourOfQuarters(hourList.get(index).startDate, entry.timeEnd(), entry.sekPerKWh()/4 + hourList.get(index).price)); + hourList.remove(index); + } + } + } else { + for(ElpriserAPI.Elpris entry : prices){ + hourList.add(new hourOfQuarters(entry.timeStart(), entry.timeEnd(), entry.sekPerKWh())); + } + } + return hourList; + } + + record hourOfQuarters(ZonedDateTime startDate, ZonedDateTime endDate, double price){} + //record hourOfQuarters(int startHour, int endHour, double price){} } From ca22f2a2f4562d868381dfe901cacba08112dade Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Sun, 5 Oct 2025 14:38:03 +0200 Subject: [PATCH 6/7] Day 3. Alternative (cleaner?) code. Passes all tests locally. --- src/main/java/com/example/Main.java | 191 ++++++++++++++++------------ 1 file changed, 110 insertions(+), 81 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 023416ab..346acce0 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -37,57 +37,68 @@ private static void printHelp() { } private static void determineUsage(String[] args, ElpriserAPI priceList) { - ElpriserAPI.Prisklass zone; - switch (args[1]){ - case "SE1" -> zone = ElpriserAPI.Prisklass.SE1; - case "SE2" -> zone = ElpriserAPI.Prisklass.SE2; - case "SE3" -> zone = ElpriserAPI.Prisklass.SE3; - case "SE4" -> zone = ElpriserAPI.Prisklass.SE4; - default -> { - printHelp(); - System.out.println("Invalid zone input"); - return; + if (args.length == 2) { + ElpriserAPI.Prisklass zone = getZone(args); + if (zone == null) return; + printPrices(getMergedList(priceList, zone, LocalDate.now())); + } else { + switch (args.length < 5 ? args[2] : args[4]) { + case "--charging" -> printChargePrice(args, priceList); + case "--sorted" -> printSortedPrices(args, priceList); + case "--date" -> printPricesForDate(args, priceList); + default -> printHelp(); } } + } - if(args.length < 3){ - printPricesForList(getMergedList(priceList, zone, LocalDate.now())); - } else if(args[2].equals("--charging")){ - printChargePrice(getMergedList(priceList, zone, LocalDate.now()), args[3]); - } else if(args[2].equals("--sorted")){ - printSortedPricesForList(getMergedList(priceList, zone, LocalDate.now())); - } else if(args[2].equals("--date")){ - LocalDate parsedDate; - try{ - parsedDate = LocalDate.parse(args[3]); - } catch (DateTimeParseException | IndexOutOfBoundsException e) { - printHelp(); - System.out.println("Invalid date"); - return; - } - if(args.length < 5){ - printPricesForList(getMergedList(priceList, zone, parsedDate)); - } else if(args[4].equals("--sorted")){ - printSortedPricesForList(getMergedList(priceList, zone, parsedDate)); - } else if(args[4].equals("--charging")){ - printChargePrice(getMergedList(priceList, zone, parsedDate), args[5]); - } else{ - printHelp(); - } + private static void printPricesForDate(String[] args, ElpriserAPI priceList) { + LocalDate parsedDate = getParsedDate(args); + ElpriserAPI.Prisklass zone = getZone(args); + if (parsedDate == null || zone == null) return; + + printPrices(getMergedList(priceList, zone, parsedDate)); + } + + private static void printSortedPrices(String[] args, ElpriserAPI priceList) { + LocalDate parsedDate = getParsedDate(args); + ElpriserAPI.Prisklass zone = getZone(args); + if (parsedDate == null || zone == null) return; + + List sortedList = getMergedList(priceList, zone, parsedDate); + sortedList = sortedList.stream() + .sorted(Comparator.comparing(hourOfQuarters::price).reversed() + .thenComparing(hourOfQuarters::startDate)) + .toList(); + + printPrices(sortedList); + } + + private static void printPrices(List priceList) { + if(priceList.isEmpty()){ + System.out.println("Found no data"); } else { - printHelp(); + double lowestPrice = Double.MAX_VALUE, highestPrice = 0, meanPrice = 0; + System.out.println("Prislista:"); + for (hourOfQuarters price : priceList) { + lowestPrice = Math.min(lowestPrice, price.price()); + highestPrice = Math.max(highestPrice, price.price()); + meanPrice += price.price(); + System.out.printf(formattedTime(price) + " %.2f öre\n", price.price() * 100); + } + System.out.printf("Lägsta pris: %.02f öre\n", lowestPrice*100); + System.out.printf("Högsta pris: %.02f öre\n", highestPrice*100); + System.out.printf("Medelpris: %.02f öre\n", meanPrice/priceList.size()*100); } } - private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate date) { - List mergedList = priceList.getPriser(date, zone); - mergedList.addAll(priceList.getPriser(date.plusDays(1), zone)); - return convertQuartersToHours(mergedList); - } + private static void printChargePrice(String[] args, ElpriserAPI priceList) { + ElpriserAPI.Prisklass zone = getZone(args); + if(zone == null){ + return; + } - private static void printChargePrice(List prices, String args) { //sliding window algorithm, 2h 4h 8h - int chargeDuration = switch(args){ + int chargeDuration = switch(args.length < 5 ? args[3] : args[5]){ case "2h" -> 2; case "4h" -> 4; case "8h" -> 8; @@ -99,7 +110,12 @@ private static void printChargePrice(List prices, String args) { return; } - List chargeWindow = prices.subList(0,chargeDuration); + LocalDate parsedDate = getParsedDate(args); + if (parsedDate == null) return; + + List prices = getMergedList(priceList, zone, parsedDate); + List chargeWindow; + int indexWindow = chargeDuration; double lowestSum = 0; for (int i = 0; i < chargeDuration; i++) { @@ -110,50 +126,17 @@ private static void printChargePrice(List prices, String args) { for (int i = chargeDuration; i < prices.size(); i++) { windowSum += prices.get(i).price() - prices.get(i - chargeDuration).price(); if(windowSum < lowestSum){ - chargeWindow = prices.subList(i+1 - chargeWindow.size(), i+1); + indexWindow = i+1; lowestSum = windowSum; } } + chargeWindow = prices.subList(indexWindow - chargeDuration, indexWindow); + System.out.printf("Medelpris för fönster: %.2f öre\n", lowestSum/chargeDuration*100); System.out.printf("Påbörja laddning kl %02d:00\n", chargeWindow.getFirst().startDate.getHour()); } - private static void printSortedPricesForList(List sortedList) { - sortedList = sortedList.stream() - .sorted(Comparator.comparing(hourOfQuarters::price).reversed() - .thenComparing(hourOfQuarters::startDate)) - .toList(); - - printPricesForList(sortedList); - } - - private static void printPricesForList(List pricelist) { - if(pricelist.isEmpty()){ - System.out.println("Found no data"); - } else { - double lowestPrice = Double.MAX_VALUE, highestPrice = 0, meanPrice = 0; - System.out.println("Prislista:"); - for (hourOfQuarters price : pricelist) { - lowestPrice = Math.min(lowestPrice, price.price()); - highestPrice = Math.max(highestPrice, price.price()); - meanPrice += price.price(); - System.out.printf(formattedTime(price) + " %.2f öre\n", price.price() * 100); - //System.out.printf("Mellan " + formattedStartTime(price) + " och " + formattedEndTime(price) + ": %.1f öre/KWh\n", price.sekPerKWh()*100); - } - System.out.printf("Lägsta pris: %.02f öre\n", lowestPrice*100); - System.out.printf("Högsta pris: %.02f öre\n", highestPrice*100); - System.out.printf("Medelpris: %.02f öre\n", meanPrice/pricelist.size()*100); - } - } - - private static String formattedTime(hourOfQuarters source){ - String formattedTime; - formattedTime = String.format("%02d-%02d", source.startDate.getHour(), source.endDate.getHour()); - //startTime = String.format("%02d", source.timeStart().getHour()) + ":" + String.format("%02d", source.timeStart().getMinute()); - return formattedTime; - } - private static List convertQuartersToHours(List prices) { List hourList = new ArrayList<>(); if (prices.isEmpty()){ @@ -178,6 +161,52 @@ private static List convertQuartersToHours(List zone = ElpriserAPI.Prisklass.SE1; + case "SE2" -> zone = ElpriserAPI.Prisklass.SE2; + case "SE3" -> zone = ElpriserAPI.Prisklass.SE3; + case "SE4" -> zone = ElpriserAPI.Prisklass.SE4; + default -> { + printHelp(); + System.out.println("Invalid zone input"); + } + } + } catch (IndexOutOfBoundsException e) { + printHelp(); + } + return zone; + } + + private static LocalDate getParsedDate(String[] args) { + LocalDate parsedDate; + if(args.length < 4){ + parsedDate = LocalDate.now(); + }else{ + try { + parsedDate = LocalDate.parse(args[3]); + } catch (DateTimeParseException | IndexOutOfBoundsException e) { + printHelp(); + System.out.println("Invalid date"); + return null; + } + } + return parsedDate; + } + + private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate date) { + List mergedList = priceList.getPriser(date, zone); + mergedList.addAll(priceList.getPriser(date.plusDays(1), zone)); + return convertQuartersToHours(mergedList); + } + + private static String formattedTime(hourOfQuarters source){ + String formattedTime; + formattedTime = String.format("%02d-%02d", source.startDate.getHour(), source.endDate.getHour()); + return formattedTime; + } + record hourOfQuarters(ZonedDateTime startDate, ZonedDateTime endDate, double price){} - //record hourOfQuarters(int startHour, int endHour, double price){} -} +} \ No newline at end of file From 2cbbafde9fb808375a81d93897c6be2e34b85a3e Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Sun, 5 Oct 2025 15:52:58 +0200 Subject: [PATCH 7/7] Day3-2. Update to handle commands in random order. Passes all tests locally. --- src/main/java/com/example/Main.java | 121 +++++++++++++--------------- 1 file changed, 58 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 346acce0..ff5cce4e 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -16,12 +16,8 @@ public static void main(String[] args) { if(args.length != 0){ ElpriserAPI elpriserAPI = new ElpriserAPI(); - if(args[0].equals("--zone")) - determineUsage(args, elpriserAPI); - else - printHelp(); - } - else{ + determineUsage(args, elpriserAPI); + }else{ printHelp(); } } @@ -37,31 +33,34 @@ private static void printHelp() { } private static void determineUsage(String[] args, ElpriserAPI priceList) { - if (args.length == 2) { - ElpriserAPI.Prisklass zone = getZone(args); - if (zone == null) return; - printPrices(getMergedList(priceList, zone, LocalDate.now())); - } else { - switch (args.length < 5 ? args[2] : args[4]) { - case "--charging" -> printChargePrice(args, priceList); - case "--sorted" -> printSortedPrices(args, priceList); - case "--date" -> printPricesForDate(args, priceList); - default -> printHelp(); + ElpriserAPI.Prisklass zone = null; + LocalDate parsedDate = LocalDate.now(); + int chargeDuration = -1; + boolean sorted = false; + + for (int i = 0; i < args.length; i++) { + switch(args[i]){ + case "--zone" -> zone = getZone(args, i); + case "--date" -> parsedDate = getParsedDate(args, i); + case "--charging" -> chargeDuration = getChargeDuration(args, i); + case "--sorted" -> sorted = true; + case "--help" -> { printHelp(); return; } } } - } - - private static void printPricesForDate(String[] args, ElpriserAPI priceList) { - LocalDate parsedDate = getParsedDate(args); - ElpriserAPI.Prisklass zone = getZone(args); - if (parsedDate == null || zone == null) return; - printPrices(getMergedList(priceList, zone, parsedDate)); + if(zone == null){ + printHelp(); + System.out.println("Invalid zone input"); + } + else if(chargeDuration != -1) + printChargePrice(priceList, zone, parsedDate, chargeDuration); + else if(sorted) + printSortedPrices(priceList, zone, parsedDate); + else + printPrices(getMergedList(priceList, zone, parsedDate)); } - private static void printSortedPrices(String[] args, ElpriserAPI priceList) { - LocalDate parsedDate = getParsedDate(args); - ElpriserAPI.Prisklass zone = getZone(args); + private static void printSortedPrices(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate parsedDate) { if (parsedDate == null || zone == null) return; List sortedList = getMergedList(priceList, zone, parsedDate); @@ -74,6 +73,7 @@ private static void printSortedPrices(String[] args, ElpriserAPI priceList) { } private static void printPrices(List priceList) { + if(priceList == null) return; if(priceList.isEmpty()){ System.out.println("Found no data"); } else { @@ -91,28 +91,14 @@ private static void printPrices(List priceList) { } } - private static void printChargePrice(String[] args, ElpriserAPI priceList) { - ElpriserAPI.Prisklass zone = getZone(args); - if(zone == null){ - return; - } - - //sliding window algorithm, 2h 4h 8h - int chargeDuration = switch(args.length < 5 ? args[3] : args[5]){ - case "2h" -> 2; - case "4h" -> 4; - case "8h" -> 8; - default -> -1; - }; + private static void printChargePrice(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate parsedDate, int chargeDuration) { + if (parsedDate == null || zone == null) return; if(chargeDuration == -1){ printHelp(); return; } - LocalDate parsedDate = getParsedDate(args); - if (parsedDate == null) return; - List prices = getMergedList(priceList, zone, parsedDate); List chargeWindow; int indexWindow = chargeDuration; @@ -161,44 +147,53 @@ private static List convertQuartersToHours(List zone = ElpriserAPI.Prisklass.SE1; case "SE2" -> zone = ElpriserAPI.Prisklass.SE2; case "SE3" -> zone = ElpriserAPI.Prisklass.SE3; case "SE4" -> zone = ElpriserAPI.Prisklass.SE4; - default -> { - printHelp(); - System.out.println("Invalid zone input"); - } } } catch (IndexOutOfBoundsException e) { - printHelp(); + return null; } return zone; } - private static LocalDate getParsedDate(String[] args) { + private static LocalDate getParsedDate(String[] args, int index) { LocalDate parsedDate; - if(args.length < 4){ - parsedDate = LocalDate.now(); - }else{ - try { - parsedDate = LocalDate.parse(args[3]); - } catch (DateTimeParseException | IndexOutOfBoundsException e) { - printHelp(); - System.out.println("Invalid date"); - return null; - } + try { + parsedDate = LocalDate.parse(args[index+1]); + } catch (DateTimeParseException | IndexOutOfBoundsException e) { + printHelp(); + System.out.println("Invalid date"); + return null; } return parsedDate; } - private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate date) { - List mergedList = priceList.getPriser(date, zone); - mergedList.addAll(priceList.getPriser(date.plusDays(1), zone)); + private static int getChargeDuration(String[] args, int index) { + int chargeDuration; + try { + chargeDuration = switch(args[index+1]){ + case "2h" -> 2; + case "4h" -> 4; + case "8h" -> 8; + default -> -1; + }; + } catch (IndexOutOfBoundsException e) { + chargeDuration = -1; + } + return chargeDuration; + } + + private static List getMergedList(ElpriserAPI priceList, ElpriserAPI.Prisklass zone, LocalDate parsedDate) { + if (parsedDate == null || zone == null) return null; + + List mergedList = priceList.getPriser(parsedDate, zone); + mergedList.addAll(priceList.getPriser(parsedDate.plusDays(1), zone)); return convertQuartersToHours(mergedList); }