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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy