[Из песочницы] Python на Assembler (Tasm)
Сегодня напишем в текстовом режиме с использованием прерываний BIOS и DOS змейку на Assembler. Для этого нужно знать основы, уметь ассемблировать (Tasm) и компоновать (Tlink) код.Для начала напишем основу — змейку, которая перемещается в одном направлении по игровому полю. Змейка будет состоять из символа »*», координаты каждого символа хранятся в памяти.
Посмотреть код model small
.data; Сегмент данных. Храним координаты тела змейки snake dw 0000h dw 0001h dw 0002h dw 0003h dw 0004h dw 7CCh dup ('?')
.stack 100h
.code ; В начале сегмента кода будем размещать процедуры delay proc push cx mov ah,0 int 1Ah add dx,3 mov bx, dx repeat: int 1Ah cmp dx, bx jl repeat pop cx ret delay endp
start: mov ax,@data mov ds, ax mov es, ax
mov ax,0003h int 10h; Очищаем игровое поле
mov cx,5 mov ax,0A2Ah int 10h; Выводим змейку из 5 символов »*»
mov si,8; Индекс координаты символа головы xor di, di; Индекс координаты символа хвоста mov cx,0001h; Регистр cx используем для управления головой. При сложении от значения cx будет изменяться координата x или y
main: ; Основной цикл call delay xor bh, bh mov ax,[snake+si] ; Берем координату головы из памяти add ax, cx; Изменяем координату x inc si inc si mov [snake+si], ax; Заносим в память новую координату головы змеи mov dx, ax mov ax,0200h int 10h; Вызываем прерывание. Перемещаем курсор mov ah,02h mov dl,002Ah int 21h; Прерывание выводит символ '*' mov ax,0200h mov dx,[snake+di] int 10h mov ax,0200h mov dl,0020h int 21h; Выводим пробел, тем самым удаляя хвост inc di inc di jmp main end start Добавим процедуру «key_press» обработки нажатия клавиши и присваивания значения регистру CX, отвечающему за направление головы.Управление стрелками.
key_press key_press proc 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 key_press endp Вызовем её сразу после вызова процедуры delay: main: call delay call key_press Накормим змейку, создаём процедуру «add_food». Эта процедура будет на игровом поле размещать еду, символы »$». В качестве случайных чисел будем брать время.
add_food add_food proc sc: inc bl; В регистре BL рандомное число cmp bx,50h; Проверяем границу числа jng ex shr bl,1; Если больше, делим на 2 логическим сдвигом jmp sc ex: mov dl, bl; Запись координаты sc2: cmp bx,19h jng ex2 shr bl,2 jmp sc2 ex2: mov dh, bl; Запись координаты mov ax,0200h int 10h mov ax,0800h int 10h cmp al,2Ah; Проверяем пустое ли место je sc cmp al,40h je sc; Если нет повторяем mov ax,0200h mov dl,0024h int 21h ret add_food endp Вызовем 1 раз в начале.
mov bl,51h call add_food main: Делаем проверку, съела змея еду или нет. Если съела, вызываем процедуру «add_food» и не удаляем хвост.
Проверку добавляем в код перед выводом символа головы:
mov ah,02h int 10h; Вызываем прерывание. Перемещаем курсор
mov ax,0800h int 10h; Читает символ mov dh, al
mov ah,02h mov dl,002Ah int 21h; Прерывание выводит символ '*'
cmp dh,24h jne next call add_food jmp main next: Усложним игру. После того, как питон съест 5 символов, в хвосте будет появляться символ »@». Пишем счетчик и вывод символа:
shit ; В сегмент данных добавим строчку .data tick dw 0; Счетчик --------------------------------------------------------------------
cmp dh,24h jne next
push cx; В стек регистр mov cx,[tick] inc cx cmp cx,5 jne exl xor cx, cx mov ax,0200h mov dx,[snake+di-2] int 10h mov ax,0200h mov dl,0040h int 21h exl: mov [tick], cx pop cx
call add_food jmp main next: Какая игра без Game Over. Пишем процедуру проверки границы поля, а также врезание в себя и символ »@».game_over game_over proc ; Проверяем границы cmp dl,50h je exit cmp dl,0 jl exit cmp dh,0 jl exit cmp dh,19h je exit ; Проверяем символы cmp al,2Ah je exit cmp al,40h je exit jmp good exit: mov ax,4c00h int 21h good: ret game_over endp Вызываем её после считывания символа: mov ax,0800h int 10h; Считываем символ
call game_over
mov dh, al Немного магии добавляем после инкремента индексов.
magic inc si inc si cmp si,7CAh jne nex xor si, si nex:
---------------------------------------------------------------------
inc di inc di cmp di,7CCh jne main xor di, di Ну вот и всё, также можно добавить меню с выбором уровня, паузу, заставку Game Over, счет очков.
По ссылке архив с исходным кодом, exe’шником и DosBox для тех, у кого не запустится.
С прошедшим днём программиста!