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] в Интернете...