Skip to content

Commit 84d347b

Browse files
committed
Day 9
1 parent 721dc53 commit 84d347b

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

src/test/java/com/macasaet/Day09.java

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package com.macasaet;
2+
3+
import java.util.*;
4+
import java.util.function.Function;
5+
import java.util.stream.Collectors;
6+
import java.util.stream.IntStream;
7+
import java.util.stream.Stream;
8+
import java.util.stream.StreamSupport;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
/**
13+
* --- Day 9: Smoke Basin ---
14+
*/
15+
public class Day09 {
16+
17+
protected Stream<String> getInput() {
18+
return StreamSupport
19+
.stream(new LineSpliterator("day-09.txt"),
20+
false);
21+
}
22+
23+
public HeightMap getHeightMap() {
24+
final var list = getInput().map(line -> {
25+
final var chars = line.toCharArray();
26+
final var ints = new int[chars.length];
27+
for (int i = chars.length; --i >= 0; ints[i] = chars[i] - '0') ;
28+
return ints;
29+
}).collect(Collectors.toList());
30+
final int[][] grid = new int[list.size()][];
31+
for (int i = list.size(); --i >= 0; grid[i] = list.get(i)) ;
32+
return new HeightMap(grid);
33+
}
34+
35+
/**
36+
* A height map of the floor of the nearby caves generated by the submarine
37+
*/
38+
public record HeightMap(int[][] grid) { // FIXME use bytes
39+
40+
public Stream<Point> points() {
41+
return IntStream.range(0, grid().length)
42+
.boxed()
43+
.flatMap(i -> IntStream.range(0, grid()[i].length)
44+
.mapToObj(j -> new Point(i, j)));
45+
}
46+
47+
/**
48+
* A location on the floor of a nearby cave
49+
*/
50+
public class Point {
51+
final int x;
52+
final int y;
53+
54+
public Point(final int x, final int y) {
55+
this.x = x;
56+
this.y = y;
57+
}
58+
59+
public int x() {
60+
return this.x;
61+
}
62+
63+
public int y() {
64+
return this.y;
65+
}
66+
67+
public int getBasinSize() {
68+
return getBasinPoints().size();
69+
}
70+
71+
/**
72+
* Identify all the higher points that are also part of the same basin, assuming this location is part of a
73+
* basin.
74+
*
75+
* @return all the higher points, if any, that are part of the same basin.
76+
*/
77+
public Set<Point> getBasinPoints() {
78+
if (getHeight() >= 9) {
79+
return Collections.emptySet();
80+
}
81+
final var result = new HashSet<Point>();
82+
result.add(this);
83+
final Function<Point, Stream<Point>> basinPointRetriever = neighbour -> {
84+
if (neighbour.getHeight() >= 9 || neighbour.getHeight() <= getHeight() || result.contains(neighbour)) {
85+
return Stream.empty();
86+
}
87+
return neighbour.getBasinPoints().stream();
88+
};
89+
above().stream().flatMap(basinPointRetriever).forEach(result::add);
90+
below().stream().flatMap(basinPointRetriever).forEach(result::add);
91+
left().stream().flatMap(basinPointRetriever).forEach(result::add);
92+
right().stream().flatMap(basinPointRetriever).forEach(result::add);
93+
return Collections.unmodifiableSet(result);
94+
}
95+
96+
/**
97+
* @return true if and only if this location is lower than all of its adjacent locations (up to four,
98+
* diagonals do not count)
99+
*/
100+
public boolean isLowPoint() {
101+
final var compareTo = new ArrayList<Point>(4);
102+
above().ifPresent(compareTo::add);
103+
below().ifPresent(compareTo::add);
104+
left().ifPresent(compareTo::add);
105+
right().ifPresent(compareTo::add);
106+
return compareTo.stream().allMatch(neighbour -> neighbour.getHeight() > getHeight());
107+
}
108+
109+
/**
110+
* @return an assessment of the risk from smoke flowing through the cave
111+
*/
112+
public int getRiskLevel() {
113+
return getHeight() + 1;
114+
}
115+
116+
/**
117+
* @return the height of this particular location, from 0-9
118+
*/
119+
public int getHeight() {
120+
return grid()[x()][y()];
121+
}
122+
123+
public Optional<Point> above() {
124+
return x() > 0 ? Optional.of(new Point(x() - 1, y())) : Optional.empty();
125+
}
126+
127+
public Optional<Point> below() {
128+
return x() < grid().length - 1 ? Optional.of(new Point(x() + 1, y())) : Optional.empty();
129+
}
130+
131+
public Optional<Point> left() {
132+
return y() > 0 ? Optional.of(new Point(x(), y() - 1)) : Optional.empty();
133+
}
134+
135+
public Optional<Point> right() {
136+
return y() < grid()[x()].length - 1 ? Optional.of(new Point(x(), y() + 1)) : Optional.empty();
137+
}
138+
139+
public int hashCode() {
140+
return Objects.hash(x(), y());
141+
}
142+
143+
public boolean equals(final Object o) {
144+
try {
145+
final Point other = (Point) o;
146+
return this.x() == other.x() && this.y() == other.y();
147+
} catch (final ClassCastException cce) {
148+
return false;
149+
}
150+
}
151+
}
152+
153+
}
154+
155+
@Test
156+
public final void part1() {
157+
final var map = getHeightMap();
158+
final int sum = map.points()
159+
.filter(HeightMap.Point::isLowPoint)
160+
.mapToInt(HeightMap.Point::getRiskLevel)
161+
.sum();
162+
System.out.println("Part 1: " + sum);
163+
}
164+
165+
@Test
166+
public final void part2() {
167+
final var map = getHeightMap();
168+
final var basinSizes = map.points()
169+
.filter(HeightMap.Point::isLowPoint)
170+
.mapToInt(HeightMap.Point::getBasinSize)
171+
.collect(() -> new TreeSet<Integer>(Comparator.reverseOrder()), SortedSet::add, SortedSet::addAll);
172+
final var iterator = basinSizes.iterator();
173+
final var result = iterator.next() * iterator.next() * iterator.next();
174+
System.out.println("Part 2: " + result);
175+
}
176+
177+
}

src/test/resources/sample/day-09.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2199943210
2+
3987894921
3+
9856789892
4+
8767896789
5+
9899965678

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