Skip to content

Commit

Permalink
AoC 2023 Day 22 Part 2 - java
Browse files Browse the repository at this point in the history
  • Loading branch information
pareronia committed Dec 22, 2023
1 parent bc3e962 commit aa2ba61
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
| | 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 |
| ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| python3 | [](src/main/python/AoC2023_01.py) | [](src/main/python/AoC2023_02.py) | [](src/main/python/AoC2023_03.py) | [](src/main/python/AoC2023_04.py) | [](src/main/python/AoC2023_05.py) | [](src/main/python/AoC2023_06.py) | [](src/main/python/AoC2023_07.py) | [](src/main/python/AoC2023_08.py) | [](src/main/python/AoC2023_09.py) | [](src/main/python/AoC2023_10.py) | [](src/main/python/AoC2023_11.py) | [](src/main/python/AoC2023_12.py) | [](src/main/python/AoC2023_13.py) | [](src/main/python/AoC2023_14.py) | [](src/main/python/AoC2023_15.py) | [](src/main/python/AoC2023_16.py) | [](src/main/python/AoC2023_17.py) | [](src/main/python/AoC2023_18.py) | [](src/main/python/AoC2023_19.py) | [](src/main/python/AoC2023_20.py) | [](src/main/python/AoC2023_21.py) | | | | |
| java | [](src/main/java/AoC2023_01.java) | [](src/main/java/AoC2023_02.java) | [](src/main/java/AoC2023_03.java) | [](src/main/java/AoC2023_04.java) | [](src/main/java/AoC2023_05.java) | [](src/main/java/AoC2023_06.java) | [](src/main/java/AoC2023_07.java) | [](src/main/java/AoC2023_08.java) | [](src/main/java/AoC2023_09.java) | [](src/main/java/AoC2023_10.java) | [](src/main/java/AoC2023_11.java) | [](src/main/java/AoC2023_12.java) | [](src/main/java/AoC2023_13.java) | [](src/main/java/AoC2023_14.java) | [](src/main/java/AoC2023_15.java) | [](src/main/java/AoC2023_16.java) | [](src/main/java/AoC2023_17.java) | [](src/main/java/AoC2023_18.java) | | [](src/main/java/AoC2023_20.java) | | | | | |
| java | [](src/main/java/AoC2023_01.java) | [](src/main/java/AoC2023_02.java) | [](src/main/java/AoC2023_03.java) | [](src/main/java/AoC2023_04.java) | [](src/main/java/AoC2023_05.java) | [](src/main/java/AoC2023_06.java) | [](src/main/java/AoC2023_07.java) | [](src/main/java/AoC2023_08.java) | [](src/main/java/AoC2023_09.java) | [](src/main/java/AoC2023_10.java) | [](src/main/java/AoC2023_11.java) | [](src/main/java/AoC2023_12.java) | [](src/main/java/AoC2023_13.java) | [](src/main/java/AoC2023_14.java) | [](src/main/java/AoC2023_15.java) | [](src/main/java/AoC2023_16.java) | [](src/main/java/AoC2023_17.java) | [](src/main/java/AoC2023_18.java) | | [](src/main/java/AoC2023_20.java) | | [](src/main/java/AoC2023_22.java) | | | |
| rust | [](src/main/rust/AoC2023_01/src/main.rs) | [](src/main/rust/AoC2023_02/src/main.rs) | [](src/main/rust/AoC2023_03/src/main.rs) | [](src/main/rust/AoC2023_04/src/main.rs) | | [](src/main/rust/AoC2023_06/src/main.rs) | [](src/main/rust/AoC2023_07/src/main.rs) | [](src/main/rust/AoC2023_08/src/main.rs) | [](src/main/rust/AoC2023_09/src/main.rs) | | | | | | [](src/main/rust/AoC2023_15/src/main.rs) | [](src/main/rust/AoC2023_16/src/main.rs) | [](src/main/rust/AoC2023_17/src/main.rs) | [](src/main/rust/AoC2023_18/src/main.rs) | [](src/main/rust/AoC2023_19/src/main.rs) | | [](src/main/rust/AoC2023_21/src/main.rs) | | | | |
<!-- @END:ImplementationsTable:2023@ -->

Expand Down
159 changes: 100 additions & 59 deletions src/main/java/AoC2023_22.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toSet;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.github.pareronia.aoc.MutableBoolean;
import com.github.pareronia.aoc.StringOps;
import com.github.pareronia.aoc.StringOps.StringSplit;
import com.github.pareronia.aoc.geometry.Draw;
import com.github.pareronia.aoc.geometry.Position;
import com.github.pareronia.aoc.geometry3d.Cuboid;
import com.github.pareronia.aoc.solution.Sample;
import com.github.pareronia.aoc.solution.Samples;
import com.github.pareronia.aoc.solution.SolutionBase;

import lombok.RequiredArgsConstructor;

public final class AoC2023_22
extends SolutionBase<List<Cuboid>, Integer, Integer> {
extends SolutionBase<AoC2023_22.Stack, Integer, Integer> {

private AoC2023_22(final boolean debug) {
super(debug);
Expand All @@ -37,40 +36,18 @@ public static AoC2023_22 createDebug() {
}

@Override
protected List<Cuboid> parseInput(final List<String> inputs) {
final ArrayList<Cuboid> bricks = new ArrayList<>();
for (final String line : inputs) {
final StringSplit split = StringOps.splitOnce(line, "~");
final String[] xyz1 = split.left().split(",");
final String[] xyz2 = split.right().split(",");
bricks.add(new Cuboid(
Integer.parseInt(xyz1[0]),
Integer.parseInt(xyz2[0]),
Integer.parseInt(xyz1[1]),
Integer.parseInt(xyz2[1]),
Integer.parseInt(xyz1[2]),
Integer.parseInt(xyz2[2])
));
}
return bricks;
protected Stack parseInput(final List<String> inputs) {
return Stack.fromInput(inputs);
}

@Override
public Integer solvePart1(final List<Cuboid> bricks) {
final Stack stack = new Stack(bricks);
stack.sort();
stack.display().forEach(this::log);
log("");
Draw.draw(stack.getViewY(), '#', '.').forEach(this::log);
stack.stack();
stack.sort();
log("");
Draw.draw(stack.getViewY(), '#', '.').forEach(this::log);
public Integer solvePart1(final Stack stack) {
// stack.display().forEach(this::log);
// log("");
// Draw.draw(stack.getViewY(), '#', '.').forEach(this::log);
final Map<Integer, List<Cuboid>> bricksByZ1 = stack.getBricksByZ1();
final Map<Integer, List<Cuboid>> bricksByZ2 = stack.getBricksByZ2();
int ans = 0;
final Map<Integer, List<Cuboid>> bricksByZ1 = bricks.stream()
.collect(groupingBy(Cuboid::getZ1));
final Map<Integer, List<Cuboid>> bricksByZ2 = bricks.stream()
.collect(groupingBy(Cuboid::getZ2));
for (final int z : bricksByZ2.keySet()) {
for (final Cuboid brick : bricksByZ2.get(z)) {
final List<Cuboid> supportees = bricksByZ1.getOrDefault(brick.getZ2() + 1, List.of()).stream()
Expand All @@ -80,7 +57,6 @@ public Integer solvePart1(final List<Cuboid> bricks) {
ans++;
continue;
}
// System.out.println("hey");
boolean onlySupporter = false;
for (final Cuboid supportee : supportees) {
if (bricksByZ2.get(supportee.getZ1() - 1).stream()
Expand All @@ -100,14 +76,51 @@ public Integer solvePart1(final List<Cuboid> bricks) {
}

@Override
public Integer solvePart2(final List<Cuboid> bricks) {
return 0;
public Integer solvePart2(final Stack stack) {
final Map<Integer, List<Cuboid>> bricksByZ1 = stack.getBricksByZ1();
final Map<Integer, List<Cuboid>> bricksByZ2 = stack.getBricksByZ2();
final Map<Cuboid, Set<Cuboid>> supportees = new HashMap<>();
final Map<Cuboid, Set<Cuboid>> supporters = new HashMap<>();
for (final Cuboid brick : stack.getBricks()) {
supportees.put(brick, bricksByZ1.getOrDefault(brick.getZ2() + 1, List.of()).stream()
.filter(b -> Cuboid.overlapX(b, brick) && Cuboid.overlapY(b, brick))
.collect(toSet()));
log(() -> "%s supportees: %s".formatted(Stack.displayBrick(brick), Stack.displayBricks(supportees.get(brick))));
supporters.put(brick, bricksByZ2.getOrDefault(brick.getZ1() - 1, List.of()).stream()
.filter(b -> Cuboid.overlapX(b, brick) && Cuboid.overlapY(b, brick))
.collect(toSet()));
log(() -> "%s supporters: %s".formatted(Stack.displayBrick(brick), Stack.displayBricks(supporters.get(brick))));
}
int ans = 0;
for (final Cuboid brick : stack.getBricks()) {
final Deque<Cuboid> q = new ArrayDeque<>();
final Set<Cuboid> falling = new HashSet<>();
falling.add(brick);
q.add(brick);
while (!q.isEmpty()) {
final Cuboid b = q.poll();
log(() -> Stack.displayBrick(b));
for (final Cuboid spee : supportees.get(b)) {
final Set<Cuboid> sprs = supporters.get(spee);
if (!sprs.isEmpty() && sprs.stream().allMatch(s -> falling.contains(s))) {
if (!falling.contains(spee)) {
q.add(spee);
}
falling.add(spee);
}
}
log(() -> "Falling: %s".formatted(Stack.displayBricks(falling)));
}
falling.remove(brick);
ans += falling.size();
}
return ans;
}

@Override
@Samples({
@Sample(method = "part1", input = TEST, expected = "5"),
// @Sample(method = "part2", input = TEST, expected = "TODO"),
@Sample(method = "part2", input = TEST, expected = "7"),
})
public void samples() {
}
Expand All @@ -116,18 +129,53 @@ public static void main(final String[] args) throws Exception {
AoC2023_22.create().run();
}

@RequiredArgsConstructor
private final class Stack {
static final class Stack {
private final List<Cuboid> bricks;

protected Stack(final List<Cuboid> bricks) {
this.bricks = bricks;
}

public void sort() {
Collections.sort(bricks,
comparing(Cuboid::getZ1)
.thenComparing(comparing(Cuboid::getY1))
.thenComparing(comparing(Cuboid::getX1))
);
public List<Cuboid> getBricks() {
return bricks;
}

public Map<Integer, List<Cuboid>> getBricksByZ1() {
return bricks.stream().collect(groupingBy(Cuboid::getZ1));
}

public Map<Integer, List<Cuboid>> getBricksByZ2() {
return bricks.stream().collect(groupingBy(Cuboid::getZ2));
}

public static Stack fromInput(final List<String> inputs) {
final List<Cuboid> bricks = new ArrayList<>();
for (final String line : inputs) {
final StringSplit split = StringOps.splitOnce(line, "~");
final String[] xyz1 = split.left().split(",");
final String[] xyz2 = split.right().split(",");
bricks.add(Cuboid.of(
Integer.parseInt(xyz1[0]),
Integer.parseInt(xyz2[0]),
Integer.parseInt(xyz1[1]),
Integer.parseInt(xyz2[1]),
Integer.parseInt(xyz1[2]),
Integer.parseInt(xyz2[2])
));
}
final Stack stack = new Stack(bricks);
stack.stack();
return stack;
}

// public void sort() {
// Collections.sort(bricks,
// comparing(Cuboid::getZ1)
// .thenComparing(comparing(Cuboid::getY1))
// .thenComparing(comparing(Cuboid::getX1))
// );
// }
//
public Set<Position> getViewY() {
return bricks.stream()
.flatMap(Cuboid::positions)
Expand All @@ -143,7 +191,7 @@ private static Cuboid moveToZ(final Cuboid block, final int dz) {
);
}

public boolean overlapsXY(final Collection<Cuboid> cuboids,final Cuboid brick) {
private boolean overlapsXY(final Collection<Cuboid> cuboids,final Cuboid brick) {
return cuboids.stream()
.anyMatch(c -> Cuboid.overlapX(c, brick) && Cuboid.overlapY(c, brick));
}
Expand All @@ -160,14 +208,12 @@ public void stack() {
.sorted()
.filter(z -> z > 1)
.forEach(z -> {
// log("z: %d".formatted(z));
final List<Cuboid> list = new ArrayList<>(bricksByZ1.get(z));
for (final Cuboid brick : list) {
if (!overlapsXY(bricksByZ2.getOrDefault(z - 1, List.of()), brick)) {
bricksByZ1.getOrDefault(brick.getZ1(), new ArrayList<>()).remove(brick);
bricksByZ2.getOrDefault(brick.getZ2(), new ArrayList<>()).remove(brick);
final Cuboid m = moveToZ(brick, -1);
// log("move: %s -> %s".formatted(displayBrick(brick), displayBrick(m)));
bricksByZ1.computeIfAbsent(m.getZ1(), k -> new ArrayList<>()).add(m);
bricksByZ2.computeIfAbsent(m.getZ2(), k -> new ArrayList<>()).add(m);
moved.setTrue();
Expand All @@ -180,26 +226,21 @@ public void stack() {
}

public List<String> display() {
return Stack.displayBricks(bricks);
return displayBricks(bricks);
}

private static List<String> displayBricks(final Collection<Cuboid> bricks) {
public static List<String> displayBricks(final Collection<Cuboid> bricks) {
return bricks.stream()
.map(Stack::displayBrick)
.toList();
}

private static String displayBrick(final Cuboid brick) {
public static String displayBrick(final Cuboid brick) {
return "%d,%d,%d->%d,%d,%d".formatted(
brick.getX1(), brick.getY1(), brick.getZ1(),
brick.getX2(), brick.getY2(), brick.getZ2()
);
}

@SuppressWarnings("unused")
private void log(final Object obj) {
AoC2023_22.this.log(obj);
}
}

private static final String TEST = """
Expand Down

0 comments on commit aa2ba61

Please sign in to comment.