...

понедельник, 15 сентября 2014 г.

[Из песочницы] 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 для тех, у кого не запустится.


С прошедшим днём программиста!


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий