Skip to content

Commit 721dc53

Browse files
committed
Day 8
1 parent 6ec140f commit 721dc53

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed

src/test/java/com/macasaet/Day08.java

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package com.macasaet;
2+
3+
import java.util.*;
4+
import java.util.stream.Collectors;
5+
import java.util.stream.Stream;
6+
import java.util.stream.StreamSupport;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
/**
11+
* --- Day 8: Seven Segment Search ---
12+
*/
13+
public class Day08 {
14+
15+
protected Stream<String> getInput() {
16+
return StreamSupport
17+
.stream(new LineSpliterator("day-08.txt"),
18+
false);
19+
}
20+
21+
public record Digit(List<Character> segments) {
22+
public Digit decode(final Map<Character, Character> map) {
23+
return new Digit(segments().stream()
24+
.map(map::get)
25+
.collect(Collectors.toUnmodifiableList()));
26+
}
27+
28+
public int asInt() {
29+
if (segments().size() == 6 && hasSegments('a', 'b', 'c', 'e', 'f', 'g')) { // FIXME use on/off mechanism
30+
return 0;
31+
} else if (segments().size() == 2 && hasSegments('c', 'f')) {
32+
return 1;
33+
} else if (segments().size() == 5 && hasSegments('a', 'c', 'd', 'e', 'g')) {
34+
return 2;
35+
} else if (segments().size() == 5 && hasSegments('a', 'c', 'd', 'f', 'g')) {
36+
return 3;
37+
} else if (segments().size() == 4 && hasSegments('b', 'c', 'd', 'f')) {
38+
return 4;
39+
} else if (segments().size() == 5 && hasSegments('a', 'b', 'd', 'f', 'g')) {
40+
return 5;
41+
} else if (segments().size() == 6 && hasSegments('a', 'b', 'd', 'e', 'f', 'g')) {
42+
return 6;
43+
} else if (segments().size() == 3 && hasSegments('a', 'c', 'f')) {
44+
return 7;
45+
} else if (segments().size() == 7 && hasSegments('a', 'b', 'c', 'd', 'e', 'f', 'g')) {
46+
return 8;
47+
} else if (segments().size() == 6 && hasSegments('a', 'b', 'c', 'd', 'f', 'g')) {
48+
return 9;
49+
}
50+
throw new IllegalStateException("Invalid Digit: " + this);
51+
}
52+
53+
public boolean hasSegments(final char... segments) {
54+
for (final var segment : segments) {
55+
if (!hasSegment(segment)) {
56+
return false;
57+
}
58+
}
59+
return true;
60+
}
61+
62+
public boolean hasSegment(final char segment) {
63+
return segments().contains(segment);
64+
}
65+
66+
public static Digit parse(final String string) {
67+
final var array = string.toCharArray();
68+
final var list = new ArrayList<Character>(array.length);
69+
for (final var c : array) {
70+
list.add(c);
71+
}
72+
return new Digit(Collections.unmodifiableList(list));
73+
}
74+
}
75+
76+
public static record Entry(List<Digit> uniqueSignalPatterns, List<Digit> outputValue) {
77+
78+
public int decodeOutput() {
79+
final var map = buildDecodingMap();
80+
final StringBuilder builder = new StringBuilder();
81+
for (final var outputDigit : outputValue()) {
82+
final var decodedDigit = outputDigit.decode(map);
83+
final int digit = decodedDigit.asInt();
84+
builder.append(digit);
85+
}
86+
final String stringInt = builder.toString();
87+
return Integer.parseInt(stringInt);
88+
}
89+
90+
protected SortedSet<Character> getDigitSegmentsWithCount(final int n) {
91+
return uniqueSignalPatterns().stream()
92+
.filter(digit -> digit.segments().size() == n)
93+
.findFirst()
94+
.get()
95+
.segments()
96+
.stream()
97+
.collect(TreeSet::new, SortedSet::add, SortedSet::addAll);
98+
}
99+
100+
protected Set<Digit> getDigitsWithCount(final int n) { // TODO return stream
101+
return uniqueSignalPatterns()
102+
.stream()
103+
.filter(digit -> digit.segments().size() == n).collect(Collectors.toUnmodifiableSet());
104+
}
105+
106+
public Map<Character, Character> buildDecodingMap() {
107+
final var encodingMap = buildEncodingMap();
108+
final var result = new HashMap<Character, Character>();
109+
for(final var entry : encodingMap.entrySet()) {
110+
result.put(entry.getValue(), entry.getKey());
111+
}
112+
return Collections.unmodifiableMap(result);
113+
}
114+
115+
public Map<Character, Character> buildEncodingMap() {
116+
final var map = new HashMap<Character, Character>();
117+
final var oneSegments = getDigitSegmentsWithCount(2);
118+
final var sevenSegments = getDigitSegmentsWithCount(3);
119+
final var fourSegments = getDigitSegmentsWithCount(4);
120+
final var eightSegments = getDigitSegmentsWithCount(7);
121+
final var aMapping = sevenSegments.stream().filter(c -> !oneSegments.contains(c)).findFirst().get();
122+
map.put('a', aMapping);
123+
124+
final var zeroSixNine = getDigitsWithCount(6);
125+
var zsnSegments = zeroSixNine.stream().flatMap(digit -> digit.segments().stream()).collect(Collectors.toList());
126+
zsnSegments.removeIf(sevenSegments::contains);
127+
zsnSegments.removeIf(fourSegments::contains);
128+
final var sssMap = new HashMap<Character, Integer>();
129+
for (final var c : zsnSegments) {
130+
sssMap.compute(c, (_key, old) -> old == null ? 1 : old + 1);
131+
}
132+
if(sssMap.size() != 2) {
133+
throw new IllegalStateException("More segments for 0, 6, 9 encountered: " + sssMap);
134+
}
135+
for (final var entry : sssMap.entrySet()) {
136+
if (entry.getValue() == 3) {
137+
map.put('g', entry.getKey());
138+
} else if (entry.getValue() == 2) {
139+
map.put('e', entry.getKey());
140+
} else {
141+
throw new IllegalStateException();
142+
}
143+
}
144+
145+
final var twoFiveThree = getDigitsWithCount(5);
146+
var tftSegments = twoFiveThree.stream().flatMap(digit -> digit.segments.stream()).collect(Collectors.toList());
147+
tftSegments.removeIf(sevenSegments::contains);
148+
tftSegments.removeIf(candidate -> candidate.equals(map.get('e')));
149+
tftSegments.removeIf(candidate -> candidate.equals(map.get('g')));
150+
final var tftCounts = new HashMap<Character, Integer>();
151+
for(final var c : tftSegments) {
152+
tftCounts.compute(c, (_key, old) -> old == null ? 1 : old + 1);
153+
}
154+
for(final var entry : tftCounts.entrySet()) {
155+
if(entry.getValue() == 3) {
156+
map.put('d', entry.getKey());
157+
} else if(entry.getValue() == 1) {
158+
map.put('b', entry.getKey());
159+
} else {
160+
throw new IllegalStateException();
161+
}
162+
}
163+
164+
zsnSegments = zeroSixNine.stream().flatMap(digit -> digit.segments().stream()).collect(Collectors.toList());
165+
zsnSegments.removeIf(candidate -> candidate.equals(map.get('a')));
166+
zsnSegments.removeIf(candidate -> candidate.equals(map.get('b')));
167+
zsnSegments.removeIf(candidate -> candidate.equals(map.get('d')));
168+
zsnSegments.removeIf(candidate -> candidate.equals(map.get('e')));
169+
zsnSegments.removeIf(candidate -> candidate.equals(map.get('g')));
170+
final var zsnCounts = new HashMap<Character, Integer>();
171+
for(final var c : zsnSegments) {
172+
zsnCounts.compute(c, (_key, old) -> old == null ? 1 : old + 1);
173+
}
174+
for(final var entry : zsnCounts.entrySet()) {
175+
if(entry.getValue() == 2) {
176+
map.put('c', entry.getKey());
177+
} else if( entry.getValue() == 3) {
178+
map.put('f', entry.getKey());
179+
} else {
180+
throw new IllegalStateException();
181+
}
182+
}
183+
184+
return map;
185+
}
186+
187+
public static Entry parse(final String string) {
188+
final var components = string.split(" \\| ");
189+
final var uniqueSignalPatterns = components[0].split(" ");
190+
final var outputValue = components[1].split(" ");
191+
192+
return new Entry(Arrays.stream(uniqueSignalPatterns)
193+
.map(Digit::parse)
194+
.collect(Collectors.toUnmodifiableList()),
195+
Arrays.stream(outputValue)
196+
.map(Digit::parse)
197+
.collect(Collectors.toUnmodifiableList()));
198+
}
199+
200+
}
201+
202+
@Test
203+
public final void part1() {
204+
final var result = getInput()
205+
.map(Entry::parse)
206+
.flatMap(entry -> entry.outputValue().stream())
207+
.filter(digit -> {
208+
final var segments = digit.segments();
209+
final var numSegments = segments.size();
210+
return numSegments == 2 || numSegments == 4 || numSegments == 3 || numSegments == 7;
211+
})
212+
.count();
213+
System.out.println("Part 1: " + result);
214+
}
215+
216+
@Test
217+
public final void part2() {
218+
final var result = getInput()
219+
.map(Entry::parse)
220+
.mapToInt(Entry::decodeOutput).sum();
221+
222+
System.out.println("Part 2: " + result);
223+
}
224+
225+
}

src/test/resources/sample/day-08.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe
2+
edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc
3+
fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg
4+
fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb
5+
aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea
6+
fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb
7+
dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe
8+
bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef
9+
egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb
10+
gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce

0 commit comments

Comments
 (0)