use16 ;16-битные коды.
org 100h ;.com-файл.
up_key:
scasb ;Сравнивает значение в al и в ячейке памяти es:di. Увеличивает значение регистра di.
int 10h ;Установка текстового видеорежима 25 строк по 40 символов в каждой.
left_key:
cld ;Сброс флага направления, т.е. df=0, поэтому обработка строк идёт слева направо.
right_key:
push 0b800h ;Помещение адреса начала текстового видеобуфера в стек для дальнейшего его присвоения регистру es.
inc di ;?
down_key:
dec si ;?
pop es ;Помещение адреса начала видеобуфера в регистр es.
int 1ah ;Считываем количество тиков после 00 часов в регистры cx:dx. 18.2 тика в секунду, 1800b0h тиков в сутках. Также обнуляется регистр ax.
xchg ax,bp ;Обнуляем регистр bp.
inc dl ;Прибавляем 1 тик.
score:
mov si,0 ;Обнуляем регистр si. Он будет выполнять роль счётчика очков.
mov cx,40*25*2 - 2 ;Вычисляем значение предпоследней текстовой области экрана.
mov fs,cx ;Заносим это значение в регистр fs.
jmp add_food ;Безусловный переход к метке add_food.
; bp = dir
; fs:bx = head
; fs:si = tail
; cx = 1998
; dl = time
main_loop:
mov ax,es
push di ;Сохраняем значение di.
mov di,word [fs:si]
stosb ;Записывает al в ячейку памяти es:di, увеличивает di на 2.
stosb ;Записывает al в ячейку памяти es:di, увеличивает di на 2.
cmpsw ;si += 2, di += 2
pop di ;Возвращаем значение di.
add di,bp
cmp di,cx
ja exit_point
mov word [fs:bx],di
inc bx
inc bx
cmp ah,[es:di+1]
stosw
ja no_eat
je exit_point
add_food:
dec si ;?
dec si ;?
pusha ;Cохраняем значения всех регистров.
mov di,score+1 ;Чтение байта по адресу score+1, т.е. 0.
mov bx,word [score+1] ;Заноси в bx слово по адресу score+1.
inc word [di] ;Прибавляем 1 очко к общему счёту и заносим в регистр di.
mov di,cx
score_loop: ;Вывод столбца с количеством набранных очков.
shr bx,1 ;Сдвиг bx на 1 бит вправо.
mov ax,es ;
adc al,'0' ;Сложение с учётом флага переноса.
stosw ;Записывает ax по адресу es:di и увеличивает значение di на размер ax, т.е. на 4.
sub di,82 ;Вычитает из адреса 82 байта, т.е. 4 байта от предыдущей команды и 78 байт за счёт строки.
jns score_loop ;Продолжает делать весь цикл команд пока значение положительное, т.е. пока не кончатся строки.
try_place: ;Выбирает место и выводит еду.
in ax,40h ;Вводит из порта 40h один байт в ax. Используется для рандомного адреса новой ячейки с едой.
add ax,ax ;Удваивает. Также используется для рандомизации.
cwd ;Опять же ради радомизации. Копирует значение старшего бита ax на все биты регистры dx, т.е. преобразует слово в двойное слово.
div cx ;Делим ax на cx. Частное в al, остаток в ah.
mov di,dx ;Заносим в di рандомное значение из dx.
cmp word [es:di],sp ;Сравнивается с вершиной стека, чтобы ячейка с новой едой попадала в видеобуфер
jl try_place ;Если не больше или равно, то переход обратно на метку try_place.
mov ah,0cfh ;Цвет внутри появившейся еды.
stosw ;Записывает al по адресу es:di.
popa ;Возвращаем все регистры в начальные значения.
no_eat:
delay:
cmp dl,[gs:46Ch] ;Предыдущее значение системного таймера.
jne delay ;Если не равно нулю, то повторяем.
add dl,4 ;Количество тиков задержки. Чем меньше, тем быстрее будет двигаться змейка.
mov ah,1 ;\
int 16h ;-Проверка готовности символа в al к выводу.
jz main_loop ;Если равно нулю, то направляемся в main_loop.
cbw ;Преобразует al в слово ax.
int 16h ;Считывает нажатую клавишу.
movzx bp,ah ;
movsx bp,byte[bp+100h-72]
cmp al,0 ;Сравнивает.
je main_loop ;Если равно, то отправляет в main_loop.
exit_point:
ret
Первоисточник [pause] как Вы думаете где? Правильно [/pause] в Интернете...