Pull to refresh
65
0
Евгений Красников @jin_x

Разработчик ПО, вокалист, ивентор, хороший человек

Send message

Отличная идея! Самому нужна такая прога, а писать было в лом :)

Хорошо бы ещё добавить возможность использования прокси для отслеживания зарубежных сайтов (типа intel.com).

Про алгоритм лучше спросить у автора. Он доступен в Discord (ссылка есть в статье про radar).

Могу сказать только, что после adc al,0x10 на первой итерации int 0x10 выполняет установку 16-цветового EGA видеорежима 640x320, а на следующих выводит точку через функцию ah=0x0C, цвет которой каждый раз меняется c помощью всё той же инструкции adc al,0x10.

Добавлена 45-байтовая версия змейки (в спойлере в конце статьи) :)

Адрес SS:BP+SI указывает на голову змеи. Т.е. по этому адресу лежит "координата" головы (если точнее, то смещение адреса в сегменте DS, соответствующего цвету символа; для простоты я буду называть это координатой). После чтения скан-кода клавиши и преобразования его в смещение координаты (-2 / 2 / -80 / 80) мы добавляем к этому значению координату головы, получая т.о. новую координату. Далее эта координата записывается в SS:BP+SI, сдвигая всё остальное далее по массиву.

Например, длина (CX) = 5. В массиве (по адресу SS:BP+SI) были такие слова: [11] [13] [15] [17] [19] (на самом деле прямо таких значений не будет, но для простоты пусть будет так, можете мысленно прибавить к этим числам 64000). Мы нажали вниз (80), получили новую координату: 80+11=91, новый массив будет таким: [91] [11] [13] [15] [17].

При этом мы рисуем только голову (91) и затираем хвост (19). При съедании яблока после вышеуказанной процедуры длина увеличивается на 2, и на следующем кадре будет так: [171] [91] [11] [13] [15] [17] [мусор]. В этот раз мы затираем (один раз) "мусорную" координату. В теории, это может быть координата на экране, т.е. мы можем затереть какое-то яблоко, часть себя или даже нарисовать на экране более жирную точку, если координата окажется чётной (символ с кодом 7, т.к. мы затираем хвост цветом 7). Если присмотреться к скриншоту, то можно увидеть, что внизу есть более жирная точка. Этот артефакт — как раз результат такого "удаления" несуществующего хвоста с мусорной координатой, которая оказалась чётной и попала в экран.

Этот глюк можно убрать, добавив инструкцию mov [bp+si],cx после loop, но это +2 байта (хотя можно всё равно уложиться в 64 байта, убрав звуковой щелчок out $61,al). Но тут всё равно нет 100% гарантии, что первые 5 (начальная длина змейки) координат не попадут в экран (а эти координаты исходно мусорные). Нужно добавлять ещё несколько байт в начало кода для их очистки. Но и в этом случае можно уложиться в 64 байта, если прибавлять длину змейки на 1, т.к. мусорной координаты при увеличении длины не будет, и mov [bp+si],cx здесь уже будет не нужен + кол-во inc cx уменьшится на 1 шт + можно до кучи убрать удаление курсора.

P. S. Обычно сдвиг массива "вперёд" делается с конца назад (чтобы не затереть самого себя), но используя xchg можно делать это, двигаясь с начала вперёд (как здесь).

Нет, меня там не было ?‍♂

KolibriOS — тоже магия ассемблерного искусства.

На SSE/AVX даже синус так просто не вычислишь (особенно в упакованном формате) :)

Сайзкодинг, кстати, как правило, имеет одну важную особенность: необходимо не просто ужать код насколько это возможно, а привести его к целевому размеру (64, 256 байт и т.д.).

В гольфкодинге люди соревнуются в стиле "у кого меньше, тот и молодец" :)

Да, сайзкодинг — это оптимизация по размеру бинарника, а гольфкодинг — по размеру исходника. Это тоже прикольная штука, я пару раз участвовал (например, тут на C).

В демосцене есть платформы, называемые фэнтези консолями (например, TIC-80, MicroW8 и пр.) Так вот, в TIC-80 исходник не компилируется и хранится в файле в сжатом (заархивированном) виде. По сути, такой сайзкодинг отчасти правильнее назвать гольфкодингом, т.к. чем меньше исходник, тем меньше и сжатый файл. В общем случае. Хотя иногда увеличение размера исходного кода (ради того, чтобы в нём были повторяющиеся символы) может привести к уменьшению сжатого файла. Поэтому я написал "отчасти" :)

Не оГРаничен, а оРГаничен :))

Правила звука не требуют, но место есть, почему бы и нет? С другой стороны, если его убрать, можно сделать выход. Или что-нибудь ещё (всё-таки 5 байт — не шуточки).

При этом плавность оставляет желать лучшего.

Но это ещё цветочки. Иногда видосы 256-байтовых интро занимают сотни мегабайт, имея при этом артефакты компрессии.

В некотором степени интро является очень хорошо сжатым самораспаковывающимся видеофайлом :)

Разве он не органичен в данном случае?

farbrausch — это легенда :)

Если "шитый байткод", тогда это было бы "threaded bytecode", а это "байтовый шитый код", ну или см. ниже ещё вариант.

Да, вполне. Или даже ещё проще: "Байтовый шитый код", но оригинальное название рядом нужно оставить обязательно.

Есть while, значит можно и do-while сделать. С for и switch сложно, в 30 байт вряд ли влезет. Массивы тоже вряд ли. Вот return ещё можно попробовать, вероятно.

Я ради прикола попытался сократить немного код, получилось ужать его на 6 байт. Профит небольшой, конечно, но в целом там есть ещё порядка 30 байт на какие-нибудь фичи типа операторов / ! ~ break continue do-while ... чего там ещё нет? :)

Есть ещё один интересный способ. Не лучше и не хуже других. Так же, как и "вот и песенке конец". Для кого-то лучше сработает одно, для кого-то - другое.

Суть в том, чтобы укорачивать повторяемый фрагмент, начиная, например, сразу с 1 секунды и до тех пор, пока это не превратится в монотонный звук (монотонный - не в смысле одного чистого тона, а в смысле очень короткого фрагмента, условно говоря, длиной в 1-10 миллисекунд). Потом резко оборвать его. Вся процедура может занимать секунды 3. Если мелодия снова всплывает (обычно не сразу), повторить. И так несколько раз. Повторять можно сразу с этого монотонного звука.

Мне вот тоже интересно, каков реальный профит будет от этого в чём?

В wait мы передаем заблокированный std::unique_lockwait снимает временно блокировку и усыпает (не всегда: когда предикат в wait истинный может и не уснуть).

Подкорректирую последовательность операций.

Wait сначала проверяет предикат (если он есть), а потом уже снимает блокировку и начинает принимать уведомления, усыпляя поток. Причём, делает это фактически атомарно (т.е. между снятием блокировки и началом приёма уведомлений другой поток вклиниться не может – это тоже важно). После пробуждения устанавливает блокировку обратно (здесь тоже обычно есть оптимизация, из-за которой рекомендуют notify ставить перед unlock'ом) и снова идёт на проверку предиката.

Если предикат есть и возвращает true, никаких unlock'ов не будет.

Information

Rating
5,055-th
Location
Самарская обл., Россия
Date of birth
Registered
Activity

Specialization

Software Developer, Backend Developer