Advent of Code 2023: Day 3: Gear Ratios⁠⁠

В начале была лень… Стойкое нежелание возиться с границами массивов. Оно, и только оно толкнуло меня на скользкую дорожку замены матрицы примитивов на List>.

Следующим шагом на пути окунания в пучины многословия – стало создание контейнеров для упаковки данных со “схемы двигателя”:

public record Coord(Integer row, Integer column){}; public record Cell(Coord coord, Integer codePoint){ Set<Coord> border() {return Set.of( new Coord(coord.row(), coord.column() - 1), // left new Coord(coord.row() - 1, coord.column() - 1), // top-left new Coord(coord.row() - 1, coord.column()), // top new Coord(coord.row() - 1, coord.column() + 1), // top-right new Coord(coord.row(), coord.column() + 1), // right new Coord(coord.row() + 1, coord.column() + 1), // bot-right new Coord(coord.row() + 1, coord.column()), // bottom new Coord(coord.row() + 1, coord.column() - 1) // bot-left );} }; public record Part(List<Cell> cells){ public Part { cells = List.copyOf(cells); } Set<Coord> border() { return cells.stream() .flatMap(c -> c.border().stream()) .filter(bCoord -> cells.stream() .noneMatch(c -> bCoord.equals(c.coord()))) .collect(Collectors.toSet()); } Integer value() { return Integer.parseInt(cells.stream() .map(c -> Character.toChars(c.codePoint())) .map(String::new).collect(Collectors.joining())); } };

У меня было три штуки рекордов, несколько методов с регулярно вычисляющей одно и то же логикой внутри них и россыпь операций по упаковке простого содержимого в сложные формы. Не то, чтобы всё это было нужно в решении задачи, но раз начал коллекционировать объекты, то иди в своём увлечении до конца.

static void day3(String puzzleInputUri) throws IOException, InterruptedException { Integer emptyCell = (int) '.'; Integer gearCell = (int) '*'; List<List<Integer>> scheme = client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()).body() .map(line -> line.chars().boxed().collect(Collectors.toCollection(ArrayList::new))) .peek(chars -> chars.addFirst(emptyCell)) .peek(chars -> chars.addLast(emptyCell)) .collect(Collectors.toCollection(ArrayList::new)); scheme.addFirst(Collections.nCopies(scheme.getFirst().size(), emptyCell)); scheme.addLast(Collections.nCopies(scheme.getFirst().size(), emptyCell)); List<Part> parts = new ArrayList<>(); List<Cell> gears = new ArrayList<>(); List<Cell> partDigit = new ArrayList<>(); boolean prevIsDigit = false; for (int row = 1; row < scheme.size() - 1; row++) { for (int column = 1; column < scheme.get(row).size() - 1; column++) { Integer cellValue = scheme.get(row).get(column); if (Character.isDigit(cellValue)) { partDigit.add(new Cell(new Coord(row, column), cellValue)); prevIsDigit = true; } else if (prevIsDigit) { parts.add(new Part(partDigit)); partDigit.clear(); prevIsDigit = false; } if (gearCell.equals(cellValue)) { gears.add(new Cell(new Coord(row, column), cellValue)); } } } var validParts = parts.stream() .filter(part -> part.border().stream().anyMatch( c -> !emptyCell.equals(scheme.get(c.row()).get(c.column())) )).toList(); var answer1 = validParts.stream() .mapToInt(part -> part.value()) .sum(); System.out.println(answer1); var answer2 = gears.stream() .map(gear -> Map.entry(gear, validParts.stream().filter(part -> part.border().contains(gear.coord())).toList() )) .filter(gearParts -> gearParts.getValue().size() == 2) .map(Map.Entry::getValue) .mapToInt(gearParts -> gearParts.getFirst().value() * gearParts.getLast().value()) .sum(); System.out.println(answer2); }

Это очень опасное предприятие закончилось благополучно! Длинная подготовка вылилась в достаточно короткие решения. Пришло удивительное, вселенское ощущение правильности всего того, что я делал.

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