Skip to content

Commit 9a2d23a

Browse files
committed
Advent of Code 2021 - Day 16
1 parent 268632a commit 9a2d23a

File tree

5 files changed

+249
-10
lines changed

5 files changed

+249
-10
lines changed

src/main/java/com/codingnagger/App.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
package com.codingnagger;
22

33
import com.codingnagger.days.Day;
4-
import com.codingnagger.days.Day10;
5-
import com.codingnagger.days.Day11;
6-
import com.codingnagger.days.Day12;
7-
import com.codingnagger.days.Day13;
8-
import com.codingnagger.days.Day14;
9-
import com.codingnagger.days.Day15;
10-
import com.codingnagger.days.Day17;
11-
import com.codingnagger.days.Day9;
4+
import com.codingnagger.days.Day16;
125
import com.codingnagger.utils.InputLoader;
136

147
import java.io.IOException;
@@ -21,9 +14,9 @@ public class App {
2114
public static void main(String[] args) throws IOException {
2215
System.out.println("Advent of Code 2021");
2316

24-
List<String> input = InputLoader.Load("day17.txt");
17+
List<String> input = InputLoader.Load("day16.txt");
2518

26-
Day day = new Day17();
19+
Day day = new Day16();
2720

2821
System.out.println("Part 1:");
2922
System.out.println(day.partOne(input));
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package com.codingnagger.days;
2+
3+
import java.math.BigDecimal;
4+
import java.math.BigInteger;
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.LinkedList;
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.stream.Collectors;
11+
12+
public class Day16 implements Day {
13+
private static final Map<String, String> HEXA_MAP = Map.ofEntries(
14+
Map.entry("0", "0000"), Map.entry("1", "0001"), Map.entry("2", "0010"),
15+
Map.entry("3", "0011"), Map.entry("4", "0100"), Map.entry("5", "0101"),
16+
Map.entry("6", "0110"), Map.entry("7", "0111"), Map.entry("8", "1000"),
17+
Map.entry("9", "1001"), Map.entry("A", "1010"), Map.entry("B", "1011"),
18+
Map.entry("C", "1100"), Map.entry("D", "1101"), Map.entry("E", "1110"),
19+
Map.entry("F", "1111"));
20+
21+
private static final String L15_BITS = "0";
22+
private static final String L11_BITS = "1";
23+
24+
private static final int T_LITERAL = 4;
25+
26+
private static final String G_LITERAL_LAST_GROUP = "0";
27+
28+
@Override
29+
public String partOne(List<String> input) {
30+
Packet rootPacket = parse(input.get(0));
31+
return String.valueOf(rootPacket.getVersionSum());
32+
}
33+
34+
@Override
35+
public String partTwo(List<String> input) {
36+
Packet rootPacket = parse(input.get(0));
37+
return String.valueOf(rootPacket.computeValue());
38+
}
39+
40+
public static Packet parse(String input) {
41+
String binaryInput = convertHexaToBinaryString(input);
42+
return getPackets(binaryInput);
43+
}
44+
45+
private static Packet getPackets(String binaryInput) {
46+
LinkedList<Character> bitsQueue = Arrays.stream(binaryInput.split("")).filter(s -> !s.isBlank()).map(s -> s.charAt(0)).collect(Collectors.toCollection(LinkedList::new));
47+
return readPacket(bitsQueue).getPacket();
48+
}
49+
50+
private static PacketReadResult readPacket(LinkedList<Character> bitsQueue) {
51+
int packetVersion = Integer.parseInt(readBits(bitsQueue, 3), 2);
52+
int packetTypeId = Integer.parseInt(readBits(bitsQueue, 3), 2);
53+
int readBits = 6;
54+
55+
if (packetTypeId == T_LITERAL) {
56+
StringBuilder binaryContentsBuilder = new StringBuilder();
57+
58+
while(!G_LITERAL_LAST_GROUP.equals(readBits(bitsQueue, 1))) {
59+
binaryContentsBuilder.append(readBits(bitsQueue, 4));
60+
readBits += 5;
61+
}
62+
63+
binaryContentsBuilder.append(readBits(bitsQueue, 4));
64+
readBits += 5;
65+
66+
return new PacketReadResult(new LiteralPacket(packetVersion, packetTypeId, binaryContentsBuilder.toString()), readBits);
67+
} else {
68+
String lengthTypeId = readBits(bitsQueue, 1);
69+
List<Packet> children = new ArrayList<>();
70+
71+
if (L15_BITS.equals(lengthTypeId)) {
72+
int bitsToRead = Integer.parseInt(readBits(bitsQueue, 15), 2);
73+
74+
LinkedList<Character> childrenBitsToRead = new LinkedList<>();
75+
76+
for (int i = 0; i < bitsToRead; i++) {
77+
childrenBitsToRead.add(bitsQueue.poll());
78+
}
79+
80+
while (!childrenBitsToRead.isEmpty()) {
81+
PacketReadResult res = readPacket(childrenBitsToRead);
82+
83+
bitsToRead -= res.getReadBits();
84+
readBits += res.getReadBits();
85+
children.add(res.getPacket());
86+
}
87+
88+
System.out.printf("Bits left to read: %d%n", bitsToRead);
89+
} else if (L11_BITS.equals(lengthTypeId)) {
90+
int childrenToRead = Integer.parseInt(readBits(bitsQueue, 11), 2);
91+
92+
while (childrenToRead > 0) {
93+
PacketReadResult res = readPacket(bitsQueue);
94+
95+
readBits += res.getReadBits();
96+
children.add(res.getPacket());
97+
childrenToRead--;
98+
}
99+
}
100+
101+
return new PacketReadResult(new OperationPacket(packetVersion, packetTypeId, children), readBits);
102+
}
103+
}
104+
105+
private static String readBits(LinkedList<Character> bitsQueue, int count) {
106+
StringBuilder sb = new StringBuilder(count);
107+
108+
for (int i = 0; i < count; i++) {
109+
sb.append(bitsQueue.poll());
110+
}
111+
112+
return sb.toString();
113+
}
114+
115+
public static String convertHexaToBinaryString(String hexa) {
116+
return Arrays.stream(hexa.split("")).map(HEXA_MAP::get).collect(Collectors.joining(""));
117+
}
118+
119+
static class PacketReadResult {
120+
private final Packet packet;
121+
private final int readBits;
122+
123+
public PacketReadResult(Packet packet, int readBits) {
124+
this.packet = packet;
125+
this.readBits = readBits;
126+
}
127+
128+
public Packet getPacket() {
129+
return packet;
130+
}
131+
132+
public int getReadBits() {
133+
return readBits;
134+
}
135+
}
136+
137+
static abstract class Packet {
138+
private final int packetVersion;
139+
private final int packetTypeId;
140+
141+
public Packet(int packetVersion, int packetTypeId) {
142+
this.packetVersion = packetVersion;
143+
this.packetTypeId = packetTypeId;
144+
}
145+
146+
public int getPacketVersion() {
147+
return packetVersion;
148+
}
149+
150+
public int getPacketTypeId() {
151+
return packetTypeId;
152+
}
153+
154+
public int getVersionSum() {
155+
return packetVersion;
156+
}
157+
158+
public abstract BigDecimal computeValue();
159+
}
160+
161+
static class LiteralPacket extends Packet {
162+
private final String binaryContents;
163+
164+
public LiteralPacket(int packetVersion, int packetTypeId, String binaryContents) {
165+
super(packetVersion, packetTypeId);
166+
this.binaryContents = binaryContents;
167+
}
168+
169+
public String getBinaryContents() {
170+
return binaryContents;
171+
}
172+
173+
public BigDecimal computeValue() {
174+
return new BigDecimal(new BigInteger(binaryContents, 2).longValue());
175+
}
176+
}
177+
178+
static class OperationPacket extends Packet {
179+
private final List<Packet> subPackets;
180+
181+
public OperationPacket(int packetVersion, int packetTypeId, List<Packet> subPackets) {
182+
super(packetVersion, packetTypeId);
183+
this.subPackets = subPackets;
184+
}
185+
186+
@Override
187+
public int getVersionSum() {
188+
return getPacketVersion() + subPackets.stream().mapToInt(Packet::getVersionSum).sum();
189+
}
190+
191+
public BigDecimal computeValue() {
192+
switch (getPacketTypeId()) {
193+
case 0: return subPackets.stream().map(Packet::computeValue).reduce(BigDecimal.ZERO, BigDecimal::add);
194+
case 1: return subPackets.stream().map(Packet::computeValue).reduce(BigDecimal.ONE, BigDecimal::multiply);
195+
case 2: return subPackets.stream().map(Packet::computeValue).reduce(BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal::min);
196+
case 3: return subPackets.stream().map(Packet::computeValue).reduce(BigDecimal.valueOf(Long.MIN_VALUE), BigDecimal::max);
197+
198+
case 5: return subPackets.get(0).computeValue().compareTo(subPackets.get(1).computeValue()) > 0 ? BigDecimal.ONE : BigDecimal.ZERO;
199+
case 6: return subPackets.get(0).computeValue().compareTo(subPackets.get(1).computeValue()) < 0 ? BigDecimal.ONE : BigDecimal.ZERO;
200+
case 7: return subPackets.get(0).computeValue().equals(subPackets.get(1).computeValue() ) ? BigDecimal.ONE : BigDecimal.ZERO;
201+
}
202+
203+
return null;
204+
}
205+
}
206+
}

src/main/resources/day16.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
020D790050D26C13EC1348326D336ACE00EC299E6A8B929ED59C880502E00A526B969F62BF35CB4FB15B93A6311F67F813300470037500043E2D4218FA000864538E905A39CAF77386E35AB01802FC01BA00021118617C1F00043A3F4748A53CF66008D00481272D73308334EDB0ED304E200D4E94CF612A49B40036C98A7CF24A53CA94C6370FBDCC9018029600ACD529CA9A4F62ACD2B5F928802F0D2665CA7D6CC013919E78A3800D3CF7794A8FC938280473057394AFF15099BA23CDD37A08400E2A5F7297F916C9F97F82D2DFA734BC600D4E3BC89CCBABCBE2B77D200412599244D4C0138C780120CC67E9D351C5AB4E1D4C981802980080CDB84E034C5767C60124F3BC984CD1E479201232C016100662D45089A00087C1084F12A724752BEFEA9C51500566759BF9BE6C5080217910CD00525B6350E8C00E9272200DCE4EF4C1DD003952F7059BCF675443005680103976997699795E830C02E4CBCE72EFC6A6218C88C9DF2F3351FCEF2D83CADB779F59A052801F2BAACDAE7F52A8190073937FE1D700439234DBB4F7374DC0CC804CF1006A0D47B8A4200F445865170401F8251662D100909401AB8803313217C680004320D43F871308D140C010E0069E7EDD1796AFC8255800052E20043E0F42A8B6400864258E51088010B85910A0F4ECE1DFE069C0229AE63D0B8DC6F82529403203305C00E1002C80AF5602908400A20240100852401E98400830021400D30029004B6100294008400B9D0023240061C000D19CACCD9005F694AEF6493D3F9948DEB3B4CC273FFD5E9AD85CFDFF6978B80050392AC3D98D796449BE304FE7F0C13CD716656BD0A6002A67E61A400F6E8029300B300B11480463D004C401889B1CA31800211162204679621200FCAC01791CF6B1AFCF2473DAC6BF3A9F1700016A3D90064D359B35D003430727A7DC464E6401594A57C93A0084CC56A662B8C00AA424989F2A9112
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.codingnagger.days;
2+
3+
import com.codingnagger.utils.InputLoader;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.CsvSource;
7+
8+
import java.util.Collections;
9+
import java.util.List;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
13+
public class Day16Test {
14+
private static final List<String> INPUT = InputLoader.LoadTest("day16.txt");
15+
private static final Day DAY = new Day16();
16+
17+
@ParameterizedTest
18+
@CsvSource({"D2FE28,6", "38006F45291200,9", "EE00D40C823060,14", "8A004A801A8002F478,16", "620080001611562C8802118E34,12", "C0015000016115A2E0802F182340,23", "A0016C880162017C3686B18A3D4780,31"})
19+
public void partOne_shoudlYieldCorrectResult(String input, String expectedResult) {
20+
String result = DAY.partOne(Collections.singletonList(input));
21+
22+
assertThat(result).isEqualTo(expectedResult);
23+
}
24+
25+
@ParameterizedTest
26+
@CsvSource({"D2FE28,110100101111111000101000", "38006F45291200,00111000000000000110111101000101001010010001001000000000"})
27+
public void convertHexaToBinaryString_shouldReturnExpectedBits(String input, String expectedResult) {
28+
assertThat(Day16.convertHexaToBinaryString(input)).isEqualTo(expectedResult);
29+
}
30+
31+
@ParameterizedTest
32+
@CsvSource({"C200B40A82,3", "04005AC33890,54", "880086C3E88112,7", "CE00C43D881120,9", "D8005AC2A8F0,1", "F600BC2D8F,0", "9C005AC2F8F0,0", "9C0141080250320F1802104A08,1",
33+
"D2FE28,2021","38006F45291200,1", "EE00D40C823060,3"})
34+
public void partTwo_shoudlYieldCorrectResult(String input, String expectedResult) {
35+
String result = DAY.partTwo(Collections.singletonList(input));
36+
37+
assertThat(result).isEqualTo(expectedResult);
38+
}
39+
}

src/test/resources/day16.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)