Skip to content
Snippets Groups Projects
Commit 6e55cf34 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Day 8 complete

parent 3048a067
No related branches found
No related tags found
No related merge requests found
......@@ -55,3 +55,33 @@ work.
Part 2 looks a bit more interesting. We *could* go for an
O(num_crabs * max_distance^2) solution, or we could recognize what Euler
recognized: ∑_{i=1}^{n}i = n(n+1)/2.
### Day 8
Seven-segment displays are cool. This has the potential to be a pain. Part 1
looks okay -- examining only the output patterns, count the number of patterns
of length 2, 3, 4, or 7.
For part 2, I think set operations are the way to go. For simplicity in this
explanation, I'm going to use numerals to depict the sets of illuminated segments.
- Those we know from length alone:
- 1 is the only digit of length 2
- 7 is the only digit of length 3
- 4 is the only digit of length 4
- 8 is the only digit of length 7
- 7\1 gives us the top segment
- Considering the length-6 digits:
- 9 is the only one for which 4\digit = ø, giving us the lower-left segment
- 6 is the only one for which 1\digit ≠ ø, giving us the upper-right segment
- 0 remains, giving us the central segment
- (9\7)\4 gives us the bottom segment
- 1\{upper-right segment} gives us the lower-right segment
- The upper-left segment remains
- Considering the length-5 digits:
- 3 is the only digit for which digit U 1 = digit
- 5 is the only remaining digit for which digit U 4 = 9
- 2 remains
It turns out we can ascertain the digits without needing to record the segments.
That's nifty.
package edu.unl.cse.bohn.year2021;
import edu.unl.cse.bohn.Puzzle;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings("unused")
public class Day8 extends Puzzle {
@SuppressWarnings("SpellCheckingInspection")
public Day8(boolean isProductionReady) {
super(isProductionReady);
// sampleData = "acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf";
sampleData = """
be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe
edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc
fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg
fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb
aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea
fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb
dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe
bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef
egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb
gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce""";
}
@Override
public long computePart1(List<String> data) {
Set<Integer> suitableDigitLengths = Set.of(2, 3, 4, 7);
long numberOfMatchingDigits = 0;
for (String line : data) {
String[] halves = line.split(" \\| ");
for (String digit : halves[1].split(" ")) {
if (suitableDigitLengths.contains(digit.length())) {
numberOfMatchingDigits++;
}
}
}
return numberOfMatchingDigits;
}
private String sortSegments(String segments) {
return segments.chars()
.sorted()
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
}
private Set<Character> stringToSet(String segments) {
return new HashSet<>(segments.chars().mapToObj(c -> (char)c).toList());
}
@Override
public long computePart2(List<String> data) {
long sumOfValues = 0L;
for(String line:data) {
Map<String, Long> numerals = new HashMap<>();
String[] halves = line.split(" \\| ");
for (String segmentPattern : halves[0].split(" ")) {
numerals.put(sortSegments(segmentPattern), null);
}
Set<String> segmentPatterns = numerals.keySet();
// Identify which patterns correspond to which digits. See the README for the reasoning.
// First the patterns whose length are unique
String one = segmentPatterns.stream().filter(pattern -> pattern.length() == 2).findAny().orElseThrow();
numerals.put(one, 1L);
String seven = segmentPatterns.stream().filter(pattern -> pattern.length() == 3).findAny().orElseThrow();
numerals.put(seven, 7L);
String four = segmentPatterns.stream().filter(pattern -> pattern.length() == 4).findAny().orElseThrow();
numerals.put(four, 4L);
String eight = segmentPatterns.stream().filter(pattern -> pattern.length() == 7).findAny().orElseThrow();
numerals.put(eight, 8L);
// Then the patterns of length 6
Set<String> candidates = segmentPatterns.stream()
.filter(pattern -> pattern.length() == 6)
.collect(Collectors.toSet());
String nine = "";
for (String candidate : candidates) {
Set<Character> candidateSet = stringToSet(candidate);
Set<Character> copyOfFour = new HashSet<>(stringToSet(four));
copyOfFour.removeAll(candidateSet);
if (copyOfFour.isEmpty()) {
nine = candidate;
numerals.put(nine, 9L);
}
}
candidates.remove(nine);
String six = "";
for (String candidate : candidates) {
Set<Character> candidateSet = stringToSet(candidate);
Set<Character> copyOfOne = new HashSet<>(stringToSet(one));
copyOfOne.removeAll(candidateSet);
if (!copyOfOne.isEmpty()) {
six = candidate;
numerals.put(six, 6L);
}
}
candidates.remove(six);
String zero = candidates.stream().findAny().orElseThrow();
numerals.put(zero, 0L);
// The remaining patterns are all length 5
candidates = segmentPatterns.stream()
.filter(pattern -> pattern.length() == 5)
.collect(Collectors.toSet());
String three = "";
for (String candidate : candidates) {
Set<Character> candidateSet = stringToSet(candidate);
Set<Character> copyOfCandidateSet = new HashSet<>(candidateSet);
candidateSet.addAll(stringToSet(one));
if (candidateSet.equals(copyOfCandidateSet)) {
three = candidate;
numerals.put(three, 3L);
}
}
candidates.remove(three);
String five = "";
for (String candidate : candidates) {
Set<Character> candidateSet = stringToSet(candidate);
candidateSet.addAll(stringToSet(four));
if (candidateSet.equals(stringToSet(nine))) {
five = candidate;
numerals.put(five, 5L);
}
}
candidates.remove(five);
String two = candidates.stream().findAny().orElseThrow();
numerals.put(two, 2L);
// Now determine the output value
long lineValue = 0L;
long magnitude = 1000L;
for (String displayDigit : halves[1].split(" ")) {
long digitValue = numerals.get(sortSegments(displayDigit));
lineValue += magnitude * digitValue;
magnitude /= 10;
}
sumOfValues += lineValue;
}
return sumOfValues;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment