Как я участвовал в IOCCC-’19 (и проиграл). Часть 2: «Симулятор NOR»

от автора

Это вторая часть цикла статей о том, как я участвовал в IOCCC’19

  1. Как я участвовал в IOCCC-’19 (и проиграл). Часть 1: «Крестики-нолики»
  2. Как я участвовал в 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" "<<<<<<<<" "<<<DSlyrXuolp}e" "<<<<<<<<"     "D_ny}hyOuqlpyKurxsk<D_ny" "}hyUq}{y" "<<<<<<<<" "DLihUq}{y" "<<<<<<<<"     "<<<DQ}lKurxsk" "<<<<<<<<" "<<DZpiot<"; 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[]) {     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" "<<<<<<<<" "<<<DSlyrXuolp}e" "<<<<<<<<"     "D_ny}hyOuqlpyKurxsk<D_ny" "}hyUq}{y" "<<<<<<<<" "DLihUq}{y" "<<<<<<<<"     "<<<DQ}lKurxsk" "<<<<<<<<" "<<DZpiot<"; ... T = dlopen(_n, 2);

Пройдем на шаг назад и проинспектируем следующий код:

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 <X11/Xlib.h>  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 <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  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 <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  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 <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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.

Выделена функция _map_read

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; 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; } 

Раз уж мы затронули переменную mapdata, обратим внимание на строки и функции, где она изменяется — это функция «b», которую мы пока трогать не будем и «main» где, обратив внимание на содержимое «комплектных» файлов конфигураций проведем рефакторинг:

После рефакторинга по mapdata

 #include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */ }  /*! \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); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     b(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     b(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     b(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     b(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     b(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  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]);         _map_wire_inputs();         _map_wire_counter(a);         _map_process_gates();                  _image_reset();                    for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 _texture_draw(((mapdata[y][x] >> 4) & 1) << 2 | (mapdata[y][x] & 3), x, y);                          for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; 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; } 

Для того, чтобы закончить обработку работы с «mapdata» нужно ответить еще на два вопроса — что такое функция «b»:

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); }

И что происходит в блоке

        for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 _texture_draw(((mapdata[y][x] >> 4) & 1) << 2 | (mapdata[y][x] & 3), x, y);

Функция «b»

Если внимательно присмотреться к функции «b», то можно заметить, что она до боли похожа на реализацию алгоритма flood_fill, что совпадает с ее теоретическим назначением — она «заливает» «провод» нужным состоянием, позволяя распространять фронт волны тока до конца провода. Переименуем ее и вынесем в блок «production ready».

Flood fill

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */ };  /*! \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); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 }; int rn = 2166136261;  void *T;  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]);         _map_wire_inputs();         _map_wire_counter(a);         _map_process_gates();                  _image_reset();                    for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 _texture_draw(((mapdata[y][x] >> 4) & 1) << 2 | (mapdata[y][x] & 3), x, y);                          for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; 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; } 

Странный блок

Теперь осталось разобрать, что происходит в строке

_texture_draw(((mapdata[y][x] >> 4) & 1) << 2 | (mapdata[y][x] & 3), x, y);

Так как мы уже построили полную таблицу состояний, которые могут находиться внутри mapdata то мы можем получить все выходные значения первого параметра:

enum int Результат
MAPCHAR_WIRE 46 2
MAPCHAR_PLUS 43 3
MAPCHAR_MINUS 45 1
MAPCHAR_NOR 62 6
MAPCHAR_EMPTY 32 0

Ага, то есть по итогам этого преобразования мы получаем индекс текстуры в массиве текстур.

Для того, чтобы продумать механизм генерации из читаемого и ассоциативно понятного набора символов в индексы текстур понадобилась пара часов. Я выписал символы, которые могли означать провода и NOR-элементы а потом расписав их двоичные значения обводил кружочками уникальные области. Кроме текущего был второй вариант с более сложными вычислениями, но он длиннее, следовательно не подошел по лимиту токенов.

Замечательно, это дает нам возможность вычленить еще одну функцию и объявить enum для каждой текстуры:

После очередного рефакторинга:

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */     MAPCHAR_EMPTY = ' ', /**< Пустой блок       (ASCII = 32) */ };  /*! \brief Содержит индексы текстур */ enum textures_indexes {     TEXINDEX_EMPTY = (0), /**< Индекс пустой текстуры                 */     TEXINDEX_MINUS = (1), /**< Индекс текстуры "выключенного провода" */     TEXINDEX_WIRE  = (2), /**< Индекс текстуры нейтрального провода   */     TEXINDEX_PLUS  = (3), /**< Индекс текстуры "включенного" провода  */     /**/     TEXINDEX_NOR   = (6)  /**< Индекс текстуры NOR-элемента           */ };  /*! \brief Аргументы программы */ enum program_arguments {      ARG_PROGRAM,  /**< Имя самой программы */     ARG_BLUEPRINT /**< Имя файла-чертежа   */ };  /*! \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] elem Символ чертежа  * \return Индекс текстуры */ static int _map2texture(char elem) {     return ((elem >> 4) & 1) << 2 | (elem & 3); }  /*! \brief Собирает изображение из отдельных тайлов согласно карте */ static void _image_compile(void) {     for (int y = 0; y < MAP_HEIGHT; y++)         for (int x = 0; x < MAP_WIDTH; x++)             _texture_draw(_map2texture(mapdata[y][x]), x, y); }  /*! \brief Рисует изображение на экране */ static void _image_draw(void) {     XPutImage(display, window,                DefaultGC(display, DefaultScreen(display)),                image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);     XMapWindow(display, window);     XFlush(display); }  /*! \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); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 }; int rn = 2166136261;  void *T;  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 argc, char * args[]) {     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;             }         }     }     unsigned int counter = 0;     while (counter++) {         _map_read(args[ARG_BLUEPRINT]);         _map_wire_inputs();         _map_wire_counter(counter);         _map_process_gates();                  _image_reset();                   _image_compile();                                            for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; 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);             }                  _image_draw();                  sleep(1);     }      return 0; } 

Текстура #7

Если присмотреться к массиву «z», то можно заметить, что он содержит 8 блоков данных, как константа количества текстур. И в нем даже есть два пробела на позициях 4 и 5, прямо как в нашем enum, скорее всего это данные текстур. Однако он содержит 8 изображений, а мы смогли «открыть» только 7. Однако, если мы будем достаточно внимательными, то мы сможем заметить, что есть участок кода, который рисует конкретно 7ю текстуру:

        for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if ((x % 14 == 2) && (y % 4 == 3))                     _texture_draw(7, x, y);

По позиции уже можно догадаться, что это, но закомментируем эти строки и запустим приложение:
До:

После:

Теперь мы точно знаем, что это текстура отверстия на плате и можем добавить ее в список enum, вынеся её отрисовку в отдельную функцию:

Все текстуры в сборе:

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */     MAPCHAR_EMPTY = ' ', /**< Пустой блок       (ASCII = 32) */ };  /*! \brief Содержит индексы текстур */ enum textures_indexes {     TEXINDEX_EMPTY = (0), /**< Индекс пустой текстуры                 */     TEXINDEX_MINUS = (1), /**< Индекс текстуры "выключенного провода" */     TEXINDEX_WIRE  = (2), /**< Индекс текстуры нейтрального провода   */     TEXINDEX_PLUS  = (3), /**< Индекс текстуры "включенного" провода  */     /**/     TEXINDEX_NOR   = (6), /**< Индекс текстуры NOR-элемента           */     TEXINDEX_HOLE  = (7)  /**< Индекс текстуры отверстия на плате     */ };  /*! \brief Аргументы программы */ enum program_arguments {      ARG_PROGRAM,  /**< Имя самой программы */     ARG_BLUEPRINT /**< Имя файла-чертежа   */ };  /*! \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;  static void _texture_draw(int t, int x, int y);  /*! \brief Создает изображение и сопутствующие сущности */ static void _image_create(void) {     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); }  /* \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] elem Символ чертежа  * \return Индекс текстуры */ static int _map2texture(char elem) {     return ((elem >> 4) & 1) << 2 | (elem & 3); }  /*! \brief Собирает изображение из отдельных тайлов согласно карте */ static void _image_compile(void) {     for (int y = 0; y < MAP_HEIGHT; y++)         for (int x = 0; x < MAP_WIDTH; x++)             _texture_draw(_map2texture(mapdata[y][x]), x, y); }  /*! \brief Рисует изображение на экране */ static void _image_draw(void) {     XPutImage(display, window,                DefaultGC(display, DefaultScreen(display)),                image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);     XMapWindow(display, window);     XFlush(display); }  /*! \brief Рисует отверстия на печатной плате */ static void _image_drill(void) {     for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if ((x % 14 == 2) && (y % 4 == 3))                     _texture_draw(TEXINDEX_HOLE, x, y); }  /*! \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); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 }; int rn = 2166136261;  void *T;  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 argc, char * args[]) {     _image_create();      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;             }         }     }     unsigned int counter = 1;     while (counter++) {         _map_read(args[ARG_BLUEPRINT]);         _map_wire_inputs();         _map_wire_counter(counter);         _map_process_gates();                  _image_reset();                   _image_compile();         _image_drill();                  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);             }                  _image_draw();                  sleep(1);     }      return 0; } 

Шейдеры

Котики из предыдущей статьи обещали шейдеры. И они тут есть. А где код, который отвечает за их обработку?

         _image_reset();           // Рано         _image_compile();       // Рано         _image_drill();            // Рано                  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);             }                  _image_draw();  // Поздно 

Методом исключения понимаем, что зашумленность экрана и эффект LCD-монитора дают эти две строчки. А как они работают?
Начнем с последней:

pixdata[y][x] += 986895 & (rn *= 16777619);

К каждому пикселю прибавляется значение 986895 (что в hex-варианты выглядит как 0x0f0f0f), которое перед этим было посредством операции битовое-И совмещено с результатом умножения rn на 16777619. Если бы rn было ренератором случайных чисел, то это создало бы зернистый «шум» на экране в пределах 16 градаций по каждому каналу. И раз шум появляется, значит rn и есть генератор случайных чисел. Но как это достигается?

int rn = 2166136261;

В самом начале программы переменная rn инициализируется числом 2166136261. А на каждой итерации пикселя умножается на 16777619. Это ничто иное, как генератор псевдослучайных чисел. Вот только вместо линейного хорошо изученного генератора используется алгоритм хэширования FNV без шага с XOR, поскольку нам не нужен конечный результат.

Остается понять, как работает предыдущая строка:

pixdata[y][x] &= 14737632 | (31 << ((x % 3) << 3));

Переведем число 14737632 в шестнадцатиричный формат, так как мы работаем с однобайтными каналами света: 0xe0e0e0. А теперь приняв x равным от 0 до 3 проведем соответствующие вычисления:

 0xe0e0e0 | (31 << ((0 % 3) << 3)) = e0e0ff                                                                                                                                                                   0xe0e0e0 | (31 << ((1 % 3) << 3)) = e0ffe0                                                                                                                                                                         0xe0e0e0 | (31 << ((2 % 3) << 3)) = ffe0e0  

Если теперь эти маски применить при помощи операции "&" к цвету пикселя, то мы получим, соответственно, приглушенные R и G, R и B, G и B каналы, что будет выглядеть как эффект от LCD-монитора:

Выделим их в отдельные функции:

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */     MAPCHAR_EMPTY = ' ', /**< Пустой блок       (ASCII = 32) */ };  /*! \brief Содержит индексы текстур */ enum textures_indexes {     TEXINDEX_EMPTY = (0), /**< Индекс пустой текстуры                 */     TEXINDEX_MINUS = (1), /**< Индекс текстуры "выключенного провода" */     TEXINDEX_WIRE  = (2), /**< Индекс текстуры нейтрального провода   */     TEXINDEX_PLUS  = (3), /**< Индекс текстуры "включенного" провода  */     /**/     TEXINDEX_NOR   = (6), /**< Индекс текстуры NOR-элемента           */     TEXINDEX_HOLE  = (7)  /**< Индекс текстуры отверстия на плате     */ };  /*! \brief Аргументы программы */ enum program_arguments {      ARG_PROGRAM,  /**< Имя самой программы */     ARG_BLUEPRINT /**< Имя файла-чертежа   */ };  /*! \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 Зерно генератора случайных чисел */ int random = 2166136261;  /*! \brief Экземпляр дисплея Xlib */ Display * display; /*! \brief Экземпляр главного окна Xlib */ Window window; /*! \brief Изображение для вывода на экран */ XImage * image;  static void _texture_draw(int t, int x, int y);  /*! \brief Создает изображение и сопутствующие сущности */ static void _image_create(void) {     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); }  /* \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] elem Символ чертежа  * \return Индекс текстуры */ static int _map2texture(char elem) {     return ((elem >> 4) & 1) << 2 | (elem & 3); }  /*! \brief Собирает изображение из отдельных тайлов согласно карте */ static void _image_compile(void) {     for (int y = 0; y < MAP_HEIGHT; y++)         for (int x = 0; x < MAP_WIDTH; x++)             _texture_draw(_map2texture(mapdata[y][x]), x, y); }  /*! \brief Рисует изображение на экране */ static void _image_draw(void) {     XPutImage(display, window,                DefaultGC(display, DefaultScreen(display)),                image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);     XMapWindow(display, window);     XFlush(display); }  /*! \brief Рисует отверстия на печатной плате */ static void _image_drill(void) {     for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if ((x % 14 == 2) && (y % 4 == 3))                     _texture_draw(TEXINDEX_HOLE, x, y); }  /*! \brief Применяет шейдер LCD-эффекта на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_lcd(int x, int y) {     pixdata[y][x] &= 0xe0e0e0 | (31 << ((x % 3) << 3)); }  /*! \brief Применяет шейдер случайного шума на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_noise(int x, int y) {     pixdata[y][x] += 0x0f0f0f & (random *= 16777619); }  /*! \brief Накладывает на изображение различные эффекты */ static void _image_postprocess(void) {     for (int y = 0; y < IMAGE_HEIGHT; y++)         for (int x = 0; x < IMAGE_WIDTH; x++) {             _shader_lcd(x, y);             _shader_noise(x, y);         } }  /*! \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); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };  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 argc, char * args[]) {     _image_create();      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;             }         }     }     unsigned int counter = 1;     while (counter++) {         _map_read(args[ARG_BLUEPRINT]);         _map_wire_inputs();         _map_wire_counter(counter);         _map_process_gates();                  _image_reset();                   _image_compile();         _image_drill();         _image_postprocess();                 _image_draw();                  sleep(1);     }      return 0; } 

«e», «k», «r», «u»

Осталось еще 4 функции, которые мы не исследовали и не переименовали — это «e», «k», «r» и «u». Попытаемся осмотреть их, не прибегая к поиску мест, откуда они вызываются:

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); }

Очевидно, что эта функция выглядит и работает как flood_fill, только для массива textures, переименуем ее в _texture_fill.

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;     } }

Функции «k» и «r» на каждую заданную единицу c рисуют два пикселя значением l и перемещаются вправо или влево на два пикселя и вниз на один — значит это функции рисования изометрических линий SW и SE. Переименуем их в _texture_linesw и _texture_linese.

На данный момент уже можно догадаться, что последняя функция «u» рисует линию вертикально вниз:

void u(int t, int x, int y, int c, int l) {     while (c--)         textures[t][y++][x] = l; }

Переименуем её в _texture_linedown.

Все отдельные функции прошли рефакторинг:

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */     MAPCHAR_EMPTY = ' ', /**< Пустой блок       (ASCII = 32) */ };  /*! \brief Содержит индексы текстур */ enum textures_indexes {     TEXINDEX_EMPTY = (0), /**< Индекс пустой текстуры                 */     TEXINDEX_MINUS = (1), /**< Индекс текстуры "выключенного провода" */     TEXINDEX_WIRE  = (2), /**< Индекс текстуры нейтрального провода   */     TEXINDEX_PLUS  = (3), /**< Индекс текстуры "включенного" провода  */     /**/     TEXINDEX_NOR   = (6), /**< Индекс текстуры NOR-элемента           */     TEXINDEX_HOLE  = (7)  /**< Индекс текстуры отверстия на плате     */ };  /*! \brief Аргументы программы */ enum program_arguments {      ARG_PROGRAM,  /**< Имя самой программы */     ARG_BLUEPRINT /**< Имя файла-чертежа   */ };  /*! \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 Зерно генератора случайных чисел */ int random = 2166136261;  /*! \brief Экземпляр дисплея Xlib */ Display * display; /*! \brief Экземпляр главного окна Xlib */ Window window; /*! \brief Изображение для вывода на экран */ XImage * image;  static void _texture_draw(int t, int x, int y);  /*! \brief Создает изображение и сопутствующие сущности */ static void _image_create(void) {     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); }  /* \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] elem Символ чертежа  * \return Индекс текстуры */ static int _map2texture(char elem) {     return ((elem >> 4) & 1) << 2 | (elem & 3); }  /*! \brief Собирает изображение из отдельных тайлов согласно карте */ static void _image_compile(void) {     for (int y = 0; y < MAP_HEIGHT; y++)         for (int x = 0; x < MAP_WIDTH; x++)             _texture_draw(_map2texture(mapdata[y][x]), x, y); }  /*! \brief Рисует изображение на экране */ static void _image_draw(void) {     XPutImage(display, window,                DefaultGC(display, DefaultScreen(display)),                image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);     XMapWindow(display, window);     XFlush(display); }  /*! \brief Рисует отверстия на печатной плате */ static void _image_drill(void) {     for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if ((x % 14 == 2) && (y % 4 == 3))                     _texture_draw(TEXINDEX_HOLE, x, y); }  /*! \brief Применяет шейдер LCD-эффекта на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_lcd(int x, int y) {     pixdata[y][x] &= 0xe0e0e0 | (31 << ((x % 3) << 3)); }  /*! \brief Применяет шейдер случайного шума на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_noise(int x, int y) {     pixdata[y][x] += 0x0f0f0f & (random *= 16777619); }  /*! \brief Накладывает на изображение различные эффекты */ static void _image_postprocess(void) {     for (int y = 0; y < IMAGE_HEIGHT; y++)         for (int x = 0; x < IMAGE_WIDTH; x++) {             _shader_lcd(x, y);             _shader_noise(x, y);         } }  /*! \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] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] source Исходный цвет  * \param[in] target Новый цвет */ static void _texture_fill(int t, int x, int y, int source, int target) {     if ((x >= TEXTURE_WIDTH || y >= TEXTURE_HEIGHT ||           x < 0 || y < 0) ||           (textures[t][y][x] == target) ||           (textures[t][y][x] != source))         return;     textures[t][y][x] = target;     _texture_fill(t, x - 1, y, source, target);     _texture_fill(t, x + 1, y, source, target);     _texture_fill(t, x, y - 1, source, target);     _texture_fill(t, x, y + 1, source, target); }  /*! \brief Рисует изометрическую линию по направлению SE  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии по короткой стороне  * \param[in] color Цвет рисования */ static void _texture_linese(int t, int x, int y, int c, int color) {     while (c--) {         textures[t][y][x++] = color;         textures[t][y++][x++] = color;     } }  /*! \brief Рисует изометрическую линию по направлению SW  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии по короткой стороне  * \param[in] color Цвет рисования */ static void _texture_linesw(int t, int x, int y, int c, int color) {     while (c--) {         textures[t][y][x--] = color;         textures[t][y++][x--] = color;     } }  /*! \brief Рисует линию вниз  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии  * \param[in] color Цвет рисования */ static void _texture_linedown(int t, int x, int y, int c, int color) {     while (c--)         textures[t][y++][x] = color; }  /*! \brief Читает данные файла-чертежа и загружает их в карту   * \param[in] filename Имя файла-чертежа */ static void _map_read(const char * filename) {     int f = open(filename, 0);     read(f, mapdata, MAP_FILEDATA);     close(f); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };  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 argc, char * args[]) {     _image_create();      for (int i = 0; i < 8; i++) {         char *p = z[i];         int c = 0;         while (*p != 4) {             switch (*p) {             case 0:                 _texture_linese(i, p[1], p[2], p[3], c);                 p += 4;                 break;             case 1:                 _texture_linesw(i, p[1], p[2], p[3], c);                 p += 4;                 break;             case 2:                 _texture_linedown(i, p[1], p[2], p[3], c);                 p += 4;                 break;             case 3:                 _texture_fill(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;             }         }     }     unsigned int counter = 1;     while (counter++) {         _map_read(args[ARG_BLUEPRINT]);         _map_wire_inputs();         _map_wire_counter(counter);         _map_process_gates();                  _image_reset();                   _image_compile();         _image_drill();         _image_postprocess();                 _image_draw();                  sleep(1);     }      return 0; } 

Векторная графика

Остался последний шаг — до конца разобраться, что же происходит в последнем, оставленном «на потом», switch-case:

    for (int i = 0; i < 8; i++) {         char *p = z[i];         int c = 0;         while (*p != 4) {             switch (*p) {             case 0:                 _texture_linese(i, p[1], p[2], p[3], c);                 p += 4;                 break;             case 1:                 _texture_linesw(i, p[1], p[2], p[3], c);                 p += 4;                 break;             case 2:                 _texture_linedown(i, p[1], p[2], p[3], c);                 p += 4;                 break;             case 3:                 _texture_fill(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;             }         }     }

Теперь, когда функции имеют новые, понятные, имена, можно сказать, что этот блок кода интерпретирует данные из массива «z», и согласно инструкциям, содержащимся в нем (например 0, 5, 5, 8, 2 — «нарисовать линию South-East, от [5,5] длиной 8 пикселей по краткой стороне цветом номер 2») рисует весь набор текстур.
Вроде бы всё понятно, но ни одного указания на цвет в программе замечено не было.

c = _x[p[1] / 4] - 1643277 * (p[1] % 4);

Ага, значит массив _x — это палитра, но в очень странном, «сжатом», формате.

int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };

Так как мы пока не знаем, сколько всего цветов используется в палитре (при установке цвета индекс как минимум делится на 4), переформатируем таблицу данных для отрисовки и группируем числа по категориям, заменив сигнатуры инструкций на константы:

Рефакторинг таблицы векторных инструкций

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */     MAPCHAR_EMPTY = ' ', /**< Пустой блок       (ASCII = 32) */ };  /*! \brief Содержит индексы текстур */ enum textures_indexes {     TEXINDEX_EMPTY = (0), /**< Индекс пустой текстуры                 */     TEXINDEX_MINUS = (1), /**< Индекс текстуры "выключенного провода" */     TEXINDEX_WIRE  = (2), /**< Индекс текстуры нейтрального провода   */     TEXINDEX_PLUS  = (3), /**< Индекс текстуры "включенного" провода  */     /**/     TEXINDEX_NOR   = (6), /**< Индекс текстуры NOR-элемента           */     TEXINDEX_HOLE  = (7)  /**< Индекс текстуры отверстия на плате     */ };  /*! \brief Список инструкций векторного интерпретатора */ enum textures_instructions {     TEXVEC_LINESE = (0), /**< Линия SE                          */     TEXVEC_LINESW = (1), /**< Линия SW                          */     TEXVEC_LINEDW = (2), /**< Линия вниз                        */     TEXVEC_FILL   = (3), /**< Заливка                           */     TEXVEC_EXIT   = (4), /**< Конец списка инструкций           */     TEXVEC_REPEAT = (5), /**< Повтор инструкций другой текстуры */     TEXVEC_COLOR  = (6)  /**< Выбор цвета                       */ };  /*! \brief Аргументы программы */ enum program_arguments {      ARG_PROGRAM,  /**< Имя самой программы */     ARG_BLUEPRINT /**< Имя файла-чертежа   */ };  /*! \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 Зерно генератора случайных чисел */ int random = 2166136261;  /*! \brief Экземпляр дисплея Xlib */ Display * display; /*! \brief Экземпляр главного окна Xlib */ Window window; /*! \brief Изображение для вывода на экран */ XImage * image;  /*! \brief Векторные инструкции для рисования текстур */ static const char * vecdata[TEXTURE_COUNT] = {      /* TEXINDEX_EMPTY */     (char[]) { TEXVEC_EXIT },      /* TEXINDEX_MINUS */     (char[]) { TEXVEC_COLOR,   5,            TEXVEC_LINESE, 32,  5, 16,                 TEXVEC_LINESE,  0, 21, 16,    TEXVEC_LINESW, 63, 21, 16,                 TEXVEC_LINEDW,  0, 21,  4,    TEXVEC_LINEDW, 31, 36,  4,                 TEXVEC_LINESW, 31,  5, 16,    TEXVEC_LINESE,  0, 24, 16,                 TEXVEC_LINESW, 63, 24, 16,    TEXVEC_LINEDW, 63, 21,  4,                 TEXVEC_LINEDW, 32, 36,  4,    TEXVEC_COLOR,   4,                 TEXVEC_FILL,   31, 8,         TEXVEC_COLOR,   6,                TEXVEC_FILL,   33, 38,        TEXVEC_COLOR,   7,                 TEXVEC_FILL,   30, 38,        TEXVEC_EXIT },     /* TEXINDEX_WIRE */     (char[]) { TEXVEC_REPEAT,  1 },      /* TEXINDEX_PLUS */     (char[]) { TEXVEC_COLOR,   1,            TEXVEC_LINESE, 32,  5, 16,                TEXVEC_LINESE,  0, 21, 16,    TEXVEC_LINESW, 63, 21, 16,                 TEXVEC_LINEDW, 63, 21,  4,    TEXVEC_LINEDW, 31, 36,  4,                 TEXVEC_LINESW, 31,  5, 16,    TEXVEC_LINESE,  0, 24, 16,                 TEXVEC_LINESW, 63, 24, 16,    TEXVEC_LINEDW, 63, 21,  4,                 TEXVEC_LINEDW, 32, 36,  4,    TEXVEC_COLOR,   0,                 TEXVEC_FILL,   31,  8,        TEXVEC_COLOR,   2,                TEXVEC_FILL,   33, 38,        TEXVEC_COLOR,   3,                 TEXVEC_FILL,   30, 38,        TEXVEC_EXIT },     /* Не используется */     (char[]) { TEXVEC_EXIT },      /* Не используется */     (char[]) { TEXVEC_EXIT },     /* TEXINDEX_NOR */     (char[]) { TEXVEC_COLOR,   9,            TEXVEC_LINESE, 32,  2, 16,                 TEXVEC_LINESE,  0, 18, 16,    TEXVEC_LINESW, 63, 18, 16,                 TEXVEC_LINEDW,  0, 18,  4,    TEXVEC_LINEDW, 31, 33,  4,                 TEXVEC_LINESW, 31,  2, 16,    TEXVEC_LINESE,  0, 21, 16,                 TEXVEC_LINESW, 63, 21, 16,    TEXVEC_LINEDW, 63, 18,  4,                 TEXVEC_LINEDW, 32, 33,  4,    TEXVEC_COLOR,   8,                TEXVEC_FILL,   31,  5,        TEXVEC_COLOR,  10,                  TEXVEC_FILL,   33, 35,        TEXVEC_COLOR,  11,                TEXVEC_FILL,   30, 35,        TEXVEC_EXIT },      /* TEXINDEX_HOLE */     (char[]) { TEXVEC_COLOR,  13,            TEXVEC_LINESE, 32, 9, 12,                 TEXVEC_LINESE,  8, 21, 12,    TEXVEC_LINESW, 31, 9, 12,                 TEXVEC_LINESW, 55, 21, 12,    TEXVEC_LINESE, 32, 12, 9,                 TEXVEC_LINESE, 14, 21,  9,    TEXVEC_LINESW, 31, 12, 9,                 TEXVEC_LINESW, 49, 21,  9,    TEXVEC_COLOR,  14,                 TEXVEC_LINEDW, 31, 13,  4,    TEXVEC_LINESW, 31, 16, 7,                 TEXVEC_FILL,   30, 14,        TEXVEC_COLOR,  12,                 TEXVEC_FILL,   32, 11,        TEXVEC_COLOR,  15,                 TEXVEC_LINEDW, 32, 13,  4,    TEXVEC_LINESE, 32, 16, 7,                 TEXVEC_FILL,   33, 14,        TEXVEC_COLOR,  16,                 TEXVEC_FILL,   31, 19,        TEXVEC_EXIT } };  static void _texture_draw(int t, int x, int y);  /*! \brief Создает изображение и сопутствующие сущности */ static void _image_create(void) {     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); }  /* \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] elem Символ чертежа  * \return Индекс текстуры */ static int _map2texture(char elem) {     return ((elem >> 4) & 1) << 2 | (elem & 3); }  /*! \brief Собирает изображение из отдельных тайлов согласно карте */ static void _image_compile(void) {     for (int y = 0; y < MAP_HEIGHT; y++)         for (int x = 0; x < MAP_WIDTH; x++)             _texture_draw(_map2texture(mapdata[y][x]), x, y); }  /*! \brief Рисует изображение на экране */ static void _image_draw(void) {     XPutImage(display, window,                DefaultGC(display, DefaultScreen(display)),                image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);     XMapWindow(display, window);     XFlush(display); }  /*! \brief Рисует отверстия на печатной плате */ static void _image_drill(void) {     for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if ((x % 14 == 2) && (y % 4 == 3))                     _texture_draw(TEXINDEX_HOLE, x, y); }  /*! \brief Применяет шейдер LCD-эффекта на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_lcd(int x, int y) {     pixdata[y][x] &= 0xe0e0e0 | (31 << ((x % 3) << 3)); }  /*! \brief Применяет шейдер случайного шума на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_noise(int x, int y) {     pixdata[y][x] += 0x0f0f0f & (random *= 16777619); }  /*! \brief Накладывает на изображение различные эффекты */ static void _image_postprocess(void) {     for (int y = 0; y < IMAGE_HEIGHT; y++)         for (int x = 0; x < IMAGE_WIDTH; x++) {             _shader_lcd(x, y);             _shader_noise(x, y);         } }  /*! \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] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] source Исходный цвет  * \param[in] target Новый цвет */ static void _texture_fill(int t, int x, int y, int source, int target) {     if ((x >= TEXTURE_WIDTH || y >= TEXTURE_HEIGHT ||           x < 0 || y < 0) ||           (textures[t][y][x] == target) ||           (textures[t][y][x] != source))         return;     textures[t][y][x] = target;     _texture_fill(t, x - 1, y, source, target);     _texture_fill(t, x + 1, y, source, target);     _texture_fill(t, x, y - 1, source, target);     _texture_fill(t, x, y + 1, source, target); }  /*! \brief Рисует изометрическую линию по направлению SE  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии по короткой стороне  * \param[in] color Цвет рисования */ static void _texture_linese(int t, int x, int y, int c, int color) {     while (c--) {         textures[t][y][x++] = color;         textures[t][y++][x++] = color;     } }  /*! \brief Рисует изометрическую линию по направлению SW  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии по короткой стороне  * \param[in] color Цвет рисования */ static void _texture_linesw(int t, int x, int y, int c, int color) {     while (c--) {         textures[t][y][x--] = color;         textures[t][y++][x--] = color;     } }  /*! \brief Рисует линию вниз  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии  * \param[in] color Цвет рисования */ static void _texture_linedown(int t, int x, int y, int c, int color) {     while (c--)         textures[t][y++][x] = color; }  /*! \brief Читает данные файла-чертежа и загружает их в карту   * \param[in] filename Имя файла-чертежа */ static void _map_read(const char * filename) {     int f = open(filename, 0);     read(f, mapdata, MAP_FILEDATA);     close(f); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  /* Код до рефакторинга */  int _x[] = { 15117427, 8413248, 5878632, 13027014, 1 };  int main(int argc, char * args[]) {     _image_create();      for (int tex = 0; tex < TEXTURE_COUNT; tex++) {         char * ptr = vecdata[tex];         int c = 0;         while (*ptr != TEXVEC_EXIT) {             switch (*ptr) {             case TEXVEC_LINESE:                 _texture_linese(tex, ptr[1], ptr[2], ptr[3], c);                 ptr += 4;                 break;             case TEXVEC_LINESW:                 _texture_linesw(tex, ptr[1], ptr[2], ptr[3], c);                 ptr += 4;                 break;             case TEXVEC_LINEDW:                 _texture_linedown(tex, ptr[1], ptr[2], ptr[3], c);                 ptr += 4;                 break;             case TEXVEC_FILL:                 _texture_fill(tex, ptr[1], ptr[2], 0, c);                 ptr += 3;                 break;             case TEXVEC_REPEAT:                 ptr = vecdata[ptr[1]];                 break;             case TEXVEC_COLOR:                 c = _x[ptr[1] / 4] - 1643277 * (ptr[1] % 4);                 ptr += 2;                 break;             }         }     }     unsigned int counter = 1;     while (counter++) {         _map_read(args[ARG_BLUEPRINT]);         _map_wire_inputs();         _map_wire_counter(counter);         _map_process_gates();                  _image_reset();                   _image_compile();         _image_drill();         _image_postprocess();                 _image_draw();                  sleep(1);     }      return 0; } 

Максимальное число, которое стоит после инструкции «TEXVEC_COLOR» — это 16. Напишем простейший код, чтобы получить всю таблицу:

Теперь, имея на руках палитру в расшифрованном виде мы можем заменить функцию её использования и написать расшифровки для цветов в константной таблице, а заодно и выделить функцию создания текстур:

Полный код после рефакторинга:

#include <X11/Xlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>  /* Код после рефакторинга */  /*! \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 Количество итераций во время расчета NOR-узлов */ #define MAP_ITERATIONS (20)  /*! \brief Содержит структуры синтаксиса файла-конфигурации */ enum map_characters {     MAPCHAR_WIRE  = '.', /**< Провод            (ASCII = 46) */     MAPCHAR_PLUS  = '+', /**< Провод (есть ток) (ASCII = 43) */     MAPCHAR_MINUS = '-', /**< Провод (нет тока) (ASCII = 45) */     MAPCHAR_NOR   = '>', /**< NOR-элемент       (ASCII = 62) */     MAPCHAR_EMPTY = ' ', /**< Пустой блок       (ASCII = 32) */ };  /*! \brief Содержит индексы текстур */ enum textures_indexes {     TEXINDEX_EMPTY = (0), /**< Индекс пустой текстуры                 */     TEXINDEX_MINUS = (1), /**< Индекс текстуры "выключенного провода" */     TEXINDEX_WIRE  = (2), /**< Индекс текстуры нейтрального провода   */     TEXINDEX_PLUS  = (3), /**< Индекс текстуры "включенного" провода  */     /**/     TEXINDEX_NOR   = (6), /**< Индекс текстуры NOR-элемента           */     TEXINDEX_HOLE  = (7)  /**< Индекс текстуры отверстия на плате     */ };  /*! \brief Список инструкций векторного интерпретатора */ enum textures_instructions {     TEXVEC_LINESE = (0), /**< Линия SE                          */     TEXVEC_LINESW = (1), /**< Линия SW                          */     TEXVEC_LINEDW = (2), /**< Линия вниз                        */     TEXVEC_FILL   = (3), /**< Заливка                           */     TEXVEC_EXIT   = (4), /**< Конец списка инструкций           */     TEXVEC_REPEAT = (5), /**< Повтор инструкций другой текстуры */     TEXVEC_COLOR  = (6)  /**< Выбор цвета                       */ };  /*! \brief Аргументы программы */ enum program_arguments {      ARG_PROGRAM,  /**< Имя самой программы */     ARG_BLUEPRINT /**< Имя файла-чертежа   */ };  /*! \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 Зерно генератора случайных чисел */ int random = 2166136261;  /*! \brief Экземпляр дисплея Xlib */ Display * display; /*! \brief Экземпляр главного окна Xlib */ Window window; /*! \brief Изображение для вывода на экран */ XImage * image;  /*! \brief Палитра цветов для векторной отрисовки   * \note Черный имеет цвет {001} для отличия от "прозрачного" черного {000} */ static const int texturepalette[] = {                           /*  Светлее   ▁▁▂▂▃▃▄▄▅▅▆▆▇▇██   Темнее */         /* Светло-коричневый */ 0xe6ac73, 0xcd9966, 0xb48659, 0x9b734c,     /* Темно-коричневый  */ 0x806040, 0x674d33, 0x4e3a26, 0x352719,     /* Зеленый           */ 0x59b368, 0x40a05b, 0x278d4e, 0x0e7a41,     /* Серый             */ 0xc6c6c6, 0xadb3b9, 0x94a0ac, 0x7b8d9f,     /* Черный            */ 0x000001 };  /*! \brief Векторные инструкции для рисования текстур */ static const char * vecdata[TEXTURE_COUNT] = {      /* TEXINDEX_EMPTY */     (char[]) { TEXVEC_EXIT },      /* TEXINDEX_MINUS */     (char[]) { TEXVEC_COLOR,   5,            TEXVEC_LINESE, 32,  5, 16,                 TEXVEC_LINESE,  0, 21, 16,    TEXVEC_LINESW, 63, 21, 16,                 TEXVEC_LINEDW,  0, 21,  4,    TEXVEC_LINEDW, 31, 36,  4,                 TEXVEC_LINESW, 31,  5, 16,    TEXVEC_LINESE,  0, 24, 16,                 TEXVEC_LINESW, 63, 24, 16,    TEXVEC_LINEDW, 63, 21,  4,                 TEXVEC_LINEDW, 32, 36,  4,    TEXVEC_COLOR,   4,                 TEXVEC_FILL,   31, 8,         TEXVEC_COLOR,   6,                TEXVEC_FILL,   33, 38,        TEXVEC_COLOR,   7,                 TEXVEC_FILL,   30, 38,        TEXVEC_EXIT },     /* TEXINDEX_WIRE */     (char[]) { TEXVEC_REPEAT,  1 },      /* TEXINDEX_PLUS */     (char[]) { TEXVEC_COLOR,   1,            TEXVEC_LINESE, 32,  5, 16,                TEXVEC_LINESE,  0, 21, 16,    TEXVEC_LINESW, 63, 21, 16,                 TEXVEC_LINEDW, 63, 21,  4,    TEXVEC_LINEDW, 31, 36,  4,                 TEXVEC_LINESW, 31,  5, 16,    TEXVEC_LINESE,  0, 24, 16,                 TEXVEC_LINESW, 63, 24, 16,    TEXVEC_LINEDW, 63, 21,  4,                 TEXVEC_LINEDW, 32, 36,  4,    TEXVEC_COLOR,   0,                 TEXVEC_FILL,   31,  8,        TEXVEC_COLOR,   2,                TEXVEC_FILL,   33, 38,        TEXVEC_COLOR,   3,                 TEXVEC_FILL,   30, 38,        TEXVEC_EXIT },     /* Не используется */     (char[]) { TEXVEC_EXIT },      /* Не используется */     (char[]) { TEXVEC_EXIT },     /* TEXINDEX_NOR */     (char[]) { TEXVEC_COLOR,   9,            TEXVEC_LINESE, 32,  2, 16,                 TEXVEC_LINESE,  0, 18, 16,    TEXVEC_LINESW, 63, 18, 16,                 TEXVEC_LINEDW,  0, 18,  4,    TEXVEC_LINEDW, 31, 33,  4,                 TEXVEC_LINESW, 31,  2, 16,    TEXVEC_LINESE,  0, 21, 16,                 TEXVEC_LINESW, 63, 21, 16,    TEXVEC_LINEDW, 63, 18,  4,                 TEXVEC_LINEDW, 32, 33,  4,    TEXVEC_COLOR,   8,                TEXVEC_FILL,   31,  5,        TEXVEC_COLOR,  10,                  TEXVEC_FILL,   33, 35,        TEXVEC_COLOR,  11,                TEXVEC_FILL,   30, 35,        TEXVEC_EXIT },      /* TEXINDEX_HOLE */     (char[]) { TEXVEC_COLOR,  13,            TEXVEC_LINESE, 32, 9, 12,                 TEXVEC_LINESE,  8, 21, 12,    TEXVEC_LINESW, 31, 9, 12,                 TEXVEC_LINESW, 55, 21, 12,    TEXVEC_LINESE, 32, 12, 9,                 TEXVEC_LINESE, 14, 21,  9,    TEXVEC_LINESW, 31, 12, 9,                 TEXVEC_LINESW, 49, 21,  9,    TEXVEC_COLOR,  14,                 TEXVEC_LINEDW, 31, 13,  4,    TEXVEC_LINESW, 31, 16, 7,                 TEXVEC_FILL,   30, 14,        TEXVEC_COLOR,  12,                 TEXVEC_FILL,   32, 11,        TEXVEC_COLOR,  15,                 TEXVEC_LINEDW, 32, 13,  4,    TEXVEC_LINESE, 32, 16, 7,                 TEXVEC_FILL,   33, 14,        TEXVEC_COLOR,  16,                 TEXVEC_FILL,   31, 19,        TEXVEC_EXIT } };  static void _texture_draw(int t, int x, int y);  /*! \brief Создает изображение и сопутствующие сущности */ static void _image_create(void) {     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); }  /* \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] elem Символ чертежа  * \return Индекс текстуры */ static int _map2texture(char elem) {     return ((elem >> 4) & 1) << 2 | (elem & 3); }  /*! \brief Собирает изображение из отдельных тайлов согласно карте */ static void _image_compile(void) {     for (int y = 0; y < MAP_HEIGHT; y++)         for (int x = 0; x < MAP_WIDTH; x++)             _texture_draw(_map2texture(mapdata[y][x]), x, y); }  /*! \brief Рисует изображение на экране */ static void _image_draw(void) {     XPutImage(display, window,                DefaultGC(display, DefaultScreen(display)),                image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);     XMapWindow(display, window);     XFlush(display); }  /*! \brief Рисует отверстия на печатной плате */ static void _image_drill(void) {     for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if ((x % 14 == 2) && (y % 4 == 3))                     _texture_draw(TEXINDEX_HOLE, x, y); }  /*! \brief Применяет шейдер LCD-эффекта на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_lcd(int x, int y) {     pixdata[y][x] &= 0xe0e0e0 | (31 << ((x % 3) << 3)); }  /*! \brief Применяет шейдер случайного шума на изображение  * \param[in] x X-координата изображения  * \param[in] y Y-координата изображения */ static void _shader_noise(int x, int y) {     pixdata[y][x] += 0x0f0f0f & (random *= 16777619); }  /*! \brief Накладывает на изображение различные эффекты */ static void _image_postprocess(void) {     for (int y = 0; y < IMAGE_HEIGHT; y++)         for (int x = 0; x < IMAGE_WIDTH; x++) {             _shader_lcd(x, y);             _shader_noise(x, y);         } }  /*! \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] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] source Исходный цвет  * \param[in] target Новый цвет */ static void _texture_fill(int t, int x, int y, int source, int target) {     if ((x >= TEXTURE_WIDTH || y >= TEXTURE_HEIGHT ||           x < 0 || y < 0) ||           (textures[t][y][x] == target) ||           (textures[t][y][x] != source))         return;     textures[t][y][x] = target;     _texture_fill(t, x - 1, y, source, target);     _texture_fill(t, x + 1, y, source, target);     _texture_fill(t, x, y - 1, source, target);     _texture_fill(t, x, y + 1, source, target); }  /*! \brief Рисует изометрическую линию по направлению SE  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии по короткой стороне  * \param[in] color Цвет рисования */ static void _texture_linese(int t, int x, int y, int c, int color) {     while (c--) {         textures[t][y][x++] = color;         textures[t][y++][x++] = color;     } }  /*! \brief Рисует изометрическую линию по направлению SW  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии по короткой стороне  * \param[in] color Цвет рисования */ static void _texture_linesw(int t, int x, int y, int c, int color) {     while (c--) {         textures[t][y][x--] = color;         textures[t][y++][x--] = color;     } }  /*! \brief Рисует линию вниз  * \param[in] t Индекс текстуры  * \param[in] x X-координата начала  * \param[in] y Y-координата начала  * \param[in] c Длина линии  * \param[in] color Цвет рисования */ static void _texture_linedown(int t, int x, int y, int c, int color) {     while (c--)         textures[t][y++][x] = color; }  /*! \brief Создает все текстуры, интерпретатор векторных инструкций */ static void _textures_create(void) {     for (int tex = 0; tex < TEXTURE_COUNT; tex++) {         const char * ptr = vecdata[tex];         int c = 0;         while (*ptr != TEXVEC_EXIT) {             switch (*ptr) {             case TEXVEC_LINESE:                 _texture_linese(tex, ptr[1], ptr[2], ptr[3], c);                 ptr += 4;                 break;                              case TEXVEC_LINESW:                 _texture_linesw(tex, ptr[1], ptr[2], ptr[3], c);                 ptr += 4;                 break;                              case TEXVEC_LINEDW:                 _texture_linedown(tex, ptr[1], ptr[2], ptr[3], c);                 ptr += 4;                 break;                              case TEXVEC_FILL:                 _texture_fill(tex, ptr[1], ptr[2], 0, c);                 ptr += 3;                 break;                              case TEXVEC_REPEAT:                 ptr = vecdata[ptr[1]];                 break;                              case TEXVEC_COLOR:                 c = texturepalette[ptr[1]];                 ptr += 2;                 break;             }         }     } }  /*! \brief Читает данные файла-чертежа и загружает их в карту   * \param[in] filename Имя файла-чертежа */ static void _map_read(const char * filename) {     int f = open(filename, 0);     read(f, mapdata, MAP_FILEDATA);     close(f); }  /*! \brief Заменяет иллюстративные входы из файла-конфигурации на вход  * в виде провода чтобы работала логика распространения фронта волны */ static void _map_wire_inputs(void) {     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] = MAPCHAR_WIRE; }  /*! \brief Производит заливку проводника нужным состоянием  * \param[in] t Игнорируется, артефакт автогенерации кода   * \param[in] x X-координата заливки  * \param[in] y Y-координата заливки  * \param[in] c Исходное состояние  * \param[in] l Целевое состояние */ static void _map_fill(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;     _map_fill(t, x - 1, y, c, l);     _map_fill(t, x + 1, y, c, l);     _map_fill(t, x, y - 1, c, l);     _map_fill(t, x, y + 1, c, l); }  /*! \brief Включает соответствующие входы схемы в зависимости от значения  * счетчика.  * \param[in] counter Счетчик */ static void _map_wire_counter(int counter) {     _map_fill(0, 2, 3,  mapdata[3][2],  counter & 1 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 7,  mapdata[7][2],  counter & 2 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 11, mapdata[11][2], counter & 4 ? MAPCHAR_PLUS : MAPCHAR_MINUS);     _map_fill(0, 2, 15, mapdata[15][2], counter & 8 ? MAPCHAR_PLUS : MAPCHAR_MINUS); }  /*! \brief Проводит расчет выходного (результирующего) тока после NOR-узла */ static void _map_process_gates(void) {            for (int i = 0; i < MAP_ITERATIONS; i++)         for (int y = 0; y < MAP_HEIGHT; y++)             for (int x = 0; x < MAP_WIDTH; x++)                 if (mapdata[y][x] == MAPCHAR_NOR)                     _map_fill(0, x + 1, y, mapdata[y][x + 1],                         !(mapdata[y - 1][x] == MAPCHAR_PLUS ? 1 : 0                        || mapdata[y + 1][x] == MAPCHAR_PLUS ? 1 : 0) ?                              MAPCHAR_PLUS : MAPCHAR_MINUS); }  int main(int argc, char * args[]) {     _image_create();     _textures_create();          unsigned int counter = 1;     while (counter++) {         _map_read(args[ARG_BLUEPRINT]);         _map_wire_inputs();         _map_wire_counter(counter);         _map_process_gates();                  _image_reset();                   _image_compile();         _image_drill();         _image_postprocess();                 _image_draw();                  sleep(1);     }      return 0; } 

Эпилог

Вот и всё. Несмотря на то, что я не занял никаких призовых мест, это был достаточно любопытный опыт (умерший за два дня до начала приема работ HDD этому поспособствовал). Было что-то неправильное в том, чтобы писать код, максимально не читаемый и одновременно абсолютно валидный с точки зрения языка. Однако нельзя сказать, что это было неинтересно. Когда утилита, подсчитывающая токены говорит, что код нарушает правила превышая лимит на 2000+ токенов, а ты не знаешь, как его сократить — это вызов. Когда размер файла превышает лимиты, а ты хочешь добавить какой-то графический эффект — это вызов. Это было трудно, вместить столько функционала, и тем слаще было читать вывод утилиты, которая после нескольких сотен исправлений наконец-таки сказала, что код можно выгружать. Я бы порекомендовал читателям поучаствовать в конкурсе хотя бы просто для того, чтобы приобщиться и испытать свои силы. Да, никаких наград или призов это не дает, но зато вы будете знать, что под ником zhestokyshveller на сайте IOCCC скрываетесь вы.

ссылка на оригинал статьи https://habr.com/ru/post/516296/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *