format binary as "img" flag = 1 ;1 = write/read in video buffer procedure ;2 = inline bios servis opt = 2 ;0 - off optimization ;1 - on optimization ;2 - write/read bios servis READ equ 0 WRITE equ 1 org 7C00h ; адреса нашей программы расчитываются с учетом данной директивы use16 ; генерируется шестнадцатиричный код cli ;запрещаем прерывания для смены адресов в сегментных регистрах mov ax, 0 mov ss, ax mov sp, 7C00h mov ax, 0B800h mov es, ax sti ;start: mov ax,0001h int 10h ;Очищаем игровое поле mov ah, 01h mov cx, 2000h ;скрыть курсор int 10h ; mov cx,5 ;для экономии можно отключить ; mov ax,0ADBh ;8 байт ; int 10h ;Выводим змейку из 5 символов квадрат;"*" mov si,8 ;Индекс координаты символа головы xor di,di ;Индекс координаты символа хвоста mov cx,0001h ;Регистр cx используем для управления головой. ;Приращение в cx, будет изменяться координата x или y xor bh,bh ;тут видео страница для bios call add_food main: ;Основной цикл ;call add_food ;для экспериментов над рандомайзером call delay call key_press xor bh,bh ;номер видео страницы mov ax,[snake+si] ;Берем координату головы из памяти add ax,cx ;Изменяем координату x inc si inc si cmp si,3E2h ;проверка конца буфера для головы jne nex xor si,si nex: mov [snake+si],ax ;Заносим в память новую координату головы змеи mov dx,ax if flag=2 mov ax,0200h int 10h ; Перемещаем курсор mov ax,0800h int 10h ;Читает символ call game_over mov dl,al ;после проверки перемещает симовл push cx mov ax,0ADBh ;рисуем голову символ квадрат mov cx,1 int 10h pop cx end if if flag =1 mov bl,READ call write_read ;Читает символ ;в ax атрибуты/символ call game_over push ax ;сохраняем символ ; mov ax,07DBh mov bl,WRITE call write_read ;рисуем голову символ квадрат pop dx ;восстанавливаем символ end if cmp dl,24h ;если скушали еду продолжаем выполнять jne next ;переход если не съели push cx ;В стек регистр mov cx,[tick] inc cx cmp cx,5 jne exl ;продолжаем выполнять если съели 5 раз xor cx,cx mov dx,[snake+di-2] ;в dx координата хвоста, где будет какашка if flag=2 mov ax,0200h int 10h ;ставим курсор push cx mov ax,0A40h ;рисуем какашку mov cx,1 int 10h pop cx end if if flag=1 mov ax,0440h mov bl,WRITE call write_read ;рисуем какашку end if exl:mov [tick],cx pop cx call add_food ;после того как съели еду, рисуем новую jmp main ;хвост не рисуется/удлиняется, т.к. съели next: ;попали сюда т.к. ничего не съели mov dx,[snake+di] if flag=2 mov ax,0200h int 10h push cx mov ax,0A20h ;Выводим пробел, тем самым удаляя хвост mov cx,1 int 10h pop cx end if if flag=1 mov ax,0020h mov bl,WRITE ;Выводим пробел, тем самым удаляя хвост call write_read end if inc di inc di cmp di,3E4h ;проверка конца буфера для хвоста jne main xor di,di jmp main ;end start ;============================= delay: push cx mov ah,0 int 1Ah add dx,3 mov bx,dx @@: int 1Ah cmp dx,bx jl @b pop cx ret ;endp ;===================================== key_press: mov ax, 0100h int 16h jz en ;Без нажатия выходим xor ah, ah int 16h cmp ah, 50h jne up cmp cx,0FF00h ;Сравниваем чтобы не пойти на себя je en mov cx,0100h jmp en up: cmp ah,48h jne left cmp cx,0100h je en mov cx,0FF00h jmp en left: cmp ah,4Bh jne right cmp cx,0001h je en mov cx,0FFFFh jmp en right: cmp cx,0FFFFh je en mov cx,0001h en: ret ;endp ;==================================== add_food: mov bl,40 call rnd mov dl,al ;Запись координаты mov bl,25 call rnd mov dh,al ;Запись координаты if flag=2 mov ax,0200h int 10h ;уст. позицию курсора mov ax,0800h int 10h ;читать символ/атрибут в текущей позиции курсора cmp al,0DBh ;Проверяем пустое ли место;????? вставить al - там символ je add_food cmp al,40h je add_food ;Если нет повторяем push cx mov ax,0A24h mov cx,1 int 10h ;замена на биос сервис pop cx end if if flag=1 mov bl,READ call write_read ;читать символ/атрибут cmp al,0DBh ;Проверяем пустое ли место je add_food cmp al,40h je add_food ;Если нет повторяем cmp al,24h ;чтоб повторно на писалась еда на тоже место je add_food ;для экспериментов mov ax,0224h mov bl,WRITE call write_read ;записать символ/атрибут end if ret ;endp ;================================ game_over: ;Проверяем границы cmp dl,28h ;40 je exit cmp dl,0 jl exit cmp dh,0 jl exit cmp dh,19h je exit ;Проверяем символы cmp al,0DBh ;съели себя? je exit cmp al,040h ;съели какашку? je exit jmp good exit: jmp $ good: ret ;endp ;================================= if flag=1 write_read: if opt=0 push di ;на входе bl = READ or WRITE xor di,di ; ax = атрибуты/символ push dx ; dx = координаты push dx shr dx,8 imul dx,80 mov di,dx pop dx xor dh,dh shl dl,1 add di,dx ;mov di,40*2*dh+2*dl cmp bl, READ jnz @f mov word ax,[es:di] ;READ jmp .exit @@: mov word [es:di],ax ;WRITE .exit: pop dx pop di ret end if ;off optimization ;endp ;++++++++++++++++++++++++++++++++ if opt=1 ;НЕРАБОЧИЙ push di ;на входе bl = READ or WRITE xor di,di ; ax = атрибуты/символ push si ; dx = координаты test bl,1 pushf movzx bx,dh ;Перемещение с нулевым удлинением movzx si,dh ;избавляет от xor shl bx,6 shl si,4 lea bx,word [bx+si] ;избавляет от add movzx si,dl shl si,1 lea di,word [bx+si] popf jz @f mov word ax,[es:di] ;READ jmp .exit @@: mov word [es:di],ax ;WRITE .exit: xor bx,bx pop si pop di ret end if ;on optimization if opt=2 ;write/read bios servis push ax mov ax,0200h ;уст. позицию курсора int 10h cmp bl, READ jnz @f mov ax,0800h int 10h ;READ inc sp inc sp jmp .exit @@: pop ax mov bl,ah push cx mov ah,09h mov cx,1 int 10h ;WRITE pop cx .exit: ret end if ;on optimization end if ;endp ;ф-я мультипликативного генератора. Алгоритм взят из функции rand библиотеки си rnd: push cx ;сохранить регистры push dx mov ax,[rand] ;взять r(i) значение на предыдущем шаге mov cx,53h ;коэффициент а mul cx ;r(i)*a inc ax ;r(i)*a+1 mov [rand],ax ;сохранить новое значение mov al,byte ptr (rand+1);+2 ;взять старшую часть произведения ;and al,3fh ;ограничить диапазон числа 40 and 25, старое знач. 7fh sc: cmp al,bl jb ex ;если меньше то переходим shr al,3 ;иначе делим на 2 логическим сдвигом jmp sc ex: pop dx ;восстановить регистры pop cx ret ;================================= rand dw 125 ;начальное значение случайной величины tick dw 0 ;Счетчик snake dw 0000h dw 0001h dw 0002h dw 0003h dw 0004h size = $-$$+2 bits = 16 display 'Размер свободного места',13,10 display '0x' repeat bits/4 d = '0' + (0200h-size) shr (bits-%*4) and 0Fh if d > '9' d = d + 'A'-'9'-1 end if display d end repeat display ' байт.' ; times 510 - ($ - $$) db 0 ;заполнение нулями промежутка между предыдущим байтом и пос- db 0x55,0xAA