Skip to content

Commit b971ced

Browse files
committed
Day 21 solution
1 parent e01e3b5 commit b971ced

File tree

2 files changed

+70
-87
lines changed

2 files changed

+70
-87
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.sbaars.adventofcode.util;
22

33
import java.util.ArrayList;
4+
import java.util.Collections;
45
import java.util.List;
56
import java.util.Optional;
67
import java.util.function.ToLongFunction;
8+
import java.util.stream.Collectors;
79
import java.util.stream.Stream;
810

911
import static com.sbaars.adventofcode.util.AOCUtils.connectedPairs;
10-
import static java.util.Collections.indexOfSubList;
11-
import static java.util.stream.Collectors.toCollection;
1212

1313
/**
1414
* The solver looks for patterns in an infinite stream of numeric data, to find the result further in the repetition.
@@ -30,37 +30,32 @@ public static <A> long solve(Stream<A> s, ToLongFunction<A> res, long target, in
3030
}
3131

3232
private static Optional<Long> findPattern(List<Long> nums, long target, int minSize) {
33-
if (nums.size() < minSize) {
34-
return Optional.empty();
35-
}
36-
return findDevelopingDeltaPattern(nums, target, minSize, 2);
37-
// return findCycleDeltaPattern(nums, target, minSize)
38-
// .or(() -> findDevelopingDeltaPattern(nums, target, minSize, 1));
33+
return findCycleDeltaPattern(nums, target, minSize)
34+
.or(() -> findDevelopingDeltaPattern(nums, target, minSize));
3935
}
4036

41-
// private static Optional<Long> findCycleDeltaPattern(List<Long> nums, long target, int minSize) {
42-
// List<Long> deltas = connectedPairs(nums).map(p -> p.b() - p.a()).collect(toCollection(ArrayList::new));
43-
// deltas.add(0, nums.get(0)); // baseline delta
44-
// target++; // Adjust target to cover baseline
45-
// if (deltas.size() >= minSize + 1 && deltas.subList(0, minSize).equals(deltas.subList(deltas.size() - minSize, deltas.size()))) {
46-
// long deltaPerRepetition = deltas.subList(0, deltas.size() - minSize).stream().mapToLong(e -> e).sum();
47-
// int elementsPerRepetition = deltas.size() - minSize;
48-
// long timesApplied = target / elementsPerRepetition;
49-
// int remainder = Math.toIntExact(target % elementsPerRepetition);
50-
// long applyRemainder = nums.subList(0, remainder).stream().mapToLong(e -> e).sum();
51-
// return Optional.of((deltaPerRepetition * timesApplied) + applyRemainder);
52-
// }
53-
// return Optional.empty();
54-
// }
37+
private static Optional<Long> findCycleDeltaPattern(List<Long> nums, long target, int minSize) {
38+
List<Long> deltas = connectedPairs(nums).map(p -> p.b() - p.a()).collect(Collectors.toCollection(ArrayList::new));
39+
deltas.add(0, nums.get(0)); // baseline delta
40+
target++; // Adjust target to cover baseline
41+
if (deltas.size() >= minSize + 1 && deltas.subList(0, minSize).equals(deltas.subList(deltas.size() - minSize, deltas.size()))) {
42+
long deltaPerRepetition = deltas.subList(0, deltas.size() - minSize).stream().mapToLong(e -> e).sum();
43+
int elementsPerRepetition = deltas.size() - minSize;
44+
long timesApplied = target / elementsPerRepetition;
45+
int remainder = Math.toIntExact(target % elementsPerRepetition);
46+
long applyRemainder = nums.subList(0, remainder).stream().mapToLong(e -> e).sum();
47+
return Optional.of((deltaPerRepetition * timesApplied) + applyRemainder);
48+
}
49+
return Optional.empty();
50+
}
5551

56-
private static Optional<Long> findDevelopingDeltaPattern(List<Long> nums, long target, int minSize, int level) {
57-
List<Long> deltas = deltaAtLevel(nums, level);
58-
target++;
52+
private static Optional<Long> findDevelopingDeltaPattern(List<Long> nums, long target, int minSize) {
53+
List<Long> deltas = connectedPairs(nums).map(p -> p.b() - p.a()).collect(Collectors.toCollection(ArrayList::new));
54+
deltas.add(0, nums.get(0)); // baseline delta
55+
target++; // Adjust target to cover baseline
5956
if (deltas.size() >= minSize * 2) {
60-
System.out.println(deltas.get(deltas.size() - 1));
61-
int subListIndex = indexOfSubList(deltas, deltas.subList(deltas.size() - minSize, deltas.size()));
57+
int subListIndex = Collections.indexOfSubList(deltas, deltas.subList(deltas.size() - minSize, deltas.size()));
6258
if (subListIndex < deltas.size() - (minSize * 2) + 1) {
63-
System.out.println("Found pattern");
6459
List<Long> repeating = deltas.subList(subListIndex, deltas.size() - minSize);
6560
long deltaPerRepetition = repeating.stream().mapToLong(e -> e).sum();
6661
int elementsPerRepetition = repeating.size();
@@ -74,16 +69,4 @@ private static Optional<Long> findDevelopingDeltaPattern(List<Long> nums, long t
7469
}
7570
return Optional.empty();
7671
}
77-
78-
private static List<Long> deltaAtLevel(List<Long> nums, int level) {
79-
List<Long> deltas = nums;
80-
for (int i = 0; i < level; i++) {
81-
deltas = connectedPairs(deltas).map(p -> p.b() - p.a()).collect(toCollection(ArrayList::new));
82-
if (i == 0) {
83-
deltas.add(0, nums.get(0));
84-
}
85-
}
86-
return deltas;
87-
}
88-
8972
}
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
package com.sbaars.adventofcode.year23.days;
22

33
import com.sbaars.adventofcode.common.Builder;
4-
import com.sbaars.adventofcode.common.Pair;
54
import com.sbaars.adventofcode.common.grid.InfiniteGrid;
65
import com.sbaars.adventofcode.common.location.Loc;
7-
import com.sbaars.adventofcode.util.Solver;
86
import com.sbaars.adventofcode.year23.Day2023;
97

10-
import java.util.HashSet;
11-
import java.util.List;
12-
import java.util.Set;
13-
import java.util.stream.Stream;
8+
import java.util.*;
149

1510
import static com.sbaars.adventofcode.common.Direction.four;
1611

@@ -25,7 +20,6 @@ public static void main(String[] args) {
2520

2621
@Override
2722
public Object part1() {
28-
// this.example = 1;
2923
var grid = new InfiniteGrid(dayGrid());
3024
Builder<Set<Loc>> places = new Builder<>(HashSet::new);
3125
places.get().add(grid.findAll('S').findAny().get());
@@ -38,48 +32,54 @@ public Object part1() {
3832

3933
@Override
4034
public Object part2() {
41-
var grid = new InfiniteGrid(dayGrid());
42-
Loc start = grid.findAll('S').findAny().get();
43-
grid.repeat(3);
44-
// System.out.println(grid);
45-
// grid = new InfiniteGrid(grid.grid);
46-
// grid.repeat(1);
47-
// System.out.println(grid);
48-
// Builder<Set<Loc>> places = new Builder<>(HashSet::new);
49-
// places.get().add(start);
50-
// for (int i = 0; i < 10000; i++) {
51-
// places.get().stream().flatMap(l -> four().map(d -> d.move(l))).peek(l -> {
52-
// if (!grid.contains(l)) {
53-
// System.out.println("DIE");
54-
// throw new IllegalStateException();
55-
// }
56-
// }).filter(l -> grid.getChar(l) != '#').forEach(places.getNew()::add);
57-
// places.refresh();
58-
// System.out.println(places.get().size());
59-
// }
60-
// return places.get().size();
61-
return Solver.solve(Stream.iterate(new Pair<>(grid, new HashSet<>(List.of(start))), this::doTurn2), p -> p.b().size(), 26501365L);
62-
}
63-
64-
int i = 1;
35+
char[][] grid = dayGrid();
36+
var infGrid = new InfiniteGrid(grid);
37+
Loc start = infGrid.findAll('S').findAny().get();
6538

66-
public Pair<InfiniteGrid, Set<Loc>> doTurn(Pair<InfiniteGrid, Set<Loc>> places) {
67-
var set = new HashSet<Loc>();
68-
places.b().stream().flatMap(l -> four().map(d -> d.move(l))).filter(l -> !places.a().contains(l) || places.a().getChar(l) != '#').forEach(set::add);
69-
System.out.println(set.size());
70-
i++;
71-
return new Pair<>(places.a(), set);
72-
}
39+
// Core algorithm by abnew123: https://github.com/abnew123/aoc2023/blob/main/src/solutions/Day21.java
40+
Map<Loc, Integer> distances = new HashMap<>();
41+
Builder<Set<Loc>> places = new Builder<>(HashSet::new);
42+
places.get().add(start);
43+
distances.put(start, 0);
44+
List<Long> totals = new ArrayList<>();
45+
List<Long> deltas = new ArrayList<>();
46+
List<Long> deltaDeltas = new ArrayList<>();
47+
long totalReached = 0;
48+
for (int i = 1; ; i++) {
49+
int finalIndex = i;
50+
places.get().stream().flatMap(l -> four().map(d -> d.move(l))).forEach(l -> {
51+
if (distances.get(l) == null) {
52+
if (grid[((l.intX() % grid.length) + grid.length) % grid.length][((l.intY() % grid.length) + grid.length) % grid.length] != '#') {
53+
places.getNew().add(l);
54+
distances.put(l, finalIndex);
55+
}
56+
}
57+
});
58+
if (i % 2 == 1) {
59+
totalReached += places.getNew().size();
60+
if (i % 262 == 65) {
61+
totals.add(totalReached);
62+
int currTotals = totals.size();
63+
if (currTotals > 1) {
64+
deltas.add(totals.get(currTotals - 1) - totals.get(currTotals - 2));
65+
}
66+
int currDeltas = deltas.size();
67+
if (currDeltas > 1) {
68+
deltaDeltas.add(deltas.get(currDeltas - 1) - deltas.get(currDeltas - 2));
69+
}
70+
if (deltaDeltas.size() > 1) {
71+
long neededLoopCount = 26501365 / 262 - 1;
72+
long currentLoopCount = i / 262 - 1;
73+
long deltaLoopCount = neededLoopCount - currentLoopCount;
74+
long deltaLoopCountTriangular = (neededLoopCount * (neededLoopCount + 1)) / 2 - (currentLoopCount * (currentLoopCount + 1)) / 2;
75+
long deltaDelta = deltaDeltas.get(deltaDeltas.size() - 1);
76+
long initialDelta = deltas.get(0);
77+
return deltaDelta * deltaLoopCountTriangular + initialDelta * deltaLoopCount + totalReached;
78+
}
79+
}
7380

74-
public Pair<InfiniteGrid, Set<Loc>> doTurn2(Pair<InfiniteGrid, Set<Loc>> places) {
75-
var set = new HashSet<Loc>();
76-
places.b().stream().flatMap(l -> four().map(d -> d.move(l))).filter(l -> places.a().getChar(l) != '#').forEach(set::add);
77-
if (places.b().stream().anyMatch(l -> !places.a().contains(l))) {
78-
System.out.println("DIE");
79-
throw new IllegalStateException();
81+
}
82+
places.refresh();
8083
}
81-
System.out.println(set.size());
82-
i++;
83-
return new Pair<>(places.a(), set);
8484
}
8585
}

0 commit comments

Comments
 (0)