4.3 KiB
Он немного изменился
На старте есть изображение kot4_izmenilsya.png. В метаданных указаны встроенный слепок и движение внутри клеток. Размер плитки и таблица направлений не указаны. Сначала ищем исходное изображение внутри PNG.
Решение
В приватном ancillary-чанке caTs лежит конверт CREF: сигнатура, версия 1, длина u32 LE, SHA-256 и байты чистого PNG. Проверяем CRC чанка, затем длину и SHA-256 конверта. Получаем эталонную картинку для сравнения.
Разность изображений показывает изменения в клетках, выровненных от (0, 0). Пробуем размеры 4 × 4, 8 × 8, 16 × 16. Для каждого сравниваем изменённую плитку с четырьмя циклическими сдвигами эталонной на один пиксель.
import numpy as np
candidates = [
np.roll(tile, -1, axis=0), # вверх
np.roll(tile, 1, axis=1), # вправо
np.roll(tile, 1, axis=0), # вниз
np.roll(tile, -1, axis=1), # влево
]
Подходит только сетка 8 × 8, в которой каждая изменённая плитка точно совпадает с одним из сдвигов. При других размерах движение пересекает предполагаемые границы плиток, и такого совпадения нет.
Однозначное направление можно прочитать только у плиток, которые действительно меняются при сдвиге. Поэтому пригодность проверяем по оригиналу, ещё до чтения битов. Все четыре сдвига должны различаться между собой и с исходной плиткой, а максимальная абсолютная разница по каналам между каждой сдвинутой плиткой и оригиналом не должна превышать 4. Разность считаем в знаковом типе, чтобы вычитание uint8 не переполнилось.
Обходим пригодные плитки по строкам. По подсказке первые использованные клетки служат для калибровки. В первых четырёх видим сдвиги вверх, вправо, вниз и влево. Пробуем сопоставить им пары 00, 01, 10, 11 по порядку, а затем проверяем гипотезу по сигнатуре и CRC полученного потока:
| Направление | Пара бит |
|---|---|
| Вверх | 00 |
| Вправо | 01 |
| Вниз | 10 |
| Влево | 11 |
Пропускаем четыре калибровочные плитки и собираем байты по четыре пары, старшая первой. Сначала читаем девятибайтный заголовок с сигнатурой CTM4, версией 1 и длиной payload в u32 LE. Затем читаем payload указанной длины и ещё четыре байта CRC32 в little-endian. Полная длина конверта равна 9 + payload_length + 4 байтам. Совпадение сигнатуры, версии и CRC подтверждает выбранную карту направлений.
В payload читаем флаг и фразу «Это точно та же самая картинка. Мы почти уверены.» Встроенного эталона и самих различий хватило, чтобы восстановить схему без готовой карты в метаданных.
Флаг
caplag{sdv1g_n4_0d1n_p1ks3l}