Как я участвовал в IOCCC-'19 (и проиграл). Часть 2: «Симулятор NOR»
Это вторая часть цикла статей о том, как я участвовал в IOCCC'19
- Как я участвовал в IOCCC-'19 (и проиграл). Часть 1: «Крестики-нолики»
- Как я участвовал в IOCCC-'19 (и проиграл). Часть 2: «Симулятор NOR»
Я надеюсь, что данная статья поможет вам при разборе чужого кода или кода после декомпилятора или обфускатора.
Если вы еще не знаете, что такое IOCCC или вы хотите ознакомиться с более простым вариантом запутанного кода, то рекомендую обратиться к первой части.
Всем остальным я желаю приятного чтения.
Все исходники помещены на github, откуда их можно невозбранно скачать и попробовать скомпилировать.
Исходные данные
Так как исходный код в текстовом виде можно найти по ссылке, покажу как код выглядит графически:
Традиционно сложилось, что «дополнительные баллы» даются, если код отформатирован нестандартно или выглядит как какое-то изображение. Что ж, будем считать, это с этим здесь всё в порядке.
Но что же делает программа?
Она инициализирует графический стек X-сервера, сканирует предоставленный файл конфигурации, рисует электрическую схему согласно файлу и запускает симуляцию, поочередно меняя полярность на 4 ножках входа, используя при этом только NOR (Not-OR) элементы. Отрисовка происходит с шейдером старого LCD-экрана.
В комплекте с программой идут несколько конфигурационных файлов, а именно:
DIP8–4packnot.txt — примерный аналог CMOS 4041/Четырехканальный инвертор
(изображение сжато в 2 раза, чтобы уместиться в рамки приличия. На самом деле забавно, что программа, весом в 3.5 КБ генерирует ряд изображений, который в максимальном сжатии занимают 10.5+МБ)
DIP8-triplexor.txt — примерный аналог CMOS 4030 с объединенными входами и тремя каналами/Трехканальный XOR-gate с объединенными входами
DIP8-fulladder.txt — примерный аналог CMOS 4008, но на два бита/сумматор на 2 бита с выводом бита переноса
Разбор кода
Самой сложной задачей в этот раз было уместиться в ограничение по размеру присылаемой работы. Ограничен не только размер файла, но и количество условных «токенов» — символов операций, ключевых слов языка и пар скобок. Именно для того, чтобы «заэксплойтить» эту особенность парсера-проверяльщика размера в программе объявлено огромное количество define’ов, приводящих блоки кода к одному ключевому слову языка С.
Для начала, заглянем в Makefile, чтобы понять, как код собирается: #!/usr/bin/env make
PROJECT=prog
CC= gcc
SRC=prog.c
CWARN=-Wall -Wextra -Wno-char-subscripts
CSTD= -std=c99
# Syscalls table
# DS — syscall nanosleep
# DO — syscall open
# DR — syscall read
# DC — syscall close
# X11 structures offsets
# dS — offset of screens in Display
# dR — offset of root in Screen
# dD — offset of root_depth in Screen
# dV — offset of root_visual in Screen
# dG — offset of default_gc in Screen
BITS:= $(shell uname -p)
ifeq ($(BITS), x86_64)
ARCH= -m64
CDEFINE= -DDS=35 -DDO=2 -DDR=0 -DDC=3 -DdS=232 -DdR=16 -DdD=56 -DdV=64 -DdG=72
else
ARCH= -m32
CDEFINE= -DDS=162 -DDO=5 -DDR=3 -DDC=6 -DdS=140 -DdR=8 -DdD=36 -DdV=40 -DdG=44
endif
OPT= -g
CFLAGS= ${CWARN} ${CSTD} ${ARCH} ${CDEFINE} ${OPT}
LDFLAGS= -ldl
RM= rm
all: ${PROJECT}
${PROJECT}:
${CC} ${CFLAGS} ${SRC} -o $@ ${LDFLAGS}
clean:
${RM} -f ${PROJECT}
Как видим, эта работа, так же, как и предыдущая активно использует системные вызовы, чтобы избежать уродливых »#include», которые нарушают узор картинки. Запомним этот факт и подготовим строку для препроцессора и линтера:
gcc -DDS=35 -DDO=2 -DDR=0 -DDC=3 -DdS=232 -DdR=16 -DdD=56 -DdV=64 -DdG=72 prog.c -ldl -E | indent -kr -brf > /tmp/fmt.c
: int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
extern void *dlsym(void *, char *);
int x_[616][1220];
extern long syscall(long, ...);
extern void *dlopen(char *, int);
char m[19][20], _n[] =
"pu~D--2os" "<<<<<<<<" "<<= 19 || y >= 19 || x < 0 || y < 0) || (m[y][x] == l)
|| (m[y][x] != c))
return;
m[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= 64 || y >= 40 || x < 0 || y < 0) || (_[t][y][x] == l)
|| (_[t][y][x] != c))
return;
_[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x++] = l;
_[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x--] = l;
_[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
_[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4}, (char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
void d_(int t, int p, int q) {
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t]
[y][x])
x_[y + q * 16 + p * 16][x + 580 + p * 32 - q *
32] = _[t][y][x];
}
int main(int a, char *s[]) {
int h = 127;
while (h--) {
_n[h] ^= 28;
_n[h] -= (_n[h] == 32 ? 32 : 0);
}
T = dlopen(_n, 2);
d = ((void *(*)()) dlsym(T, _n + (1 * 20))) (0);
w = ((long (*)()) dlsym(T, _n + (2 * 20))) (d,
(*(long *)
((char
*) (*(long *) ((char *)
d +
232)) +
16))
, 0, 0, 1220, 616, 1, 0,
0);
M = ((void *(*)()) dlsym(T, _n + (3 * 20))) (d,
(*(long *)
((char
*) (*(long *) ((char *)
d +
232)) +
64)),
(*(long *)
((char
*) (*(long *) ((char *)
d +
232)) +
56)), 2, 0, (char *) x_,
1220, 616, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
int f = syscall(2, s[1], 0);
syscall(0, f, m, 380);
syscall(3, f);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
m[y][x] = 46;
b(0, 2, 3, m[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, m[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, m[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, m[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if (m[y][x] == 62)
b(0, x + 1, y, m[y][x + 1],
!(m[y - 1][x] == 43 ? 1 : 0
|| m[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++)
x_[y][x] = 0;
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
d_(((m[y][x] >> 4) & 1) << 2 | (m[y][x] & 3), x, y);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
d_(7, x, y);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++) {
x_[y][x] &= 14737632 | (31 << ((x % 3) << 3));
x_[y][x] += 986895 & (rn *= 16777619);
} ((long (*)()) dlsym(T, _n + (4 * 20))) (d, w,
(*(long *)
((char
*) (*(long
*) ((char *)
d +
232)) +
72)), M, 0, 0, 0,
0, 1220, 616);
((long (*)()) dlsym(T, _n + (5 * 20))) (d, w);
((long (*)()) dlsym(T, _n + (6 * 20))) (d);
syscall(35, &N, &R);
} return 0;
}
Что ж, по крайней мере одно из условий конкурса мы выполнили, код после препроцессора понятнее не стал.
Начнем с того, что можно выловить с первого взгляда и попытаемся восстановить цепочку событий:
dlsym\dlopen
Очевидно, что чтобы воспользоваться функциями X-сервера и создать окно, а затем в нем что-то отрисовать код должен обратиться к библиотеке XLib. В коде присутствуют функции dlopen/dlsym, позволяющие динамически подгрузить библиотеку, однако на вход им подается какая-то хитрая каша:
char _n[] =
"pu~D--2os" "<<<<<<<<" "<<
Пройдем на шаг назад и проинспектируем следующий код:
int h = 127;
while (h--) {
_n[h] ^= 28;
_n[h] -= (_n[h] == 32 ? 32 : 0);
}
Судя по всему, он некоторым образом преобразует исходный массив, позволяя нам получить читаемые строки. Выполним его отдельно:
https://onlinegdb.com/SJNM9Og7v: libX11.so
XOpenDisplay
XCreateSimpleWindow
XCreateImage
XPutImage
XMapWindow
XFlush
Для того, чтобы одной строкой вызывать столь различные по формату функции код эксплуатирует тот факт, что в стандарте языка С (void) означает отсутствие параметров, а () — любое число параметров. Остается только привести полученный void * к соответствующему ((long (*)()) типу и вуаля:
w = ((long (*)()) dlsym(T, _n + (2 * 20))) (d, (*(long *)((char *) (*(long *)((char *) d + 232)) + 16))
Зная, что эти преобразования означают теперь мы можем заменить столь необычное использование dlsym сначала на строки:
int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
extern void *dlsym(void *, char *);
int x_[616][1220];
extern long syscall(long, ...);
extern void *dlopen(char *, int);
char m[19][20];
long w, N[2] = { 0, 1 << 29 };
int rn = 2166136261, _[8][40][64] = { 0 };
long R[2];
void *M, *d, *T;
void b(int t, int x, int y, int c, int l) {
if ((x >= 19 || y >= 19 || x < 0 || y < 0) || (m[y][x] == l)
|| (m[y][x] != c))
return;
m[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= 64 || y >= 40 || x < 0 || y < 0) || (_[t][y][x] == l)
|| (_[t][y][x] != c))
return;
_[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x++] = l;
_[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x--] = l;
_[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
_[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4}, (char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
void d_(int t, int p, int q) {
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t]
[y][x])
x_[y + q * 16 + p * 16][x + 580 + p * 32 - q *
32] = _[t][y][x];
}
int main(int a, char *s[]) {
T = dlopen("libX11.so", 2);
d = ((void *(*)()) dlsym(T, "XOpenDisplay") (0);
w = ((long (*)()) dlsym(T, "XCreateSimpleWindow")) (d,
(*(long *)
((char
*) (*(long *) ((char *)
d +
232)) +
16))
, 0, 0, 1220, 616, 1, 0,
0);
M = ((void *(*)()) dlsym(T, "XCreateImage")) (d,
(*(long *)
((char
*) (*(long *) ((char *)
d +
232)) +
64)),
(*(long *)
((char
*) (*(long *) ((char *)
d +
232)) +
56)), 2, 0, (char *) x_,
1220, 616, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
int f = syscall(2, s[1], 0);
syscall(0, f, m, 380);
syscall(3, f);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
m[y][x] = 46;
b(0, 2, 3, m[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, m[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, m[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, m[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if (m[y][x] == 62)
b(0, x + 1, y, m[y][x + 1],
!(m[y - 1][x] == 43 ? 1 : 0
|| m[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++)
x_[y][x] = 0;
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
d_(((m[y][x] >> 4) & 1) << 2 | (m[y][x] & 3), x, y);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
d_(7, x, y);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++) {
x_[y][x] &= 14737632 | (31 << ((x % 3) << 3));
x_[y][x] += 986895 & (rn *= 16777619);
} ((long (*)()) dlsym(T, "XPutImage")) (d, w,
(*(long *)
((char
*) (*(long
*) ((char *)
d +
232)) +
72)), M, 0, 0, 0,
0, 1220, 616);
((long (*)()) dlsym(T, "XMapWindow")) (d, w);
((long (*)()) dlsym(T, "XFlush")) (d);
syscall(35, &N, &R);
} return 0;
}
А потом и на родные функции:
#include
int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
int x_[616][1220];
extern long syscall(long, ...);
char m[19][20];
long w, N[2] = { 0, 1 << 29 };
int rn = 2166136261, _[8][40][64] = { 0 };
long R[2];
void *M, *d, *T;
void b(int t, int x, int y, int c, int l) {
if ((x >= 19 || y >= 19 || x < 0 || y < 0) || (m[y][x] == l)
|| (m[y][x] != c))
return;
m[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= 64 || y >= 40 || x < 0 || y < 0) || (_[t][y][x] == l)
|| (_[t][y][x] != c))
return;
_[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x++] = l;
_[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x--] = l;
_[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
_[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4}, (char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
void d_(int t, int p, int q) {
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t]
[y][x])
x_[y + q * 16 + p * 16][x + 580 + p * 32 - q *
32] = _[t][y][x];
}
int main(int a, char *s[]) {
d = XOpenDisplay(0);
w = XCreateSimpleWindow(d, (*(long *) ((char *) (*(long *) ((char *)d + 232)) + 16)), 0, 0, 1220, 616, 1, 0, 0);
M = XCreateImage(d, (*(long *)((char *) (*(long *) ((char *)d + 232)) + 64)), (*(long *)((char *) (*(long *) ((char *)d + 232)) + 56)), 2, 0, (char *) x_, 1220, 616, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
int f = syscall(2, s[1], 0);
syscall(0, f, m, 380);
syscall(3, f);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
m[y][x] = 46;
b(0, 2, 3, m[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, m[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, m[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, m[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if (m[y][x] == 62)
b(0, x + 1, y, m[y][x + 1],
!(m[y - 1][x] == 43 ? 1 : 0
|| m[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++)
x_[y][x] = 0;
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
d_(((m[y][x] >> 4) & 1) << 2 | (m[y][x] & 3), x, y);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
d_(7, x, y);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++) {
x_[y][x] &= 14737632 | (31 << ((x % 3) << 3));
x_[y][x] += 986895 & (rn *= 16777619);
}
XPutImage(d, w, (*(long *)((char *) (*(long *) ((char *)d + 232)) + 72)), M, 0, 0, 0, 0, 1220, 616);
XMapWindow(d, w);
XFlush(d);
syscall(35, &N, &R);
}
return 0;
}
Syscalls
Заменим системные вызовы по тому же принципу, которому мы следовали в первой части:
#include
#include
#include
#include
#include
int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
int x_[616][1220];
char m[19][20];
long w;
int rn = 2166136261, _[8][40][64] = { 0 };
void *M, *d, *T;
void b(int t, int x, int y, int c, int l) {
if ((x >= 19 || y >= 19 || x < 0 || y < 0) || (m[y][x] == l)
|| (m[y][x] != c))
return;
m[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= 64 || y >= 40 || x < 0 || y < 0) || (_[t][y][x] == l)
|| (_[t][y][x] != c))
return;
_[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x++] = l;
_[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x--] = l;
_[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
_[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4}, (char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
void d_(int t, int p, int q) {
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t]
[y][x])
x_[y + q * 16 + p * 16][x + 580 + p * 32 - q *
32] = _[t][y][x];
}
int main(int a, char *s[]) {
d = XOpenDisplay(0);
w = XCreateSimpleWindow(d, (*(long *) ((char *) (*(long *) ((char *)d + 232)) + 16)), 0, 0, 1220, 616, 1, 0, 0);
M = XCreateImage(d, (*(long *)((char *) (*(long *) ((char *)d + 232)) + 64)), (*(long *)((char *) (*(long *) ((char *)d + 232)) + 56)), 2, 0, (char *) x_, 1220, 616, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
int f = open(s[1], 0);
read(f, m, 380);
close(f);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
m[y][x] = 46;
b(0, 2, 3, m[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, m[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, m[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, m[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if (m[y][x] == 62)
b(0, x + 1, y, m[y][x + 1],
!(m[y - 1][x] == 43 ? 1 : 0
|| m[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++)
x_[y][x] = 0;
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
d_(((m[y][x] >> 4) & 1) << 2 | (m[y][x] & 3), x, y);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
d_(7, x, y);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++) {
x_[y][x] &= 14737632 | (31 << ((x % 3) << 3));
x_[y][x] += 986895 & (rn *= 16777619);
}
XPutImage(d, w, (*(long *)((char *) (*(long *) ((char *)d + 232)) + 72)), M, 0, 0, 0, 0, 1220, 616);
XMapWindow(d, w);
XFlush(d);
sleep(1);
}
return 0;
}
XCreateSimpleWindow и смещения
Постараемся разобрать следующую конструкцию:
w = XCreateSimpleWindow(d, (*(long *) ((char *) (*(long *) ((char *)d + 232)) + 16)), 0, 0, 1220, 616, 1, 0, 0);
Куча преобразований типов, которые, на первый взгляд, нужны лишь чтобы запутать читателя, однако каждое преобразование здесь имеет свою цель, а именно:
d — это указатель на структуру Display в контексте Xlib. Он имеет поле-массив, называемое screens и для того, чтобы получить указатель на первый элемент этого массива мы должны отсчитать некоторое количество байт (на x64 — 232) от указателя на Display вперед. Так как Display не char *, то при прямом отсчитывании мы обсчитались бы в sizeof (long *) байт. Поэтому приведем d к char * и сдвинемся на 232 байта:
((char *)d + 232)
Мы получили позицию первого элемента Screens в памяти. Приведем его к полноценному указателю и разыменуем:
(*(long *) ((char *)d + 232))
Теперь внутри структуры Screens мы должны получить указатель на корневое окно, Root. Для этого отойдем от Screens на 16 байт и разыменуем конструкцию:
(*(long *) ((char *) (*(long *) ((char *)d + 232)) + 16))
Эта конструкция на самом деле каждый день используется программистами под Xlib, поскольку её общеупотребимый эквивалент — это
RootWindow(Display, DefaultScreen(Display))
Аналогичным образом заменим соответствующие смещения в других местах, чтобы получить более привычные глазу макросы (заодно поправим косяки indent):
#include
#include
#include
#include
#include
int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
int x_[616][1220];
char m[19][20];
int rn = 2166136261, _[8][40][64] = { 0 };
void *T;
Display * display;
Window window;
XImage * image;
void b(int t, int x, int y, int c, int l) {
if ((x >= 19 || y >= 19 || x < 0 || y < 0) || (m[y][x] == l)
|| (m[y][x] != c))
return;
m[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= 64 || y >= 40 || x < 0 || y < 0) || (_[t][y][x] == l)
|| (_[t][y][x] != c))
return;
_[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x++] = l;
_[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
_[t][y][x--] = l;
_[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
_[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4},
(char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
void d_(int t, int p, int q) {
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t][y][x])
x_[y + q * 16 + p * 16][x + 580 + p * 32 - q * 32] = _[t][y][x];
}
int main(int a, char *s[]) {
display = XOpenDisplay(0);
window = XCreateSimpleWindow(display,
RootWindow(display, DefaultScreen(display)),
0, 0, 1220, 616, 1, 0, 0);
image = XCreateImage(display,
DefaultVisual(display, DefaultScreen(display)),
DefaultDepth(display, DefaultScreen(display)),
2, 0, (char *) x_, 1220, 616, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
int f = open(s[1], 0);
read(f, m, 380);
close(f);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
m[y][x] = 46;
b(0, 2, 3, m[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, m[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, m[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, m[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if (m[y][x] == 62)
b(0, x + 1, y, m[y][x + 1],
!(m[y - 1][x] == 43 ? 1 : 0
|| m[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++)
x_[y][x] = 0;
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
d_(((m[y][x] >> 4) & 1) << 2 | (m[y][x] & 3), x, y);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
d_(7, x, y);
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++) {
x_[y][x] &= 14737632 | (31 << ((x % 3) << 3));
x_[y][x] += 986895 & (rn *= 16777619);
}
XPutImage(display, window,
DefaultGC(display, DefaultScreen(display)),
image, 0, 0, 0, 0, 1220, 616);
XMapWindow(display, window);
XFlush(display);
sleep(1);
}
return 0;
}
Данные изображения
Обратим внимание, что XCreateImage требует на вход указатель на область памяти, где будут храниться данные пикселей. Для нашего вызова функции это переменная «x_». Переименуем ее в pixdata и найдем все места, где она используется:
void d_(int t, int p, int q) {
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t][y][x])
pixdata[y + q * 16 + p * 16][x + 580 + p * 32 - q * 32] = _[t][y][x]; // Очевидно, что это копирование данных из какого-то источника
}
image = XCreateImage(display,
DefaultVisual(display, DefaultScreen(display)),
DefaultDepth(display, DefaultScreen(display)),
2, 0, (char *) pixdata, 1220, 616, 32, 0); // создание изображения
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++)
pixdata[y][x] = 0; // "Обнуление" пикселей, закраска черным цветом
for (int y = 0; y < 616; y++)
for (int x = 0; x < 1220; x++) { // Какая-то странная математическая операция, очевидно применяемая ко всему изображению.
pixdata[y][x] &= 14737632 | (31 << ((x % 3) << 3));
pixdata[y][x] += 986895 & (rn *= 16777619);
}
Вычленим блок pixdata[…] = 0 в отдельную функцию и попытаемся разобрать, что же делает первое вхождение:
for (int y = 0; y < 40; y++)
for (int x = 0; x < 64; x++)
if (_[t][y][x])
pixdata[y + q * 16 + p * 16][x + 580 + p * 32 - q * 32] = _[t][y][x];
Если присмотреться к итоговому изображению, сформированному при работе программы, то легко заметить, что 40 и 64 — это размеры отдельного «блока», из которого построена схема.
Следовательно, эта функция рисует отдельный «тайл» на канве основного изображения, а судя по индексации массива »_» переменная «t» отвечает за индекс изображения, а p и q — за координаты x и y. Заодно переименуем »_» в textures:
#include
#include
#include
#include
#include
/* Код после рефакторинга */
/*! \brief Ширина изображения в пикселях */
#define IMAGE_WIDTH *1220)
/*! \brief Высота изображения в пикселях */
#define IMAGE_HEIGHT (616)
/*! \brief Количество текстур */
#define TEXTURE_COUNT (8)
/*! \brief Ширина текстуры в пикселях */
#define TEXTURE_WIDTH (64)
/*! \brief Высота текстур в пикселях */
#define TEXTURE_HEIGHT (40)
/*! \brief Бинарные данные пикселей изображения.
* Типизированы к int для оперирования пикселями вместо каналов */
int pixdata[IMAGE_HEIGHT][IMAGE_WIDTH];
int textures[TEXTURE_COUNT][TEXTURE_HEIGHT][TEXTURE_WIDTH] = { 0 };
/*! \brief Экземпляр дисплея Xlib */
Display * display;
/*! \brief Экземпляр главного окна Xlib */
Window window;
/*! \brief Изображение для вывода на экран */
XImage * image;
/* \brief Обнуляет изображение, заполняя его черным цветом */
static void _image_reset(void) {
for (int y = 0; y < IMAGE_HEIGHT; y++)
for (int x = 0; x < IMAGE_WIDTH; x++)
pixdata[y][x] = 0;
}
/*! \brief Отрисовывает текстуру на главном холсте по указанным координатам
* \param[in] t Индекс текстуры
* \param[in] x X координата тайла
* \param[in] y Y координата тайла */
void _texture_draw(int t, int x, int y) {
for (int ty = 0; ty < TEXTURE_HEIGHT; ty++)
for (int tx = 0; tx < TEXTURE_WIDTH; tx++)
if (textures[t][ty][tx])
pixdata[ty + y * 16 + x * 16]
[tx + 580 + x * 32 - y * 32] = textures[t][ty][tx];
}
/* Код до рефакторинга */
int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
char m[19][20];
int rn = 2166136261;
void *T;
void b(int t, int x, int y, int c, int l) {
if ((x >= 19 || y >= 19 || x < 0 || y < 0) || (m[y][x] == l)
|| (m[y][x] != c))
return;
m[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= TEXTURE_WIDTH || y >= TEXTURE_HEIGHT ||
x < 0 || y < 0) ||
(textures[t][y][x] == l) ||
(textures[t][y][x] != c))
return;
textures[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
textures[t][y][x++] = l;
textures[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
textures[t][y][x--] = l;
textures[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
textures[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4},
(char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
int main(int a, char *s[]) {
display = XOpenDisplay(0);
window = XCreateSimpleWindow(display,
RootWindow(display, DefaultScreen(display)),
0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 1, 0, 0);
image = XCreateImage(display,
DefaultVisual(display, DefaultScreen(display)),
DefaultDepth(display, DefaultScreen(display)),
2, 0, (char *) pixdata, IMAGE_WIDTH, IMAGE_HEIGHT, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
int f = open(s[1], 0);
read(f, m, 380);
close(f);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
m[y][x] = 46;
b(0, 2, 3, m[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, m[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, m[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, m[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if (m[y][x] == 62)
b(0, x + 1, y, m[y][x + 1],
!(m[y - 1][x] == 43 ? 1 : 0
|| m[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
_image_reset();
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
_texture_draw(((m[y][x] >> 4) & 1) << 2 | (m[y][x] & 3), x, y);
for (int y = 0; y < 19; y++)
for (int x = 0; x < 19; x++)
if ((x % 14 == 2) && (y % 4 == 3))
_texture_draw(7, x, y);
for (int y = 0; y < IMAGE_HEIGHT; y++)
for (int x = 0; x < IMAGE_WIDTH; x++) {
pixdata[y][x] &= 14737632 | (31 << ((x % 3) << 3));
pixdata[y][x] += 986895 & (rn *= 16777619);
}
XPutImage(display, window,
DefaultGC(display, DefaultScreen(display)),
image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
XMapWindow(display, window);
XFlush(display);
sleep(1);
}
return 0;
}
Чтение карты
Выделим в отдельную функцию строки open…close, где читается содержимое выбранного файла в переменную m (которую переименуем в mapdata).
Почему файл считается в каждом цикле? Так было короче с точки зрения кода и токенов. Около 4 дней занял процесс «утрамбовывания» кода чтобы поместиться в лимиты правил. Если читать файл только один раз то потребовалось бы дополнительное хранилище и какой-то аналог функции memcpy.
#include
#include
#include
#include
#include
/* Код после рефакторинга */
/*! \brief Ширина изображения в пикселях */
#define IMAGE_WIDTH (1220)
/*! \brief Высота изображения в пикселях */
#define IMAGE_HEIGHT (616)
/*! \brief Сдвиг верхней грани карты от левой стороны */
#define IMAGE_SHIFTX (580)
/*! \brief Количество текстур */
#define TEXTURE_COUNT (8)
/*! \brief Ширина текстуры в пикселях */
#define TEXTURE_WIDTH (64)
/*! \brief Высота текстур в пикселях */
#define TEXTURE_HEIGHT (40)
/*! \brief Ширина грани текстуры в пикселях */
#define TEXTURE_TOP_WIDTH (64)
/*! \brief Высота грани текстуры в пикселях */
#define TEXTURE_TOP_HEIGHT (32)
/*! \brief Ширина эмулируемого поля */
#define MAP_WIDTH (19)
/*! \brief Высота эмулируемого поля */
#define MAP_HEIGHT (19)
/*! \brief Количество данные в файле-чертеже. Один байт добавлен для символа '\n' */
#define MAP_FILEDATA ((MAP_WIDTH + 1) * MAP_HEIGHT)
/*! \brief Бинарные данные пикселей изображения.
* Типизированы к int для оперирования пикселями вместо каналов */
int pixdata[IMAGE_HEIGHT][IMAGE_WIDTH];
/*! \brief Текстуры блоков, отображаемых на поле */
int textures[TEXTURE_COUNT][TEXTURE_HEIGHT][TEXTURE_WIDTH] = { 0 };
/*! \brief Данные эмулируемого поля.
* Один байт добавлен для упрощения обработки символа '\n' */
char mapdata[MAP_HEIGHT][MAP_WIDTH + 1];
/*! \brief Экземпляр дисплея Xlib */
Display * display;
/*! \brief Экземпляр главного окна Xlib */
Window window;
/*! \brief Изображение для вывода на экран */
XImage * image;
/* \brief Обнуляет изображение, заполняя его черным цветом */
static void _image_reset(void) {
for (int y = 0; y < IMAGE_HEIGHT; y++)
for (int x = 0; x < IMAGE_WIDTH; x++)
pixdata[y][x] = 0;
}
/*! \brief Отрисовывает текстуру на главном холсте по указанным координатам
* \param[in] t Индекс текстуры
* \param[in] x X координата тайла
* \param[in] y Y координата тайла */
static void _texture_draw(int t, int x, int y) {
for (int ty = 0; ty < TEXTURE_HEIGHT; ty++)
for (int tx = 0; tx < TEXTURE_WIDTH; tx++)
if (textures[t][ty][tx])
pixdata[ty +
y * (TEXTURE_TOP_HEIGHT / 2) +
x * (TEXTURE_TOP_HEIGHT / 2)]
[tx +
IMAGE_SHIFTX +
x * (TEXTURE_TOP_WIDTH / 2) -
y * TEXTURE_TOP_HEIGHT] = textures[t][ty][tx];
}
/*! \brief Читает данные файла-чертежа и загружает их в карту
* \param[in] filename Имя файла-чертежа */
static void _map_read(const char * filename) {
int f = open(filename, 0);
read(f, mapdata, MAP_FILEDATA);
close(f);
}
/* Код до рефакторинга */
int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };
int rn = 2166136261;
void *T;
void b(int t, int x, int y, int c, int l) {
if ((x >= MAP_WIDTH || y >= MAP_HEIGHT ||
x < 0 || y < 0) || (mapdata[y][x] == l)
|| (mapdata[y][x] != c))
return;
mapdata[y][x] = l;
b(t, x - 1, y, c, l);
b(t, x + 1, y, c, l);
b(t, x, y - 1, c, l);
b(t, x, y + 1, c, l);
}
void e(int t, int x, int y, int c, int l) {
if ((x >= TEXTURE_WIDTH || y >= TEXTURE_HEIGHT ||
x < 0 || y < 0) ||
(textures[t][y][x] == l) ||
(textures[t][y][x] != c))
return;
textures[t][y][x] = l;
e(t, x - 1, y, c, l);
e(t, x + 1, y, c, l);
e(t, x, y - 1, c, l);
e(t, x, y + 1, c, l);
}
void k(int t, int x, int y, int c, int l) {
while (c--) {
textures[t][y][x++] = l;
textures[t][y++][x++] = l;
}
}
void r(int t, int x, int y, int c, int l) {
while (c--) {
textures[t][y][x--] = l;
textures[t][y++][x--] = l;
}
}
void u(int t, int x, int y, int c, int l) {
while (c--)
textures[t][y++][x] = l;
}
char *z[8] = {
(char[]) {4},
(char[]) {6, 1 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16, 0, 0,
21 + 0 * 3 - 0, 16, 1, 63, 21 + 0 * 3 - 0, 16, 2,
63 * 0, 21 - 0, 4, 2, 31 + 0, 36 - 0, 4, 0 + 1,
32 - 1, 5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1, 63,
21 + 1 * 3 - 0, 16, 2, 63 * 1, 21 - 0, 4, 2, 31 + 1,
36 - 0, 4, 6, 1 * 4 + 0, 3, 31, 8 - 0, 6, 1 * 4 + 2,
3, 33, 38 - 0, 6, 1 * 4 + 3, 3, 30, 38 - 0, 4},
(char[]) {5, 1},
(char[]) {6, 0 * 4 + 1, 0 + 0, 32 - 0, 5 - 0, 16,
0, 0, 21 + 0 * 3 - 0, 16, 1, 63,
21 + 0 * 3 - 0, 16, 2, 63 * 0, 21 - 0,
4, 2, 31 + 0, 36 - 0, 4, 0 + 1, 32 - 1,
5 - 0, 16, 0, 0, 21 + 1 * 3 - 0, 16, 1,
63, 21 + 1 * 3 - 0, 16, 2, 63 * 1,
21 - 0, 4, 2, 31 + 1, 36 - 0, 4, 6,
0 * 4 + 0, 3, 31, 8 - 0, 6, 0 * 4 + 2,
3, 33, 38 - 0, 6, 0 * 4 + 3, 3, 30,
38 - 0,
4},
(char[]) {4},
(char[]) {4},
(char[]) {6, 2 * 4 + 1, 0 + 0, 32 - 0, 5 - 3, 16, 0, 0,
21 + 0 * 3 - 3, 16, 1, 63, 21 + 0 * 3 - 3, 16, 2, 63 * 0,
21 - 3, 4, 2, 31 + 0, 36 - 3, 4, 0 + 1, 32 - 1, 5 - 3,
16, 0, 0, 21 + 1 * 3 - 3, 16, 1, 63, 21 + 1 * 3 - 3, 16,
2, 63 * 1, 21 - 3, 4, 2, 31 + 1, 36 - 3, 4, 6, 2 * 4 + 0,
3, 31, 8 - 3, 6, 2 * 4 + 2, 3, 33, 38 - 3, 6, 2 * 4 + 3,
3, 30, 38 - 3, 4},
(char[]) {6, 13, 0, 32, 9 + 0, 12 - 0,
0, 8 + 0 + 0, 21, 12 - 0, 1,
31, 9 + 0, 12 - 0, 1,
55 - 0 - 0, 21, 12 - 0, 0,
32, 9 + 3, 12 - 3, 0,
8 + 3 + 3, 21, 12 - 3, 1,
31, 9 + 3, 12 - 3, 1,
55 - 3 - 3, 21, 12 - 3, 6,
14 + 0, 2, 31 + 0, 13, 4,
1 - 0, 31 + 0, 16, 7, 3,
30 + 3 * 0, 14, 6,
12 + 0 * 4, 3, 32 - 0,
11 + 0 * 8, 6, 14 + 1, 2,
31 + 1, 13, 4, 1 - 1,
31 + 1, 16, 7, 3,
30 + 3 * 1, 14, 6,
12 + 1 * 4, 3, 32 - 1,
11 + 1 * 8,
4}
};
int main(int a, char *s[]) {
display = XOpenDisplay(0);
window = XCreateSimpleWindow(display,
RootWindow(display, DefaultScreen(display)),
0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 1, 0, 0);
image = XCreateImage(display,
DefaultVisual(display, DefaultScreen(display)),
DefaultDepth(display, DefaultScreen(display)),
2, 0, (char *) pixdata, IMAGE_WIDTH, IMAGE_HEIGHT, 32, 0);
for (int i = 0; i < 8; i++) {
char *p = z[i];
int c = 0;
while (*p != 4) {
switch (*p) {
case 0:
k(i, p[1], p[2], p[3], c);
p += 4;
break;
case 1:
r(i, p[1], p[2], p[3], c);
p += 4;
break;
case 2:
u(i, p[1], p[2], p[3], c);
p += 4;
break;
case 3:
e(i, p[1]
, p[2], 0, c);
p += 3;
break;
case 5:
p = z[p[1]];
break;
case 6:
c = _x[p[1] / 4] - 1643277 * (p[1] % 4);
p += 2;
break;
}
}
}
while (a++) {
_map_read(s[1]);
for (int y = 0; y < MAP_HEIGHT; y++)
for (int x = 0; x < MAP_WIDTH; x++)
if ((x % 14 == 2) && (y % 4 == 3))
mapdata[y][x] = 46;
b(0, 2, 3, mapdata[3][2], a & 1 ? 43 : 45);
b(0, 2, 7, mapdata[7][2], a & 2 ? 43 : 45);
b(0, 2, 11, mapdata[11][2], a & 4 ? 43 : 45);
b(0, 2, 15, mapdata[15][2], a & 8 ? 43 : 45);
for (int i = 0; i < 20; i++)
for (int y = 0; y < MAP_HEIGHT; y++)
for (int x = 0; x < MAP_WIDTH; x++)
if (mapdata[y][x] == 62)
b(0, x + 1, y, mapdata[y][x + 1],
!(mapdata[y - 1][x] == 43 ? 1 : 0
|| mapdata[y + 1][x] == 43 ? 1 : 0) ? 43 : 45);
_image_reset();
for (int y = 0; y < MAP_HEIGHT; y++)
for (int x = 0; x < MAP_WIDTH; x++)
_texture_draw(((m[y][x] >> 4) & 1) << 2 | (mapdata[y][x] & 3), x, y);
for (int y = 0; y < MAP_HEIG