From 8a948b4505ac6cfbfa82bbea4cb6f8262fdefe86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Thu, 16 May 2019 22:15:27 +0200 Subject: [PATCH 01/16] AOC-024: Basic setup. --- .../advent2018/days/day07/Day07.java | 72 +++++++++++++ .../advent2018/days/day07/Input.txt | 101 ++++++++++++++++++ .../advent2018/days/day07/package-info.java | 6 ++ .../advent2018/days/day07/Day07Test.java | 59 ++++++++++ 4 files changed, 238 insertions(+) create mode 100644 src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java create mode 100644 src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt create mode 100644 src/main/java/org/basseur/adventofcode/advent2018/days/day07/package-info.java create mode 100644 src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java new file mode 100644 index 0000000..51e85ae --- /dev/null +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -0,0 +1,72 @@ +package org.basseur.adventofcode.advent2018.days.day07; + +import org.basseur.adventofcode.advent2018.ProblemStatusEnum; +import org.basseur.adventofcode.advent2018.days.Days; +import org.basseur.adventofcode.advent2018.utils.FileReaders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; + +/** + * Implementation for Day 7: The Sum of Its Parts. + * + * @author Jan Philipp Gölz + */ +@Component +public class Day07 implements Days { + + /** The location of the puzzle input file */ + private static final String FILE_LOCATION = "src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt"; + /** The puzzle status {@code HashMap} */ + private final HashMap problemStatus; + + /** A list containing the instructions */ + private final List instructions; + + /** + * Constructor for Day07. + * + * @param fileReaders {@code @Autowired} fileReader + */ + @Autowired + Day07(FileReaders fileReaders) { + this.problemStatus = new HashMap<>(); + this.problemStatus.put("1", ProblemStatusEnum.UNSOLVED); + this.problemStatus.put("2", ProblemStatusEnum.UNSOLVED); + + this.instructions = fileReaders.readFileIntoStringList(FILE_LOCATION); + } + + @Override + public int getDay() { + return 7; + } + + @Override + public String firstPart() { + return "Part 1 - Order in which the steps in the instructions should be completed: " + determineOrder(); + } + + @Override + public String secondPart() { + return ""; + } + + @Override + public HashMap getProblemStatus() { + return problemStatus; + } + + /** + * Primary Method for Day 7, Part 1. + *

+ * Determines the order, in which the instructions should be completed. + * + * @return the ordered String of instructions + */ + private String determineOrder() { + return ""; + } +} \ No newline at end of file diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt new file mode 100644 index 0000000..f309b05 --- /dev/null +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt @@ -0,0 +1,101 @@ +Step X must be finished before step C can begin. +Step C must be finished before step G can begin. +Step F must be finished before step G can begin. +Step U must be finished before step Y can begin. +Step O must be finished before step S can begin. +Step D must be finished before step N can begin. +Step M must be finished before step H can begin. +Step J must be finished before step Q can begin. +Step G must be finished before step R can begin. +Step I must be finished before step N can begin. +Step R must be finished before step K can begin. +Step A must be finished before step Z can begin. +Step Y must be finished before step L can begin. +Step H must be finished before step P can begin. +Step K must be finished before step S can begin. +Step Z must be finished before step P can begin. +Step T must be finished before step S can begin. +Step N must be finished before step P can begin. +Step E must be finished before step S can begin. +Step S must be finished before step W can begin. +Step W must be finished before step V can begin. +Step L must be finished before step V can begin. +Step P must be finished before step B can begin. +Step Q must be finished before step V can begin. +Step B must be finished before step V can begin. +Step P must be finished before step Q can begin. +Step S must be finished before step V can begin. +Step C must be finished before step Q can begin. +Step I must be finished before step H can begin. +Step A must be finished before step E can begin. +Step H must be finished before step Q can begin. +Step G must be finished before step V can begin. +Step N must be finished before step L can begin. +Step R must be finished before step Q can begin. +Step W must be finished before step L can begin. +Step X must be finished before step L can begin. +Step X must be finished before step J can begin. +Step W must be finished before step P can begin. +Step U must be finished before step B can begin. +Step P must be finished before step V can begin. +Step O must be finished before step P can begin. +Step W must be finished before step Q can begin. +Step S must be finished before step Q can begin. +Step U must be finished before step Z can begin. +Step Z must be finished before step T can begin. +Step M must be finished before step T can begin. +Step A must be finished before step P can begin. +Step Z must be finished before step B can begin. +Step N must be finished before step S can begin. +Step H must be finished before step N can begin. +Step J must be finished before step E can begin. +Step M must be finished before step J can begin. +Step R must be finished before step A can begin. +Step A must be finished before step Y can begin. +Step F must be finished before step V can begin. +Step L must be finished before step P can begin. +Step K must be finished before step L can begin. +Step F must be finished before step P can begin. +Step G must be finished before step L can begin. +Step I must be finished before step Q can begin. +Step C must be finished before step L can begin. +Step I must be finished before step Y can begin. +Step G must be finished before step B can begin. +Step H must be finished before step L can begin. +Step X must be finished before step U can begin. +Step I must be finished before step K can begin. +Step R must be finished before step N can begin. +Step I must be finished before step L can begin. +Step M must be finished before step I can begin. +Step K must be finished before step V can begin. +Step G must be finished before step E can begin. +Step F must be finished before step B can begin. +Step O must be finished before step Y can begin. +Step Y must be finished before step Q can begin. +Step F must be finished before step K can begin. +Step N must be finished before step W can begin. +Step O must be finished before step R can begin. +Step N must be finished before step E can begin. +Step M must be finished before step V can begin. +Step H must be finished before step T can begin. +Step Y must be finished before step T can begin. +Step F must be finished before step J can begin. +Step F must be finished before step O can begin. +Step W must be finished before step B can begin. +Step T must be finished before step E can begin. +Step T must be finished before step P can begin. +Step F must be finished before step M can begin. +Step U must be finished before step I can begin. +Step H must be finished before step S can begin. +Step S must be finished before step P can begin. +Step T must be finished before step W can begin. +Step A must be finished before step N can begin. +Step O must be finished before step N can begin. +Step L must be finished before step B can begin. +Step U must be finished before step K can begin. +Step Z must be finished before step W can begin. +Step X must be finished before step D can begin. +Step Z must be finished before step L can begin. +Step I must be finished before step T can begin. +Step O must be finished before step W can begin. +Step I must be finished before step B can begin. \ No newline at end of file diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/package-info.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/package-info.java new file mode 100644 index 0000000..93e40f8 --- /dev/null +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/package-info.java @@ -0,0 +1,6 @@ +/** + * Contains Day 7: The Sum of Its Parts. + * + * @author Jan Philipp Gölz + */ +package org.basseur.adventofcode.advent2018.days.day07; \ No newline at end of file diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java new file mode 100644 index 0000000..58b78ab --- /dev/null +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java @@ -0,0 +1,59 @@ +package org.basseur.adventofcode.advent2018.days.day07; + +import org.basseur.adventofcode.advent2018.days.Days; +import org.basseur.adventofcode.advent2018.utils.FileReaders; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(SpringRunner.class) +public class Day07Test { + + @MockBean + private FileReaders fileReaders; + private List instructions = new ArrayList<>(); + private Days day07; + + @Before + public void setUp() { + instructions.add("Step C must be finished before step A can begin."); + instructions.add("Step C must be finished before step F can begin."); + instructions.add("Step A must be finished before step B can begin."); + instructions.add("Step A must be finished before step D can begin."); + instructions.add("Step B must be finished before step E can begin."); + instructions.add("Step D must be finished before step E can begin."); + instructions.add("Step F must be finished before step E can begin."); + + day07 = new Day07(fileReaders); + } + + @Test + public void getDay() { + int expectedResult = 7; + int actualResult = day07.getDay(); + + Assert.assertEquals(expectedResult, actualResult); + } + + @Test + public void firstPart() { + String expectedResult = "Part 1 - Order in which the steps in the instructions should be completed: CABDFE"; + String actualResult = day07.firstPart(); + + Assert.assertEquals(expectedResult, actualResult); + } + + @Test + public void secondPart() { + String expectedResult = "Part 2 - Length of the shortest polymer: 4"; + String actualResult = day07.secondPart(); + + Assert.assertEquals(expectedResult, actualResult); + } +} \ No newline at end of file From 6cb16b218e28d0a80f0b22fb5e8fc2d0b1d7a77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Thu, 16 May 2019 22:15:42 +0200 Subject: [PATCH 02/16] AOC-024: Step class and tests --- .../advent2018/days/day07/Step.java | 41 +++++++++++++++++++ .../advent2018/days/day07/StepTest.java | 34 +++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java create mode 100644 src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java new file mode 100644 index 0000000..b8c87ac --- /dev/null +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -0,0 +1,41 @@ +package org.basseur.adventofcode.advent2018.days.day07; + +import java.util.ArrayList; + +public class Step { + /** Letter of this step */ + private final String id; + /** ArrayList of previous steps */ + private ArrayList previousSteps = new ArrayList<>(); + + public Step(String id) { + this.id = id; + } + + /** + * Returns {@code true} if this step has previous steps + * + * @return {@code true} if this Step has previous steps, {@code false} otherwise + */ + public boolean hasPrevious() { + return previousSteps.size() > 0; + } + + /** + * Adds an id to the {@link Step#previousSteps} ArrayList. + * + * @param prevId id of the previous step to be added + */ + public void addPrevious(String prevId) { + previousSteps.add(prevId); + } + + /** + * Removes an id to the {@link Step#previousSteps} ArrayList. + * + * @param prevId id of the previous step to be removed + */ + public void removePrevious(String prevId) { + previousSteps.remove(prevId); + } +} diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java new file mode 100644 index 0000000..26bc646 --- /dev/null +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java @@ -0,0 +1,34 @@ +package org.basseur.adventofcode.advent2018.days.day07; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringRunner; + + +@RunWith(SpringRunner.class) +public class StepTest { + + private Step step; + + @Before + public void setUp() { + step = new Step("A"); + } + + @Test + public void testAddRemoveAndHasPrevious() { + step.addPrevious("B"); + Assert.assertTrue(step.hasPrevious()); + + step.removePrevious("B"); + Assert.assertFalse(step.hasPrevious()); + } + + @Test + public void testRemoveFromEmptyPreviousSteps() { + step.removePrevious("Z"); + Assert.assertFalse(step.hasPrevious()); + } +} \ No newline at end of file From 43eabf9f8086fe82d4facdd349a465382033d0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Fri, 17 May 2019 00:35:28 +0200 Subject: [PATCH 03/16] AOC-024: Changed String ids to Character. Finished Day 7 Part 1. --- .../advent2018/days/day07/Day07.java | 55 ++++++++++++++++++- .../advent2018/days/day07/Step.java | 15 +++-- .../advent2018/days/day07/Day07Test.java | 2 + .../advent2018/days/day07/StepTest.java | 8 +-- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 51e85ae..3ecdfd1 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -6,8 +6,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Implementation for Day 7: The Sum of Its Parts. @@ -24,6 +28,8 @@ public class Day07 implements Days { /** A list containing the instructions */ private final List instructions; + /** A {@code Map} containing all the {@link Step}s mapped to their IDs */ + private HashMap stepHashMap = new HashMap<>(); /** * Constructor for Day07. @@ -33,7 +39,7 @@ public class Day07 implements Days { @Autowired Day07(FileReaders fileReaders) { this.problemStatus = new HashMap<>(); - this.problemStatus.put("1", ProblemStatusEnum.UNSOLVED); + this.problemStatus.put("1", ProblemStatusEnum.SOLVED); this.problemStatus.put("2", ProblemStatusEnum.UNSOLVED); this.instructions = fileReaders.readFileIntoStringList(FILE_LOCATION); @@ -63,10 +69,55 @@ public HashMap getProblemStatus() { * Primary Method for Day 7, Part 1. *

* Determines the order, in which the instructions should be completed. + * For this purpose {@link Day07#stepHashMap} is copied. The new HashMap is + * scanned for all {@link Step}s that have no previous steps in them. These + * are added to an ArrayList which then gets sorted alphabetically. The first + * item is the current step, which gets added to the output. Subsequently, this + * step gets removed from all {@link Step#previousSteps} and from the HashMap, + * as well as from the available Steps. This process gets repeated until the + * HashMap is empty. * * @return the ordered String of instructions */ private String determineOrder() { - return ""; + parseSteps(); + ArrayList availableSteps = new ArrayList<>(); + HashMap steps = stepHashMap; + String order = ""; + + while (!steps.isEmpty()) { + + steps.forEach((id, step) -> { + if (!step.hasPrevious()) { + availableSteps.add(id); + } + }); + + Collections.sort(availableSteps); + Character currentStep = availableSteps.get(0); + order = order + currentStep; + + steps.forEach((id, step) -> step.removePrevious(currentStep)); + steps.remove(currentStep); + availableSteps.removeAll(Collections.singleton(currentStep)); + } + + return order; + } + + /** + * Parses the {@link Day07#instructions} to create {@link Step}s and add previous IDs. + */ + private void parseSteps() { + for (String instruction : instructions) { + Matcher matcher = Pattern.compile("Step (\\w) must be finished before step (\\w) can begin\\.").matcher(instruction); + if (matcher.find()) { + char firstId = matcher.group(1).charAt(0); + char secondId = matcher.group(2).charAt(0); + stepHashMap.putIfAbsent(firstId, new Step(firstId)); + stepHashMap.putIfAbsent(secondId, new Step(secondId)); + stepHashMap.get(secondId).addPrevious(firstId); + } + } } } \ No newline at end of file diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java index b8c87ac..a65afe4 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -4,11 +4,16 @@ public class Step { /** Letter of this step */ - private final String id; + public final char id; /** ArrayList of previous steps */ - private ArrayList previousSteps = new ArrayList<>(); + private ArrayList previousSteps = new ArrayList<>(); - public Step(String id) { + /** + * Constructs Step with + * + * @param id + */ + public Step(Character id) { this.id = id; } @@ -26,7 +31,7 @@ public boolean hasPrevious() { * * @param prevId id of the previous step to be added */ - public void addPrevious(String prevId) { + public void addPrevious(Character prevId) { previousSteps.add(prevId); } @@ -35,7 +40,7 @@ public void addPrevious(String prevId) { * * @param prevId id of the previous step to be removed */ - public void removePrevious(String prevId) { + public void removePrevious(Character prevId) { previousSteps.remove(prevId); } } diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java index 58b78ab..df2db9a 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java @@ -6,6 +6,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; @@ -30,6 +31,7 @@ public void setUp() { instructions.add("Step D must be finished before step E can begin."); instructions.add("Step F must be finished before step E can begin."); + Mockito.when(fileReaders.readFileIntoStringList(Mockito.anyString())).thenReturn(instructions); day07 = new Day07(fileReaders); } diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java index 26bc646..5b470c5 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java @@ -14,21 +14,21 @@ public class StepTest { @Before public void setUp() { - step = new Step("A"); + step = new Step('A'); } @Test public void testAddRemoveAndHasPrevious() { - step.addPrevious("B"); + step.addPrevious('B'); Assert.assertTrue(step.hasPrevious()); - step.removePrevious("B"); + step.removePrevious('B'); Assert.assertFalse(step.hasPrevious()); } @Test public void testRemoveFromEmptyPreviousSteps() { - step.removePrevious("Z"); + step.removePrevious('Z'); Assert.assertFalse(step.hasPrevious()); } } \ No newline at end of file From c773d8084294025253896ed19955de8e50f39653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Fri, 17 May 2019 21:45:23 +0200 Subject: [PATCH 04/16] AOC-024: Refactored, so that result for Day 7 Part 1 can be requested multiple times with same result --- .../advent2018/days/day07/Day07.java | 37 +++++++++++++------ .../advent2018/days/day07/Step.java | 24 +++++++++++- .../advent2018/days/day07/Day07Test.java | 4 +- .../advent2018/days/day07/StepTest.java | 11 ++++++ 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 3ecdfd1..090d225 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -6,10 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,7 +26,7 @@ public class Day07 implements Days { /** A list containing the instructions */ private final List instructions; /** A {@code Map} containing all the {@link Step}s mapped to their IDs */ - private HashMap stepHashMap = new HashMap<>(); + private Map stepHashMap = new HashMap<>(); /** * Constructor for Day07. @@ -43,6 +40,8 @@ public class Day07 implements Days { this.problemStatus.put("2", ProblemStatusEnum.UNSOLVED); this.instructions = fileReaders.readFileIntoStringList(FILE_LOCATION); + + parseSteps(); } @Override @@ -80,13 +79,11 @@ public HashMap getProblemStatus() { * @return the ordered String of instructions */ private String determineOrder() { - parseSteps(); - ArrayList availableSteps = new ArrayList<>(); - HashMap steps = stepHashMap; - String order = ""; + List availableSteps = new ArrayList<>(); + Map steps = getCopyOfStepHashMap(); + StringBuilder order = new StringBuilder(); while (!steps.isEmpty()) { - steps.forEach((id, step) -> { if (!step.hasPrevious()) { availableSteps.add(id); @@ -95,14 +92,15 @@ private String determineOrder() { Collections.sort(availableSteps); Character currentStep = availableSteps.get(0); - order = order + currentStep; + order.append(currentStep); steps.forEach((id, step) -> step.removePrevious(currentStep)); steps.remove(currentStep); availableSteps.removeAll(Collections.singleton(currentStep)); } - return order; + System.out.println(order); + return order.toString(); } /** @@ -111,13 +109,28 @@ private String determineOrder() { private void parseSteps() { for (String instruction : instructions) { Matcher matcher = Pattern.compile("Step (\\w) must be finished before step (\\w) can begin\\.").matcher(instruction); + if (matcher.find()) { char firstId = matcher.group(1).charAt(0); char secondId = matcher.group(2).charAt(0); + stepHashMap.putIfAbsent(firstId, new Step(firstId)); stepHashMap.putIfAbsent(secondId, new Step(secondId)); stepHashMap.get(secondId).addPrevious(firstId); } } } + + /** + * Creates and returns a deep copy of the {@link Day07#stepHashMap} + * + * @return a copy of the {@link Day07#stepHashMap} + */ + private HashMap getCopyOfStepHashMap() { + HashMap copyOfStepHashMap = new HashMap<>(); + + stepHashMap.forEach((id, step) -> copyOfStepHashMap.put(id, new Step(step))); + + return copyOfStepHashMap; + } } \ No newline at end of file diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java index a65afe4..16e8bf4 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -9,14 +9,34 @@ public class Step { private ArrayList previousSteps = new ArrayList<>(); /** - * Constructs Step with + * Constructs Step with id. * - * @param id + * @param id the id of this Step */ public Step(Character id) { this.id = id; } + /** + * Constructs Step with id and previousSteps. + * + * @param id the id for this Step + * @param previousSteps the previous Steps for this Step + */ + public Step(Character id, ArrayList previousSteps) { + this.id = id; + this.previousSteps.addAll(previousSteps); + } + + /** + * Constructs Step as copy of another Step + * + * @param other the other Step to be copied + */ + public Step(Step other) { + this(other.id, other.previousSteps); + } + /** * Returns {@code true} if this step has previous steps * diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java index df2db9a..341fda6 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java @@ -47,13 +47,15 @@ public void getDay() { public void firstPart() { String expectedResult = "Part 1 - Order in which the steps in the instructions should be completed: CABDFE"; String actualResult = day07.firstPart(); + String actualResult2 = day07.firstPart(); Assert.assertEquals(expectedResult, actualResult); + Assert.assertEquals(expectedResult, actualResult2); } @Test public void secondPart() { - String expectedResult = "Part 2 - Length of the shortest polymer: 4"; + String expectedResult = "Part 2 - Time required to complete all of the steps: 15 seconds"; String actualResult = day07.secondPart(); Assert.assertEquals(expectedResult, actualResult); diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java index 5b470c5..0511d9f 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java @@ -31,4 +31,15 @@ public void testRemoveFromEmptyPreviousSteps() { step.removePrevious('Z'); Assert.assertFalse(step.hasPrevious()); } + + @Test + public void testCopiedStepIsNotJustReference() { + Step copiedStep = new Step(step); + + step.addPrevious('B'); + + Assert.assertTrue(step.hasPrevious()); + Assert.assertFalse(copiedStep.hasPrevious()); + + } } \ No newline at end of file From 98e1de8b3e67a14acb42db1b1f73b30e89c11085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Fri, 17 May 2019 21:45:23 +0200 Subject: [PATCH 05/16] AOC-024: Refactored, so that result for Day 7 Part 1 can be requested multiple times with same result --- .../advent2018/days/day07/Day07.java | 38 ++++++++++++------- .../advent2018/days/day07/Step.java | 24 +++++++++++- .../advent2018/days/day07/Day07Test.java | 4 +- .../advent2018/days/day07/StepTest.java | 11 ++++++ 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 3ecdfd1..7f4e76f 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -6,10 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,7 +26,7 @@ public class Day07 implements Days { /** A list containing the instructions */ private final List instructions; /** A {@code Map} containing all the {@link Step}s mapped to their IDs */ - private HashMap stepHashMap = new HashMap<>(); + private Map stepHashMap = new HashMap<>(); /** * Constructor for Day07. @@ -43,6 +40,8 @@ public class Day07 implements Days { this.problemStatus.put("2", ProblemStatusEnum.UNSOLVED); this.instructions = fileReaders.readFileIntoStringList(FILE_LOCATION); + + parseSteps(); } @Override @@ -66,7 +65,7 @@ public HashMap getProblemStatus() { } /** - * Primary Method for Day 7, Part 1. + * Primary Method for Day 7, Part 1 and helper for Part 2. *

* Determines the order, in which the instructions should be completed. * For this purpose {@link Day07#stepHashMap} is copied. The new HashMap is @@ -80,13 +79,11 @@ public HashMap getProblemStatus() { * @return the ordered String of instructions */ private String determineOrder() { - parseSteps(); - ArrayList availableSteps = new ArrayList<>(); - HashMap steps = stepHashMap; - String order = ""; + List availableSteps = new ArrayList<>(); + Map steps = getCopyOfStepHashMap(); + StringBuilder order = new StringBuilder(); while (!steps.isEmpty()) { - steps.forEach((id, step) -> { if (!step.hasPrevious()) { availableSteps.add(id); @@ -95,14 +92,14 @@ private String determineOrder() { Collections.sort(availableSteps); Character currentStep = availableSteps.get(0); - order = order + currentStep; + order.append(currentStep); steps.forEach((id, step) -> step.removePrevious(currentStep)); steps.remove(currentStep); availableSteps.removeAll(Collections.singleton(currentStep)); } - return order; + return order.toString(); } /** @@ -111,13 +108,28 @@ private String determineOrder() { private void parseSteps() { for (String instruction : instructions) { Matcher matcher = Pattern.compile("Step (\\w) must be finished before step (\\w) can begin\\.").matcher(instruction); + if (matcher.find()) { char firstId = matcher.group(1).charAt(0); char secondId = matcher.group(2).charAt(0); + stepHashMap.putIfAbsent(firstId, new Step(firstId)); stepHashMap.putIfAbsent(secondId, new Step(secondId)); stepHashMap.get(secondId).addPrevious(firstId); } } } + + /** + * Creates and returns a deep copy of the {@link Day07#stepHashMap} + * + * @return a copy of the {@link Day07#stepHashMap} + */ + private HashMap getCopyOfStepHashMap() { + HashMap copyOfStepHashMap = new HashMap<>(); + + stepHashMap.forEach((id, step) -> copyOfStepHashMap.put(id, new Step(step))); + + return copyOfStepHashMap; + } } \ No newline at end of file diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java index a65afe4..16e8bf4 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -9,14 +9,34 @@ public class Step { private ArrayList previousSteps = new ArrayList<>(); /** - * Constructs Step with + * Constructs Step with id. * - * @param id + * @param id the id of this Step */ public Step(Character id) { this.id = id; } + /** + * Constructs Step with id and previousSteps. + * + * @param id the id for this Step + * @param previousSteps the previous Steps for this Step + */ + public Step(Character id, ArrayList previousSteps) { + this.id = id; + this.previousSteps.addAll(previousSteps); + } + + /** + * Constructs Step as copy of another Step + * + * @param other the other Step to be copied + */ + public Step(Step other) { + this(other.id, other.previousSteps); + } + /** * Returns {@code true} if this step has previous steps * diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java index df2db9a..341fda6 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java @@ -47,13 +47,15 @@ public void getDay() { public void firstPart() { String expectedResult = "Part 1 - Order in which the steps in the instructions should be completed: CABDFE"; String actualResult = day07.firstPart(); + String actualResult2 = day07.firstPart(); Assert.assertEquals(expectedResult, actualResult); + Assert.assertEquals(expectedResult, actualResult2); } @Test public void secondPart() { - String expectedResult = "Part 2 - Length of the shortest polymer: 4"; + String expectedResult = "Part 2 - Time required to complete all of the steps: 15 seconds"; String actualResult = day07.secondPart(); Assert.assertEquals(expectedResult, actualResult); diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java index 5b470c5..0511d9f 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/StepTest.java @@ -31,4 +31,15 @@ public void testRemoveFromEmptyPreviousSteps() { step.removePrevious('Z'); Assert.assertFalse(step.hasPrevious()); } + + @Test + public void testCopiedStepIsNotJustReference() { + Step copiedStep = new Step(step); + + step.addPrevious('B'); + + Assert.assertTrue(step.hasPrevious()); + Assert.assertFalse(copiedStep.hasPrevious()); + + } } \ No newline at end of file From fa438b765adb9ba13b97893540ba20a896cc1f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Sat, 18 May 2019 13:43:19 +0200 Subject: [PATCH 06/16] AOC-024: Refactored, so there are no duplicates in `availableSteps` --- .../org/basseur/adventofcode/advent2018/days/day07/Day07.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 7f4e76f..85cc57f 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -85,7 +85,7 @@ private String determineOrder() { while (!steps.isEmpty()) { steps.forEach((id, step) -> { - if (!step.hasPrevious()) { + if (!step.hasPrevious() && !availableSteps.contains(id)) { availableSteps.add(id); } }); @@ -96,7 +96,7 @@ private String determineOrder() { steps.forEach((id, step) -> step.removePrevious(currentStep)); steps.remove(currentStep); - availableSteps.removeAll(Collections.singleton(currentStep)); + availableSteps.remove(currentStep); } return order.toString(); From 0fa6cac85e398fdca41b96d75bcc56ec0a4c32ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Sat, 18 May 2019 13:44:55 +0200 Subject: [PATCH 07/16] AOC-024: initial setup for Part2 --- .../basseur/adventofcode/advent2018/days/day07/Day07.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 85cc57f..558834a 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -37,7 +37,7 @@ public class Day07 implements Days { Day07(FileReaders fileReaders) { this.problemStatus = new HashMap<>(); this.problemStatus.put("1", ProblemStatusEnum.SOLVED); - this.problemStatus.put("2", ProblemStatusEnum.UNSOLVED); + this.problemStatus.put("2", ProblemStatusEnum.IN_PROGRESS); this.instructions = fileReaders.readFileIntoStringList(FILE_LOCATION); @@ -56,7 +56,7 @@ public String firstPart() { @Override public String secondPart() { - return ""; + return "Part 2 - Time required to complete all of the steps: " + determineTime() + " seconds"; } @Override @@ -102,6 +102,10 @@ private String determineOrder() { return order.toString(); } + private int determineTime() { + return 0; + } + /** * Parses the {@link Day07#instructions} to create {@link Step}s and add previous IDs. */ From eaf668e58c2d0ed820bac33cb4cca7bf01869ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Tue, 21 May 2019 21:50:26 +0200 Subject: [PATCH 08/16] AOC-024: Finished Day7, Part 2. --- .../advent2018/days/day07/Day07.java | 101 +++++++++++++++--- .../advent2018/days/day07/Step.java | 2 +- .../advent2018/days/day07/Day07Test.java | 4 + 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 558834a..f80b5ae 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -20,13 +20,18 @@ public class Day07 implements Days { /** The location of the puzzle input file */ private static final String FILE_LOCATION = "src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt"; + /** The difference between the integer value of a char and seconds to finish a step, e.g. `(int)char 'A' = 65`, but A takes 1 extra second. */ + private static int DIFFERENCE_BETWEEN_CHAR_AND_SECONDS = 64; /** The puzzle status {@code HashMap} */ private final HashMap problemStatus; - /** A list containing the instructions */ private final List instructions; /** A {@code Map} containing all the {@link Step}s mapped to their IDs */ private Map stepHashMap = new HashMap<>(); + /** Number of available Workers in Part 2 */ + private int workers = 5; + /** Minimum time per Task */ + private int minTimePerTask = 60; /** * Constructor for Day07. @@ -37,7 +42,7 @@ public class Day07 implements Days { Day07(FileReaders fileReaders) { this.problemStatus = new HashMap<>(); this.problemStatus.put("1", ProblemStatusEnum.SOLVED); - this.problemStatus.put("2", ProblemStatusEnum.IN_PROGRESS); + this.problemStatus.put("2", ProblemStatusEnum.SOLVED); this.instructions = fileReaders.readFileIntoStringList(FILE_LOCATION); @@ -65,10 +70,10 @@ public HashMap getProblemStatus() { } /** - * Primary Method for Day 7, Part 1 and helper for Part 2. + * Primary Method for Day 7, Part 1. *

* Determines the order, in which the instructions should be completed. - * For this purpose {@link Day07#stepHashMap} is copied. The new HashMap is + * For this purpose {@link #stepHashMap} is copied. The new HashMap is * scanned for all {@link Step}s that have no previous steps in them. These * are added to an ArrayList which then gets sorted alphabetically. The first * item is the current step, which gets added to the output. Subsequently, this @@ -79,35 +84,97 @@ public HashMap getProblemStatus() { * @return the ordered String of instructions */ private String determineOrder() { - List availableSteps = new ArrayList<>(); + List availableStepsIds = new ArrayList<>(); Map steps = getCopyOfStepHashMap(); StringBuilder order = new StringBuilder(); while (!steps.isEmpty()) { steps.forEach((id, step) -> { - if (!step.hasPrevious() && !availableSteps.contains(id)) { - availableSteps.add(id); + if (!step.hasPrevious() && !availableStepsIds.contains(id)) { + availableStepsIds.add(id); } }); - Collections.sort(availableSteps); - Character currentStep = availableSteps.get(0); - order.append(currentStep); + Collections.sort(availableStepsIds); + Character currentStepId = availableStepsIds.get(0); + order.append(currentStepId); - steps.forEach((id, step) -> step.removePrevious(currentStep)); - steps.remove(currentStep); - availableSteps.remove(currentStep); + steps.forEach((id, step) -> step.removePrevious(currentStepId)); + steps.remove(currentStepId); + availableStepsIds.remove(currentStepId); } return order.toString(); } + /** + * Primary method for Day 7, Part 2. + *

+ * Determines the time it takes to complete all tasks with the number of workers given in {@link #workers}. + * For this purpose, {@link #stepHashMap} is copied. In a while loop, first the available steps are determined. + * Secondly, each available step is given to a worker, if one is available. The time it takes for the step to + * be completed is calculated in this step and stored with the respective ID. In the third step, the time left + * is reduced. If there is just one second left, the step is removed from the map of Steps, from the list of + * previous steps in each other step and from the list of steps in progress. Lastly the time taken is increased + * by 1. If there are no more steps left, the while loop ends and the total time taken is returned. + * + * @return time it takes to complete all the tasks + */ private int determineTime() { - return 0; + Map steps = getCopyOfStepHashMap(); + int availableWorkers = workers; + + List availableSteps = new ArrayList<>(); + Map stepsInProgress = new HashMap<>(); + + int timeTaken = 0; + + while (!steps.isEmpty()) { + steps.forEach((id, step) -> { + if (!(step.hasPrevious() || availableSteps.contains(id) || stepsInProgress.containsKey(id))) { + availableSteps.add(id); + } + }); + + List stepsToRemoveFromAvailable = new ArrayList<>(); + for (Character id : availableSteps) { + if (availableWorkers > 0) { + int timeForThisId = id - DIFFERENCE_BETWEEN_CHAR_AND_SECONDS; + int timeToFinish = minTimePerTask + timeForThisId; + + stepsInProgress.put(id, timeToFinish); + availableWorkers--; + + stepsToRemoveFromAvailable.add(id); + } + } + availableSteps.removeAll(stepsToRemoveFromAvailable); + + List stepsToRemoveFromInProgress = new ArrayList<>(); + for (Map.Entry stepInProgress : stepsInProgress.entrySet()) { + int timeLeft = stepInProgress.getValue(); + char currentStepId = stepInProgress.getKey(); + + if (timeLeft > 1) { + --timeLeft; + stepInProgress.setValue(timeLeft); + } else { + steps.remove(currentStepId); + steps.forEach((id, step) -> step.removePrevious(currentStepId)); + stepsToRemoveFromInProgress.add(currentStepId); + availableWorkers++; + } + } + stepsInProgress.keySet().removeAll(stepsToRemoveFromInProgress); + + timeTaken++; + } + + return timeTaken; } /** - * Parses the {@link Day07#instructions} to create {@link Step}s and add previous IDs. + * Parses the {@link #instructions} to create {@link Step}s and add previous IDs. */ private void parseSteps() { for (String instruction : instructions) { @@ -125,9 +192,9 @@ private void parseSteps() { } /** - * Creates and returns a deep copy of the {@link Day07#stepHashMap} + * Creates and returns a deep copy of the {@link #stepHashMap} * - * @return a copy of the {@link Day07#stepHashMap} + * @return a copy of the {@link #stepHashMap} */ private HashMap getCopyOfStepHashMap() { HashMap copyOfStepHashMap = new HashMap<>(); diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java index 16e8bf4..e0335c9 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -5,7 +5,7 @@ public class Step { /** Letter of this step */ public final char id; - /** ArrayList of previous steps */ + /** List of previous steps */ private ArrayList previousSteps = new ArrayList<>(); /** diff --git a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java index 341fda6..b43bf48 100644 --- a/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java +++ b/src/test/java/org/basseur/adventofcode/advent2018/days/day07/Day07Test.java @@ -9,6 +9,7 @@ import org.mockito.Mockito; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; import java.util.ArrayList; import java.util.List; @@ -55,6 +56,9 @@ public void firstPart() { @Test public void secondPart() { + ReflectionTestUtils.setField(day07, "workers", 2); + ReflectionTestUtils.setField(day07, "minTimePerTask", 0); + String expectedResult = "Part 2 - Time required to complete all of the steps: 15 seconds"; String actualResult = day07.secondPart(); From fa3398a98c99e96c6b1a2733d1d690d22ead6ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Wed, 22 May 2019 10:25:24 +0200 Subject: [PATCH 09/16] AOC-024: refactored to use `List` instead of `Map`. --- .../advent2018/days/day07/Day07.java | 60 ++++++++++++------- .../advent2018/days/day07/Step.java | 2 +- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index f80b5ae..360d355 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -27,7 +27,7 @@ public class Day07 implements Days { /** A list containing the instructions */ private final List instructions; /** A {@code Map} containing all the {@link Step}s mapped to their IDs */ - private Map stepHashMap = new HashMap<>(); + private Map stepsMap = new HashMap<>(); /** Number of available Workers in Part 2 */ private int workers = 5; /** Minimum time per Task */ @@ -73,7 +73,7 @@ public HashMap getProblemStatus() { * Primary Method for Day 7, Part 1. *

* Determines the order, in which the instructions should be completed. - * For this purpose {@link #stepHashMap} is copied. The new HashMap is + * For this purpose {@link #stepsMap} is copied into a list. The new HashMap is * scanned for all {@link Step}s that have no previous steps in them. These * are added to an ArrayList which then gets sorted alphabetically. The first * item is the current step, which gets added to the output. Subsequently, this @@ -85,13 +85,13 @@ public HashMap getProblemStatus() { */ private String determineOrder() { List availableStepsIds = new ArrayList<>(); - Map steps = getCopyOfStepHashMap(); + List steps = getLocalCopyOfStepsMapAsArrayList(); StringBuilder order = new StringBuilder(); while (!steps.isEmpty()) { - steps.forEach((id, step) -> { - if (!step.hasPrevious() && !availableStepsIds.contains(id)) { - availableStepsIds.add(id); + steps.forEach((step) -> { + if (!step.hasPrevious() && !availableStepsIds.contains(step.id)) { + availableStepsIds.add(step.id); } }); @@ -99,8 +99,7 @@ private String determineOrder() { Character currentStepId = availableStepsIds.get(0); order.append(currentStepId); - steps.forEach((id, step) -> step.removePrevious(currentStepId)); - steps.remove(currentStepId); + removeStepFromListAndPreviousSteps(steps, currentStepId); availableStepsIds.remove(currentStepId); } @@ -111,7 +110,7 @@ private String determineOrder() { * Primary method for Day 7, Part 2. *

* Determines the time it takes to complete all tasks with the number of workers given in {@link #workers}. - * For this purpose, {@link #stepHashMap} is copied. In a while loop, first the available steps are determined. + * For this purpose, {@link #stepsMap} is copied into a list. In a while loop, first the available steps are determined. * Secondly, each available step is given to a worker, if one is available. The time it takes for the step to * be completed is calculated in this step and stored with the respective ID. In the third step, the time left * is reduced. If there is just one second left, the step is removed from the map of Steps, from the list of @@ -121,7 +120,7 @@ private String determineOrder() { * @return time it takes to complete all the tasks */ private int determineTime() { - Map steps = getCopyOfStepHashMap(); + List steps = getLocalCopyOfStepsMapAsArrayList(); int availableWorkers = workers; List availableSteps = new ArrayList<>(); @@ -130,9 +129,9 @@ private int determineTime() { int timeTaken = 0; while (!steps.isEmpty()) { - steps.forEach((id, step) -> { - if (!(step.hasPrevious() || availableSteps.contains(id) || stepsInProgress.containsKey(id))) { - availableSteps.add(id); + steps.forEach((step) -> { + if (!(step.hasPrevious() || availableSteps.contains(step.id) || stepsInProgress.containsKey(step.id))) { + availableSteps.add(step.id); } }); @@ -159,8 +158,7 @@ private int determineTime() { --timeLeft; stepInProgress.setValue(timeLeft); } else { - steps.remove(currentStepId); - steps.forEach((id, step) -> step.removePrevious(currentStepId)); + removeStepFromListAndPreviousSteps(steps, currentStepId); stepsToRemoveFromInProgress.add(currentStepId); availableWorkers++; } @@ -184,23 +182,39 @@ private void parseSteps() { char firstId = matcher.group(1).charAt(0); char secondId = matcher.group(2).charAt(0); - stepHashMap.putIfAbsent(firstId, new Step(firstId)); - stepHashMap.putIfAbsent(secondId, new Step(secondId)); - stepHashMap.get(secondId).addPrevious(firstId); + stepsMap.putIfAbsent(firstId, new Step(firstId)); + stepsMap.putIfAbsent(secondId, new Step(secondId)); + stepsMap.get(secondId).addPrevious(firstId); } } } /** - * Creates and returns a deep copy of the {@link #stepHashMap} + * Creates a deep copy of the {@link #stepsMap} and returns it as an ArrayList. * - * @return a copy of the {@link #stepHashMap} + * @return a copy of the {@link #stepsMap} as an ArrayList. */ - private HashMap getCopyOfStepHashMap() { - HashMap copyOfStepHashMap = new HashMap<>(); + private ArrayList getLocalCopyOfStepsMapAsArrayList() { + ArrayList copyOfStepHashMap = new ArrayList<>(); - stepHashMap.forEach((id, step) -> copyOfStepHashMap.put(id, new Step(step))); + stepsMap.forEach((id, step) -> copyOfStepHashMap.add(new Step(step))); return copyOfStepHashMap; } + + /** + * Removes the given step ID from the given List and the previous steps of its elements. + * + * @param stepsList list of Steps to remove from + * @param currentStepId ID of step to remove + */ + private void removeStepFromListAndPreviousSteps(List stepsList, char currentStepId) { + for (Iterator steps = stepsList.iterator(); steps.hasNext(); ) { + Step step = steps.next(); + step.removePrevious(currentStepId); + if (step.id == currentStepId) { + steps.remove(); + } + } + } } \ No newline at end of file diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java index e0335c9..4ae0913 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -40,7 +40,7 @@ public Step(Step other) { /** * Returns {@code true} if this step has previous steps * - * @return {@code true} if this Step has previous steps, {@code false} otherwise + * @return {@code true} if this Step has previous steps, {@code false} otherwise. */ public boolean hasPrevious() { return previousSteps.size() > 0; From f93e7cfc5b9830b0f36df76c6e5aaec7f854fe3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Thu, 18 Jul 2019 20:04:39 +0200 Subject: [PATCH 10/16] AOC-024: Updated to current folder structures. --- .../org/basseur/adventofcode/advent2018/days/day07/Day07.java | 2 +- .../days/day07/Input.txt => resources/puzzleInputs/Input07.txt} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/main/{java/org/basseur/adventofcode/advent2018/days/day07/Input.txt => resources/puzzleInputs/Input07.txt} (100%) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 360d355..25d0d22 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -19,7 +19,7 @@ public class Day07 implements Days { /** The location of the puzzle input file */ - private static final String FILE_LOCATION = "src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt"; + private static final String FILE_LOCATION = "/puzzleInputs/Input07.txt"; /** The difference between the integer value of a char and seconds to finish a step, e.g. `(int)char 'A' = 65`, but A takes 1 extra second. */ private static int DIFFERENCE_BETWEEN_CHAR_AND_SECONDS = 64; /** The puzzle status {@code HashMap} */ diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt b/src/main/resources/puzzleInputs/Input07.txt similarity index 100% rename from src/main/java/org/basseur/adventofcode/advent2018/days/day07/Input.txt rename to src/main/resources/puzzleInputs/Input07.txt From de93b99e688b11c6a5501a4a73b6b9ff242583ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Thu, 13 May 2021 23:50:05 +0200 Subject: [PATCH 11/16] final --- .../org/basseur/adventofcode/advent2018/days/day07/Step.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java index 4ae0913..645c911 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Step.java @@ -6,7 +6,7 @@ public class Step { /** Letter of this step */ public final char id; /** List of previous steps */ - private ArrayList previousSteps = new ArrayList<>(); + private final ArrayList previousSteps = new ArrayList<>(); /** * Constructs Step with id. From 63de375cfda087801e22e6676f0d8cfcf91f198d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Thu, 13 May 2021 23:52:25 +0200 Subject: [PATCH 12/16] formatting --- .../advent2018/days/day07/Day07.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 25d0d22..00a4b5a 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -20,7 +20,10 @@ public class Day07 implements Days { /** The location of the puzzle input file */ private static final String FILE_LOCATION = "/puzzleInputs/Input07.txt"; - /** The difference between the integer value of a char and seconds to finish a step, e.g. `(int)char 'A' = 65`, but A takes 1 extra second. */ + /** + * The difference between the integer value of a char and seconds to finish a step, e.g. `(int)char 'A' = 65`, but A + * takes 1 extra second. + */ private static int DIFFERENCE_BETWEEN_CHAR_AND_SECONDS = 64; /** The puzzle status {@code HashMap} */ private final HashMap problemStatus; @@ -72,14 +75,11 @@ public HashMap getProblemStatus() { /** * Primary Method for Day 7, Part 1. *

- * Determines the order, in which the instructions should be completed. - * For this purpose {@link #stepsMap} is copied into a list. The new HashMap is - * scanned for all {@link Step}s that have no previous steps in them. These - * are added to an ArrayList which then gets sorted alphabetically. The first - * item is the current step, which gets added to the output. Subsequently, this - * step gets removed from all {@link Step#previousSteps} and from the HashMap, - * as well as from the available Steps. This process gets repeated until the - * HashMap is empty. + * Determines the order, in which the instructions should be completed. For this purpose {@link #stepsMap} is copied + * into a list. The new HashMap is scanned for all {@link Step}s that have no previous steps in them. These are + * added to an ArrayList which then gets sorted alphabetically. The first item is the current step, which gets added + * to the output. Subsequently, this step gets removed from all previous steps and from the HashMap, as well as from + * the available Steps. This process gets repeated until the HashMap is empty. * * @return the ordered String of instructions */ @@ -109,13 +109,13 @@ private String determineOrder() { /** * Primary method for Day 7, Part 2. *

- * Determines the time it takes to complete all tasks with the number of workers given in {@link #workers}. - * For this purpose, {@link #stepsMap} is copied into a list. In a while loop, first the available steps are determined. - * Secondly, each available step is given to a worker, if one is available. The time it takes for the step to - * be completed is calculated in this step and stored with the respective ID. In the third step, the time left - * is reduced. If there is just one second left, the step is removed from the map of Steps, from the list of - * previous steps in each other step and from the list of steps in progress. Lastly the time taken is increased - * by 1. If there are no more steps left, the while loop ends and the total time taken is returned. + * Determines the time it takes to complete all tasks with the number of workers given in {@link #workers}. For this + * purpose, {@link #stepsMap} is copied into a list. In a while loop, first the available steps are determined. + * Secondly, each available step is given to a worker, if one is available. The time it takes for the step to be + * completed is calculated in this step and stored with the respective ID. In the third step, the time left is + * reduced. If there is just one second left, the step is removed from the map of Steps, from the list of previous + * steps in each other step and from the list of steps in progress. Lastly the time taken is increased by 1. If + * there are no more steps left, the while loop ends and the total time taken is returned. * * @return time it takes to complete all the tasks */ @@ -217,4 +217,4 @@ private void removeStepFromListAndPreviousSteps(List stepsList, char curre } } } -} \ No newline at end of file +} From 5c5552cd0eae3a5c72c56dfc0b05fa5612647609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Thu, 13 May 2021 23:53:23 +0200 Subject: [PATCH 13/16] final; formatting --- .../adventofcode/advent2018/days/day07/Day07.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 00a4b5a..79c5c69 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -20,21 +20,27 @@ public class Day07 implements Days { /** The location of the puzzle input file */ private static final String FILE_LOCATION = "/puzzleInputs/Input07.txt"; + /** * The difference between the integer value of a char and seconds to finish a step, e.g. `(int)char 'A' = 65`, but A * takes 1 extra second. */ - private static int DIFFERENCE_BETWEEN_CHAR_AND_SECONDS = 64; + private static final int DIFFERENCE_BETWEEN_CHAR_AND_SECONDS = 64; + /** The puzzle status {@code HashMap} */ private final HashMap problemStatus; + /** A list containing the instructions */ private final List instructions; + /** A {@code Map} containing all the {@link Step}s mapped to their IDs */ - private Map stepsMap = new HashMap<>(); + private final Map stepsMap = new HashMap<>(); + /** Number of available Workers in Part 2 */ - private int workers = 5; + private final int workers = 5; + /** Minimum time per Task */ - private int minTimePerTask = 60; + private final int minTimePerTask = 60; /** * Constructor for Day07. From a6aae6790f2a98a7ccd1622bc596c4d95d25b812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Fri, 14 May 2021 00:04:49 +0200 Subject: [PATCH 14/16] use list instead of array list --- .../org/basseur/adventofcode/advent2018/days/day07/Day07.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 79c5c69..8404732 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -200,8 +200,8 @@ private void parseSteps() { * * @return a copy of the {@link #stepsMap} as an ArrayList. */ - private ArrayList getLocalCopyOfStepsMapAsArrayList() { - ArrayList copyOfStepHashMap = new ArrayList<>(); + private List getLocalCopyOfStepsMapAsArrayList() { + final List copyOfStepHashMap = new ArrayList<>(); stepsMap.forEach((id, step) -> copyOfStepHashMap.add(new Step(step))); From c0e592a87e37ccaa4f17a788177f1ff5f6333833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Fri, 14 May 2021 00:08:06 +0200 Subject: [PATCH 15/16] finals --- .../advent2018/days/day07/Day07.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 8404732..058a4d4 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -48,7 +48,7 @@ public class Day07 implements Days { * @param fileReaders {@code @Autowired} fileReader */ @Autowired - Day07(FileReaders fileReaders) { + Day07(final FileReaders fileReaders) { this.problemStatus = new HashMap<>(); this.problemStatus.put("1", ProblemStatusEnum.SOLVED); this.problemStatus.put("2", ProblemStatusEnum.SOLVED); @@ -90,9 +90,9 @@ public HashMap getProblemStatus() { * @return the ordered String of instructions */ private String determineOrder() { - List availableStepsIds = new ArrayList<>(); - List steps = getLocalCopyOfStepsMapAsArrayList(); - StringBuilder order = new StringBuilder(); + final List availableStepsIds = new ArrayList<>(); + final List steps = getLocalCopyOfStepsMapAsArrayList(); + final StringBuilder order = new StringBuilder(); while (!steps.isEmpty()) { steps.forEach((step) -> { @@ -102,7 +102,7 @@ private String determineOrder() { }); Collections.sort(availableStepsIds); - Character currentStepId = availableStepsIds.get(0); + final Character currentStepId = availableStepsIds.get(0); order.append(currentStepId); removeStepFromListAndPreviousSteps(steps, currentStepId); @@ -126,11 +126,11 @@ private String determineOrder() { * @return time it takes to complete all the tasks */ private int determineTime() { - List steps = getLocalCopyOfStepsMapAsArrayList(); + final List steps = getLocalCopyOfStepsMapAsArrayList(); int availableWorkers = workers; - List availableSteps = new ArrayList<>(); - Map stepsInProgress = new HashMap<>(); + final List availableSteps = new ArrayList<>(); + final Map stepsInProgress = new HashMap<>(); int timeTaken = 0; @@ -141,11 +141,11 @@ private int determineTime() { } }); - List stepsToRemoveFromAvailable = new ArrayList<>(); - for (Character id : availableSteps) { + final List stepsToRemoveFromAvailable = new ArrayList<>(); + for (final Character id : availableSteps) { if (availableWorkers > 0) { - int timeForThisId = id - DIFFERENCE_BETWEEN_CHAR_AND_SECONDS; - int timeToFinish = minTimePerTask + timeForThisId; + final int timeForThisId = id - DIFFERENCE_BETWEEN_CHAR_AND_SECONDS; + final int timeToFinish = minTimePerTask + timeForThisId; stepsInProgress.put(id, timeToFinish); availableWorkers--; @@ -155,10 +155,10 @@ private int determineTime() { } availableSteps.removeAll(stepsToRemoveFromAvailable); - List stepsToRemoveFromInProgress = new ArrayList<>(); - for (Map.Entry stepInProgress : stepsInProgress.entrySet()) { + final List stepsToRemoveFromInProgress = new ArrayList<>(); + for (final Map.Entry stepInProgress : stepsInProgress.entrySet()) { int timeLeft = stepInProgress.getValue(); - char currentStepId = stepInProgress.getKey(); + final char currentStepId = stepInProgress.getKey(); if (timeLeft > 1) { --timeLeft; @@ -181,12 +181,12 @@ private int determineTime() { * Parses the {@link #instructions} to create {@link Step}s and add previous IDs. */ private void parseSteps() { - for (String instruction : instructions) { - Matcher matcher = Pattern.compile("Step (\\w) must be finished before step (\\w) can begin\\.").matcher(instruction); + for (final String instruction : instructions) { + final Matcher matcher = Pattern.compile("Step (\\w) must be finished before step (\\w) can begin\\.").matcher(instruction); if (matcher.find()) { - char firstId = matcher.group(1).charAt(0); - char secondId = matcher.group(2).charAt(0); + final char firstId = matcher.group(1).charAt(0); + final char secondId = matcher.group(2).charAt(0); stepsMap.putIfAbsent(firstId, new Step(firstId)); stepsMap.putIfAbsent(secondId, new Step(secondId)); @@ -214,9 +214,9 @@ private List getLocalCopyOfStepsMapAsArrayList() { * @param stepsList list of Steps to remove from * @param currentStepId ID of step to remove */ - private void removeStepFromListAndPreviousSteps(List stepsList, char currentStepId) { - for (Iterator steps = stepsList.iterator(); steps.hasNext(); ) { - Step step = steps.next(); + private void removeStepFromListAndPreviousSteps(final List stepsList, final char currentStepId) { + for (final Iterator steps = stepsList.iterator(); steps.hasNext(); ) { + final Step step = steps.next(); step.removePrevious(currentStepId); if (step.id == currentStepId) { steps.remove(); From b273476bd81ee074ddc0f1b0f69303050d06670f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Philipp=20G=C3=B6lz?= Date: Fri, 14 May 2021 00:08:23 +0200 Subject: [PATCH 16/16] use foreach, which is faster --- .../org/basseur/adventofcode/advent2018/days/day07/Day07.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java index 058a4d4..83ad69e 100644 --- a/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java +++ b/src/main/java/org/basseur/adventofcode/advent2018/days/day07/Day07.java @@ -169,7 +169,7 @@ private int determineTime() { availableWorkers++; } } - stepsInProgress.keySet().removeAll(stepsToRemoveFromInProgress); + stepsToRemoveFromInProgress.forEach(stepsInProgress.keySet()::remove); timeTaken++; }