Advent of Code 2022: Day 18

Загадка восемнадцатого дня, на мой вкус, могла бы служить образцом для многих предыдущих загадок.

Минимум возни с парсингом ввода и кодированием очередных обходов графа. Максимум размышлений над поисками решения.

В то же время, само решение — не переусложнённое. Похожей по соотношению интерес/сложность для меня была задачка с обработкой сигналов.

Решение тут получилось компактным

static void day18(String puzzleInputUri) throws IOException, InterruptedException { List<Point> points = client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()) .body() .map(line -> line.split(",")) .map(xyz -> new Point(Integer.parseInt(xyz[0]), Integer.parseInt(xyz[1]), Integer.parseInt(xyz[2]))) .collect(Collectors.toUnmodifiableList()); long area1 = area(points); System.out.println("Answer 1: " + area1); List<Point> voids = findVoids(new Point(0, 0, 0), makeCube(points)); System.out.println("Answer 2: " + (area1 - area(voids))); }

Но только за счет раздутой подготовки

enum Matter { AIR, STEAM, LAVA } static class Point { public final int x, y, z; private final Set<BiFunction<Point, Integer, Point>> makeNeighbor = Set.of( (p, add) -> new Point(p.x + add, p.y, p.z), (p, add) -> new Point(p.x, p.y + add, p.z), (p, add) -> new Point(p.x, p.y, p.z + add) ); public Point(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } public boolean isNeighbor(Point c) { return Math.abs(this.x - c.x) + Math.abs(this.y - c.y) + Math.abs(this.z - c.z) == 1; } public List<Point> makeNeighbours() { return makeNeighbor.stream() .flatMap(f -> IntStream.of(-1, 1).mapToObj(i -> f.apply(this, i))) .collect(Collectors.toList()); } } static List<Point> findVoids(Point start, int[][][] cube) { Deque<Point> stack = new ArrayDeque<>(); Set<Point> visited = new HashSet<>(); stack.push(start); while (!stack.isEmpty()) { Point cur = stack.pop(); visited.add(cur); if (cube[cur.x][cur.y][cur.z] == Matter.AIR.ordinal()) { cube[cur.x][cur.y][cur.z] = Matter.STEAM.ordinal(); for (Point neighbour : cur.makeNeighbours()) { if (!visited.contains(neighbour) && isBelongCube(neighbour, cube)) { stack.push(neighbour); } } } } return IntStream.range(0, cube.length) .mapToObj(x -> IntStream.range(0, cube[x].length) .mapToObj(y -> IntStream.range(0, cube[x][y].length) .mapToObj(z -> new Point(x, y, z)) ) ) .flatMap(it -> it.flatMap(Function.identity())) .filter(p -> cube[p.x][p.y][p.z] == Matter.AIR.ordinal()) .collect(Collectors.toList()); } static boolean isBelongCube(Point p, final int[][][] cube) { return (p.x >= 0 && p.y >= 0 && p.z >= 0) && (p.x < cube.length && p.y < cube[0].length && p.z < cube[0][0].length); } static int[][][] makeCube(List<Point> points) { int maxCoord = points.stream() .flatMapToInt(p -> IntStream.of(p.x, p.y, p.z)) .summaryStatistics().getMax(); int[][][] cube = new int[maxCoord + 1][maxCoord + 1][maxCoord + 1]; points.forEach(p -> cube[p.x][p.y][p.z] = Matter.LAVA.ordinal()); return cube; } static long area(List<Point> points) { return (points.size() * 6L) - IntStream.range(0, points.size()) .mapToObj(i -> IntStream.range(i, points.size()) .mapToObj(j -> points.get(i).isNeighbor(points.get(j))) ) .flatMap(b -> b) .filter(Boolean.TRUE::equals) .count() * 2; }

Возможно, для постоянно имеющих дело играми/графикой (и подобным), эта задачка будет выглядеть скучной. Мне же она понравилась (и с капелькой стримоза!).

Начать дискуссию