-
Notifications
You must be signed in to change notification settings - Fork 0
/
AoC2023_12.java
138 lines (123 loc) Β· 4.21 KB
/
AoC2023_12.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.github.pareronia.aoc.AssertUtils;
import com.github.pareronia.aoc.IntegerSequence.Range;
import com.github.pareronia.aoc.StringOps;
import com.github.pareronia.aoc.StringOps.StringSplit;
import com.github.pareronia.aoc.solution.Sample;
import com.github.pareronia.aoc.solution.Samples;
import com.github.pareronia.aoc.solution.SolutionBase;
public final class AoC2023_12
extends SolutionBase<List<String>, Long, Long> {
private static final char[] CHARS = {'.', '#'};
private final Map<Integer, Long> cache = new HashMap<>();
private AoC2023_12(final boolean debug) {
super(debug);
}
public static AoC2023_12 create() {
return new AoC2023_12(false);
}
public static AoC2023_12 createDebug() {
return new AoC2023_12(true);
}
@Override
protected List<String> parseInput(final List<String> inputs) {
return inputs;
}
private long count(
final String s,
final int[] counts,
final int s_idx,
final int c_idx,
final int idx
) {
if (s_idx == s.length()) {
if (c_idx == counts.length && idx == 0) {
return 1;
} else {
return 0;
}
}
if (idx == 0) {
int sum = 0;
for (int i = c_idx; i < counts.length; i++) {
sum += counts[i];
}
if (s.length() - s_idx < sum + counts.length - c_idx - 1) {
return 0;
}
}
final int key = s_idx << 16 | c_idx << 8 | idx;
if (this.cache.containsKey(key)) {
return this.cache.get(key);
}
long ans = 0;
final char[] nxts = s.charAt(s_idx) == '?' ? CHARS : new char[] { s.charAt(s_idx) };
for (final char nxt : nxts) {
if (nxt == '#') {
ans += count(s, counts, s_idx + 1, c_idx, idx + 1);
} else if (nxt == '.') {
if (idx > 0) {
if (c_idx < counts.length && counts[c_idx] == idx) {
ans += count(s, counts, s_idx + 1, c_idx + 1, 0);
}
} else {
ans += count(s, counts, s_idx + 1, c_idx, 0);
}
} else {
AssertUtils.unreachable();
}
}
this.cache.put(key, ans);
return ans;
}
@Override
public Long solvePart1(final List<String> input) {
long ans = 0;
for (final String line: input) {
this.cache.clear();
final StringSplit split = StringOps.splitOnce(line, " ");
final int[] counts = Arrays.stream(split.right().split(","))
.mapToInt(Integer::parseInt)
.toArray();
ans += count(split.left() + ".", counts, 0, 0, 0);
}
return ans;
}
@Override
public Long solvePart2(final List<String> input) {
long ans = 0;
for (final String line: input) {
this.cache.clear();
final StringSplit split = StringOps.splitOnce(line, " ");
final String s = String.join(
"?",
Range.range(5).intStream().mapToObj(i -> split.left()).toList()) + ".";
final int[] counts = Range.range(5).intStream()
.flatMap(i -> Arrays.stream(split.right().split(",")).mapToInt(Integer::parseInt))
.toArray();
ans += count(s, counts, 0, 0, 0);
}
return ans;
}
@Override
@Samples({
@Sample(method = "part1", input = TEST, expected = "21"),
@Sample(method = "part2", input = TEST, expected = "525152"),
})
public void samples() {
}
public static void main(final String[] args) throws Exception {
AoC2023_12.createDebug().run();
}
private static final String TEST = """
???.### 1,1,3
.??..??...?##. 1,1,3
?#?#?#?#?#?#?#? 1,3,1,6
????.#...#... 4,1,1
????.######..#####. 1,6,5
?###???????? 3,2,1
""";
}