Так вот ты какая – идеальная капча!
Задача десятого дня далась неожиданно просто. Ну, не совсем неожиданно и не совсем просто, будем честны. Но, по сравнению с проклятым “древом седьмого дня” – это было совсем не больно 🙂
Поначалу думал, что получится всё запихать в один длинный и страшный стрим, с кучей таинственных мутаций внутри.
Как-то я делал сервис, реализующий развесистую логику подбора уже не помню чего по куче разных условий – и вот там было именно так. Мапы перетекали в мапы, всё это бесконечно упаковывалось и распаковывалось, подвергалось преобразованиям Шварца (да, корни где-то в Лиспе), и, в качестве вишенки на торте, венчалось самосборным коллектором.
В общем, для такого лучше подошел бы Perl. Или, например, JS. И уже через минуту я бы точно забыл, как это работает.
На джаве всё получилось достаточно стройненько (но очень даже длинненько), не смотря на использование только консоли jshell
. Кучка сущностей с описанием системы:
interface SignalTracker {
void track(int rX, int cycle);
}
static class SignalStrengthCounter implements SignalTracker {
private final Set<Integer> cycleToCheck = Set.of(20, 60, 100, 140, 180, 220);
public int strength = 0;
@Override
public void track(int rX, int cycle) {
if (cycleToCheck.contains(cycle)) this.strength += rX * cycle;
}
}
static class CRT implements SignalTracker {
private static final int SCREEN_WIDTH = 40;
public final StringBuilder screen = new StringBuilder(System.lineSeparator());
@Override
public void track(int ra, int cycle) {
var symbol = cycle % SCREEN_WIDTH;
screen.append(symbol >= ra && symbol <= ra + 2 ? "#" : " ");
if (cycle != 0 && symbol % SCREEN_WIDTH == 0) screen.append(System.lineSeparator());
}
}
enum Operation {
noop(1),
addx(2);
final int busyTime;
Operation(int busyTime) {
this.busyTime = busyTime;
}
}
static class Instruction {
public Operation operation;
int value;
private Instruction(Operation operation, int value) {
this.operation = operation;
this.value = value;
}
static public Instruction parseCommand(String input) {
String[] split = input.split(" ");
int v = split.length > 1 ? Integer.parseInt(split[1]) : 0;
return new Instruction(Operation.valueOf(split[0]), v);
}
}
static class CPU {
private final SignalTracker counter;
private int rX = 1;
private int cycle = 0;
public CPU(SignalTracker c) {
this.counter = c;
}
public void exec(Instruction instruction) {
Operation o = instruction.operation;
this.updateCycle(o);
if (o == Operation.addx) {
rX += instruction.value;
}
}
private void updateCycle(Operation op) {
for (int i = 0; i < op.busyTime; i++) {
cycle++;
counter.track(rX, cycle);
}
}
}
Черту под которыми подводит достаточно простая логика обработки входа:
static void day10(String puzzleInputUri) throws IOException, InterruptedException {
SignalStrengthCounter sigStrength = new SignalStrengthCounter();
CPU cpu = new CPU(sigStrength);
CRT crt = new CRT();
CPU gpu = new CPU(crt);
client.send(request.uri((URI.create(puzzleInputUri))).build(), HttpResponse.BodyHandlers.ofLines())
.body()
.map(Instruction::parseCommand)
.peek(cpu::exec)
.peek(gpu::exec)
.count();
System.out.println(sigStrength.strength);
System.out.println(crt.screen);
}
В итоге получилось заветное слово АБЫРВАЛГ
. Шучу – получилось (не менее странное) RZHFGJCB
.
С точками в качестве “пустых символов” это выглядело абсолютно нечитаемо, подчеркивания чуть исправили картину, но наилучший эффект и белоснежную улыбку обеспечили самые обыкновенные пробелы!
### #### # # #### ## ## ## ###
# # # # # # # # # # # # #
# # # #### ### # # # ###
### # # # # # ## # # # ##
# # # # # # # # # # # # # ##
# # #### # # # ### ## ## ###
Кто-нибудь знает, что это может означать? Я тоже понятия не имею 🙂 Наверное, можно было бы поколдовать с escape-символами консоли, но наш девиз – “И так сойдёт!”.
Исходные данные: https://adventofcode.com/2022/day/10/input