Вариация на тему змейки — это любопытно. Задачка решилась бы быстро, если бы не моя невнимательность.
Проклятая невнимательность! Она стоила мне пары часов бесплодных поисков ошибок в формулах перемещения узла.
К счастью, решение второй части не потребовало каких-то кардинальных изменений — просто больше узлов, больше хвостов. Но, сколь веревочке ни виться, — ответ будет найден!
Для начала — сделал узелки — «головы» и «хвосты» (и это я не про самогоноварение сейчас).
class RopeKnot {
public Set<List<Integer>> visited = new HashSet<>();
public int x;
public int y;
}
class Head extends RopeKnot {
public void doStep(String direction) {
if ("R".equals(direction)) this.x++;
if ("L".equals(direction)) this.x--;
if ("U".equals(direction)) this.y++;
if ("D".equals(direction)) this.y--;
}
}
class Tail extends RopeKnot {
private final RopeKnot head;
public Tail(RopeKnot head) {
this.head = head;
}
public void doFollow() {
int dX = head.x - this.x;
int dY = head.y - this.y;
if (Math.abs(dX) == 2 && dY == 0) {
this.x += dX > 0 ? 1 : -1;
} else if (Math.abs(dY) == 2 && dX == 0) {
this.y += dY > 0 ? 1 : -1;
} else if (Math.sqrt(Math.pow(dX, 2) + Math.pow(dY, 2)) > 2d) {
this.x += dX > 0 ? 1 : -1;
this.y += dY > 0 ? 1 : -1;
}
visited.add(List.of(this.x, this.y));
}
}
Вот где здесь можно ошибиться? Инкремент, декремент, три вида перемещения — положительно — негде! Однако — именно здесь я и пытался безуспешно найти сбой.
Сам алгоритм плетения узлов тоже не поражает сложностью:
static void day9(String puzzleInputUri) throws IOException, InterruptedException {
Head h = new Head();
Tail t1 = new Tail(h);
List<Tail> knots = new ArrayList<>(List.of(t1));
for (int i = 1; i < 9; i++) {
knots.add(new Tail(knots.get(i-1)));
}
client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines()).body()
.map(line -> line.split(" "))
.forEachOrdered(command -> {
for (int i = 0; i < Integer.parseInt(command[1]); i++) {
h.doStep(command[0]);
knots.forEach(tail -> tail.doFollow());
}
});
System.out.println(knots.get(0).visited.size());
System.out.println(knots.get(knots.size() - 1).visited.size());
}
Но именно в нём крылась досадная ошибка! Парсинг количества перемещений я скопипастил с решения восьмого дня, и он представлял собой такую конструкцию: command[1].charAt(0) - '0'
. Всё это прекрасно работало на тестовом примере и ни в какую не хотело выдавать верный ответ на рабочем наборе данных 🙁
Проверил на бумажке в клетку несколько перемещений. Распечатал историю движения хвоста. Всё совпадает, всё верно! Уже было думал переписать на вложенных циклах и двигать не «точки по карте», а «карту под точками». К счастью — не пришлось.
Бесплодные мучения продолжались до тех пор, пока я не пролистал весь входной набор и не заметил, наконец (как индеец «Зоркий глаз»), что шаги бывают заданы двузначными числами.
«Эврика!» — воскликнул Архимед. А я воскликнул — «Идиот!». Быстренько поправил парсинг и, с глубоким облегчением, отправил верные ответы на загадку!
Исходные данные: https://adventofcode.com/2022/day/9/input