[ASM] Worm

16-битные ПЦ-совместимые компьютеры с процессорами 8086/8088/80286 работающие под управлением ДОС

Moderator: Shaos

Shiru Otaku
Retired
Posts: 490
Joined: 16 Mar 2002 17:00

[ASM] Worm

Post by Shiru Otaku »

Нет, к вирусам и троянам эта тема отношения не имеет;) Сабж - это моя попытка (двухлетней с небольшим давности) написать всем известную игрушку Piton на x86 ассемблере, сделав её как можно меньше. Долгое время не мог уложить её менее, чем в 189 байт; весной прошлого года по совету товарища E}|{ укоротил её ещё на пару байт. На том пока и застрял;)

Кто хочет поразвлечься, попытавшись сделать код ещё короче - ниже привожу исходник. Работает на 086, в текстовом режиме (вывод атрибутами текста). Нормально запускается под Win XP, скорость игры не изменяется на любом компе.

Code: Select all

; Worm-187 by Shiru Otaku^IIpr 23.03.2005
; это просто игрушка Питон размером в 187 байт

CODESG SEGMENT BYTE 'CODE'
       ASSUME CS:CODESG, DS:CODESG, SS:CODESG, ES:CODESG
       ORG    100H


MAIN   PROC   NEAR

		mov es,ax
		int 10h

		mov bh,0b8h
		mov ds,bx
		
gameStart:
		mov bh,09h
clearAttr:
		mov byte ptr[bx],011h
		dec bx
		jnz clearAttr

		mov bl,0a6h
fillFld0:
		mov cl,044h
fillFld1:
		mov byte ptr[bx],ch
		inc bx
		loop fillFld1
		add bx,12
		cmp bh,07h
		jb fillFld0

		mov bx,1000h
		mov dx,4
		inc si
		inc si
		mov cl,dl
initWorm:
		mov word ptr[bx],03e5h
		add bx,si
		loop initWorm

genPiece:

randSeed=$+1
		mov bx,0
     	add bx,word ptr es:[046ch]
     	and bh,07h
     	mov word ptr cs:[randSeed],bx
		or bl,1
     	cmp cl,byte ptr[bx]
     	jne genPiece
	    mov byte ptr[bx],0bbh

gameLoop:

		mov cl,2
waitLoop0:
		mov al,byte ptr es:[046ch]
waitLoop1:
		cmp al,byte ptr es:[046ch]
		je waitLoop1
		loop waitLoop0
		
		mov ah,ch
		mov cx,dx
		mov bx,0ffeh

drawWorm:
		inc bx
		inc bx
		mov di,word ptr[bx]
		mov word ptr[bx-2],di
		mov byte ptr[di],ah
		mov ah,0aah
		loop drawWorm
		
		cmp si,cx
		je gameStart
		
		mov ah,1
		int 16h
		jz inpTest3
		xor ah,ah
    	int 16h
		
		mov al,ah
	    cmp al,48h
	    jne inpTest0
	    mov si,0ffb0h
inpTest0:
	   	cmp al,50h
	   	jne inpTest1
	   	mov si,50h
inpTest1:
		cmp al,4bh
		jne inpTest2
		mov si,0fffeh
inpTest2:
		cmp al,4dh
		jne inpTest3
		mov si,2
inpTest3:

		add di,si
		mov word ptr[bx],di
		mov word ptr[bx+2],di

		mov al,byte ptr[di]
		cmp al,cl
		je inpTest4
		inc dx
		cmp al,0bbh
		je genPiece
		mov si,cx
inpTest4:
	    cmp ah,1
	    jne gameLoop

		mov ax,3
		int 10h

		ret
		
MAIN   ENDP
CODESG ENDS
       END  MAIN
Ещё раньше аналогичная попытка предпринималась мною на Speccy, но там я сделал игрушку в 255 байт, со звуковыми эффектами и прочей ерундой - чтобы максимально забить 1 сектор;)

А началась эта история с желания написать питона размером в 128 байт. Пока мне это не удалось ни на одной платформе;)
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Смотри ка ты - работает :)

Image

Во истину - NedoPC ;)

Кто не верит что оно действительно 187 байт занимает - качайте и смотрите сами: WORM.COM
Last edited by Shaos on 21 Jan 2006 08:34, edited 1 time in total.
Я тут за главного - если что шлите мыло на me собака shaos точка net
bar
Senior
Posts: 185
Joined: 07 Aug 2006 10:18

Post by bar »

этт... а что делает `int 0x16' с ah, в случае если нету ввода? я из dosemu пытался погонять -- дык, условный переход:

Code: Select all

inpTest4:
       cmp ah,1
       jne gameLoop
не выполняется нифига. Если нечего читать, dosemu'шный бивис не трогает ah, ограничиваясь установкой zf. а что делает "настоящий"?
я в раздумьях кого править: worm.com или dosemu :)
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

bar wrote:этт... а что делает `int 0x16' с ah, в случае если нету ввода? я из dosemu пытался погонять -- дык, условный переход:

Code: Select all

inpTest4:
       cmp ah,1
       jne gameLoop
не выполняется нифига. Если нечего читать, dosemu'шный бивис не трогает ah, ограничиваясь установкой zf. а что делает "настоящий"?
я в раздумьях кого править: worm.com или dosemu :)
DOSBox эмулит всё как надо (см. скриншот) - переходи на него ;)
Я тут за главного - если что шлите мыло на me собака shaos точка net
bar
Senior
Posts: 185
Joined: 07 Aug 2006 10:18

Post by bar »

в dosemu добавил обнуление ah -- оно заработало, но кривовато: у dosemu проблемы с видеорежимом 0. в консоли вообще не хочет, а в X'ах, может если шрифт подходящий подобрать, то будет в самый раз.
Shaos wrote:DOSBox эмулит всё как надо (см. скриншот) - переходи на него ;)
:)
поставил я его...
та же фигня. Даже скачал приведённый worm.com: думаю мало ли что. dosbox'овый биос тоже не меняет значение ah. Обнуляю ah -- работает, прям как на скриншоте.
:roll: А у тебя "чистый" dosbox 0.63? В смысле нету ли на нём левых патчей от debian, rh или ещё откуда?
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

bar wrote:в dosemu добавил обнуление ah -- оно заработало, но кривовато: у dosemu проблемы с видеорежимом 0. в консоли вообще не хочет, а в X'ах, может если шрифт подходящий подобрать, то будет в самый раз.
Shaos wrote:DOSBox эмулит всё как надо (см. скриншот) - переходи на него ;)
:)
поставил я его...
та же фигня. Даже скачал приведённый worm.com: думаю мало ли что. dosbox'овый биос тоже не меняет значение ah. Обнуляю ah -- работает, прям как на скриншоте.
:roll: А у тебя "чистый" dosbox 0.63? В смысле нету ли на нём левых патчей от debian, rh или ещё откуда?
Чистый DOSBox под линух - скачанный с ихнего сайта

А где ты AH обнуляешь? Там же есть XOR AH,AH - обнуление. А проверка на 1 похоже на ESC.
Я тут за главного - если что шлите мыло на me собака shaos точка net
bar
Senior
Posts: 185
Joined: 07 Aug 2006 10:18

Post by bar »

Code: Select all

    mov ah, 1 ;запихнули в ah 1
    int 16h
    jz inpTest3
[...]
inpTest3:
[...] ; ничего влияющего на значение ah
      ; отсюда можно уйти не на inpTest4, но только если сожрать кролика
    cmp ah, 1 ;и если ввода небыло, то ah до сих пор 1.
              ;запихивали номер функции, а теперь трактуем как
              ;скан-код клавиши
    jne gameLoop
если в фции 1 int 16 обнулить ah, то работает, даже если ввода нет.
Либо можно обнулить после int16 по значению ZF.

DOSBox, говоришь чистый... у меня, по ходу дела, тоже. патчи которые ебилд накладывает, к делу никакого отношения не имеют. обновил dosbox до 0.65 -- тоже не работает.
Странно всё это... Заглянул в сорец dosbox'а -- там, вроде как, gcc не может оказать своего пагубного влияния на ah. фихня какая-то. И чем дальше, тем больше я сомневаюсь в правильности обнуления ah в int16.

ps. но dosbox это бонус :) на нём в супаплекс можно играть -- в dosemu мне так и не удалось скорость настроить.
bar
Senior
Posts: 185
Joined: 07 Aug 2006 10:18

Post by bar »

однако, award'овый биос, по ходу дела, изменяет значение ah. нифига не понимаю, как оно могло работать на dosbox в неизменном виде.
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Ну у меня dosbox-0.63, собранный из исходников и запускаемый через dboxfe-0.0.5, также из исходников полученный. Всё работает - только что проверил. WORM.COM собран функциональным аналогом MASM-a (называется Arrowsoft Assembler - публик домайн) в том же DOSBox-e.

Посмотрел код - AH там при ненажатой кнопке не меняется...

Проверил экспериментально - после mov ah,1 и int 16h при ненажатой кнопке в AH сидит #11, значит всё-таки меняется...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Shaos wrote: Посмотрел код - AH там при ненажатой кнопке не меняется...

Проверил экспериментально - после mov ah,1 и int 16h при ненажатой кнопке в AH сидит #11, значит всё-таки меняется...
Ооо - там не зря стоит обработчик двух случаев - case 0x01 и case 0x11 - хотя я так и не нашёл то место, где 0x01 превращается в 0x11...
Я тут за главного - если что шлите мыло на me собака shaos точка net
bar
Senior
Posts: 185
Joined: 07 Aug 2006 10:18

Post by bar »

Shaos wrote:Проверил экспериментально - после mov ah,1 и int 16h при ненажатой кнопке в AH сидит #11, значит всё-таки меняется...
я тоже экспериментально. у меня не меняется и хоть тресни. ладно, я в обработчике int16 dosbox'а тоже обнулил ah.
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Новый рекорд:

Code: Select all

;Worm-154 by Shelwien 19.11.2006
;http://compression.ru/sh

CODESG SEGMENT BYTE 'CODE' 
       ASSUME CS:CODESG, DS:CODESG, SS:CODESG, ES:CODESG 
       ORG    100H 

ideal
p286

MAIN:
; ax = temp
; bx = snake head ptr
; cx = temp
; dx = temp (mostly unused)
; si = temp (mostly unused)
; di = video ptr
; bp = unused ; random seed
; es = b800

;buf = 736h-4*2
buf = 03E5h-4*2

;		pop	fs
		int 16

;		mov bh,0b8h 
;		mov es,bx 

		xchg	di,ax
		mov	al,11h
		;xor	di,di
;		mov	ch,high 900h
		mov	cx,0b800h
		mov	es,cx
	rep	stosb
		xchg	cx,ax

gameStart: 	; ax=0 at start and after jump
;		mov	al,0
;		mov	di,(40*2+3)*2
;f0:		mov	cx,(40-3*2)
;	rep	stosw
;		add	di,3*2*2
;		cmp	di,700h
;		jb	f0

		mov	cx,21
		mov	di,(40*2+3)*2
f0:		push	cx
		mov	cl,(40-3*2)
	rep	stosw
		pop	cx
		add	di,3*2*2
		loop	f0

;		mov	ax,(12*40+18)*2+1 ; 03E5h
;		mov	bx,buf+4*2
;		mov	bx,di
;		mov	sp,bx
;		push	ax ax ax ax

		mov	bx,buf+4*2
		mov	sp,bx
		push	bx bx bx bx
		
		test	ax,?
		org $-2	

genPiece: 	inc	bx	; len increment
		inc	bx

gp1:		;add	bp,[word fs:046ch]
		xor	ax,ax	; ah=0 on all pathes, but int 1ah spoils all the fun
		int 26
;		add	bp,dx
		
		add	di,dx
		and	di,07FEh

;		xor	ax,ax
		scasw
		jnz	gp1
		dec	di
		mov	al,0bbh
		stosb

gameLoop: 


;		mov	si,046ch
;		mov	ax,[word fs:si]
;		add	ax,2
;w0:		cmp	ax,[word fs:si]
;		jnz	w0

		mov	ah,0
		int 26
		mov	si,dx
		inc	si
		inc	si
w0:		;mov	ah,0
		int 26
		cmp	dx,si
		jnz	w0
		
		mov	ah,1 
		int 22
		jz	inpTest3 
		mov	ah,0
		int 22
 
		cmp	al,27 ; esc ascii
		jz	quit

		xchg	dx,ax	
inpTest3: 	
		mov	si,offset cmds
i0:		lodsw
		cmp	ah,dh
		jnz	i1
		mov	[byte ds:MoveDir],al
i1:		test	ax,ax
		jnz	i0

;		mov	si,offset cmds
;i0:		lods	[byte ds:si]
;		cmp	al,ah
;		lods	[byte ds:si]
;		jz	i1
;		cmp	al,0
;		jnz	i0
;i1:		;cbw
;		;xchg	dx,ax
;		mov	[byte ds:MoveDir],al

;		mov	al,0
dw0:		pop	di
		push	di di
		pop	di
		stosb
		pop	di
		mov	al,0aah
		cmp	sp,bx
		jb	dw0
		 
;		add	di,dx
		add	di,2
		MoveDir = $-1
		pop	ax 
		push	di di

		mov	sp,buf

		mov	al,0bbh
		scasb	
		jz	genPiece
		dec	di ; it was attr already
		xor	ax,ax
		scasb
		je	gameLoop
		jmp	gameStart

quit:		mov	ax,3
		int 16
		int 32

cmds:
;		db	48h,-50h
;		db	50h, 50h
;		db	4bh,-02h
;		db	4dh, 02h
;		db	  0,   0
		 
		db	-50h,48h
		db	 50h,50h
		db	-02h,4bh
		db	 02h,4dh
		db	   0,  0
		 
ENDS 
END  MAIN

Для сборки нужен TASM - стандартный MASM на этот код будет ругаться
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24087
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Worm для ZX перенёс в другое место
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
LazyBear
Junior
Posts: 1
Joined: 11 Sep 2007 03:54
Location: Великий Новгород

Post by LazyBear »

В 97-ом году у нас олимпиада была в универе, надо было написать самого короткого питона. На самой олимпиаде я писал на паскале (правда от паскаля там в итоге остался только begin/end и пара циклов, остальное было встроенный асм)
После я, обложившись справочниками, сваял питона на 117 байт. ;) Правда он был сильно упрощён. Мог уползать влево-вправо и выползал на строку ниже-выше.
Более честная версия занимала 144 байта.
Правда сейчас под XP они не запустились. То-ли что-то с видеопамятью (я просто из фара пробовал запускать), то-ли дело в 15h прерывании которым я задержку делал.
Под DOS 6.0 в те времена работал нормально (и без дос-а, мы его пробовали в бут-сектор дискеты записывать и загружаться с неё ;))

Асм я тогда плохо знал (а сейчас ещё и забыл ;)), поэтому откомментирован практически построчно.
Компилировалось это всё TASM-ом (из состава BC 3.1/BP 7.0)

Самый короткий и слегка нечестный вариант. 117 байт

Code: Select all

; 1997 Eugene Nikulin (LazyBear)


Field_Char   EQU ' '              ; Символ заполнения поля
Field_ChAt   EQU 0F2Eh              
Piton_Char   EQU '█'              ; Символ тела питона
Rabbit_Char  EQU 'K'              ; Символ кролика

 Code segment

  org 100h
  assume cs:CODE,ds:CODE,es:CODE

START:

    xor  AX, AX
    int  10h

    mov  BX, 0B800h                    ; Установить DS на видеопамять
    mov  DS, BX

    mov  BH, 08h                       ; Начальное смещение головы
    mov  DI, BX                        ; Начальное смещение хвоста

    mov  DX, 2                         ; Начальное направление движения
    mov  CX, DX

NEW_RABBIT:

 @11:
    inc  BP   
    mov  SI, [BP]                      ; В SI случайное число
    and  SI, 03FEh                     ; Обрезаем чтобы влезло на экран
    cmp  BYTE ptr [SI], Field_Char     ; Это место пустое?
    jnz  @11                           ; Место не пустое, ищем еще
    mov  BYTE ptr [SI], Rabbit_Char    ; Нарисовать кролика

GAME_LOOP:


    mov  SI, [BX]                      ; В SI координата головы
    mov  BYTE ptr [SI], Piton_Char     ; Нарисовать голову

    add  SI, DX                        ; Добавить смещение
    add  BL, CL                        ; Увеличить указатель головы
    mov  [BX], SI                      ; Записать новое положение головы

    cmp  BYTE ptr [SI], Rabbit_Char    ; Проверка на съедание кролика
    jz   NEW_RABBIT                    ; Кролик съеден!

    cmp  BYTE ptr [SI], Field_Char     ; Проверка на попадание в поле
    jnz  END_GAME                      ; В поле не попали
    

    push DX                            ; Задержка через 15h прерывание
    xor  DX, DX                        ; Задержка на 020000h мс
    mov  AH, 86h
    int  15h
    pop  DX

    xchg DI, BX                        ; В BX указатель на хвост
    mov  SI, [BX]                      ; В SI координата хвоста 
    mov  BYTE ptr [SI], Field_Char     ; Затереть хвост
    add  BL, CL                        ; Увеличение указателя на хвост
    xchg DI, BX

    mov  AH, 01                        ; Проверка на нажатую клавишу
    int  16h                           ; В AX код клавиши
    je   GAME_LOOP                     ; Клавиша не нажата

    xchg AH, AL                        ; 'cmp AL' занимает меньше места 
                                       ; чем  'cmp AH' !

    cmp  AL, 4Bh                       ; Клавиша влево?
    jnz  @1
    mov  DX, -2
  @1:
    cmp  AL, 4Dh                       ; Клавиша вправо?
    jnz  @2
    mov  DX, CX                        ; CX = 2
  @2:
    cmp  AL, 50h                       ; Клавиша ввниз?
    jnz  @3
    mov  DX, AX                        ; AX = 50h = 80
  @3:
    cmp  AL, 48h                       ; Клавиша вверх?
    jnz  @4
    mov  DX, -80
  @4:
    xor  AH, AH                       
    int  16h                           ; Очистка буфера клавиатуры

    cmp  AL, 27                        ; Проверка на 'Esc'
    jnz GAME_LOOP

END_GAME:
    ret

Code ends
end start
Более честный и цветной. 144 байта

Code: Select all

; 1997 Eugene Nikulin (LazyBear)

Field_Char   EQU 2Eh            ; Символ заполнения поля
Field_ChAt   EQU 0F2Eh              
Piton_Char   EQU 0DBh           ; Символ тела питона
Piton_ChAt   EQU 0ADBh
Rabbit_Char  EQU 4Bh            ; Символ кролика
Rabbit_ChAt  EQU 0C4Bh

Field_Width  EQU 35
Field_Height EQU 20

 Code segment

  org 100h
  assume cs:CODE,ds:CODE,es:CODE

START:

    xor  AX, AX
    int  10h

    mov  BX, 0B800h                    ; Установить DS на видеопамять
    mov  DS, BX

    mov  ES, BX
    xor  DI, DI

    mov  DX, Field_Height
    mov  AX, Field_ChAt
  @15:
    mov  CX, Field_Width
    rep  stosw
    add  DI, 10
    dec  DX
    jnz  @15

    mov  BH, 08h                       ; Начальное смещение головы
    mov  [BX], 810                     ; Начальная координата головы
    mov  DI, BX                        ; Начальное смещение хвоста

    mov  DL, 2                         ; Начальное направление движения
    mov  CX, DX

NEW_RABBIT:

 @11:
    inc  BP
    mov  SI, [BP]                      ; В SI случайное число
    cmp  BYTE ptr [SI], Field_Char     ; Это место пустое?
    jnz  NEW_RABBIT                    ; Место не пустое, ищем еще
    mov  BYTE ptr [SI], Rabbit_Char    ; Нарисовать кролика

GAME_LOOP:


    mov  SI, [BX]                      ; В SI координата головы
    mov  BYTE ptr [SI], Piton_Char     ; Нарисовать голову

    add  SI, DX                        ; Добавить смещение
    add  BL, CL                        ; Увеличить указатель головы
    mov  [BX], SI                      ; Записать новое положение головы

    cmp  BYTE ptr [SI], Rabbit_Char    ; Проверка на съедание кролика
    jz   NEW_RABBIT                    ; Кролик съеден!

    cmp  BYTE ptr [SI], Field_Char     ; Проверка на попадание в поле
    jnz  END_GAME                      ; В поле не попали
    

    push DX                            ; Задержка через 15h прерывание
    xor  DX, DX                        ; Задержка на 020000h мс
    mov  AH, 86h
    int  15h
    pop  DX

    xchg DI, BX                        ; В BX указатель на хвост
    mov  SI, [BX]                      ; В SI координата хвоста 
    mov  BYTE ptr [SI], Field_Char     ; Затереть хвост
    add  BL, CL                        ; Увеличение указателя на хвост
    xchg DI, BX

    mov  AH, 01                        ; Проверка на нажатую клавишу
    int  16h                           ; В AX код клавиши
    je   GAME_LOOP                     ; Клавиша не нажата

    xchg AH, AL                        ; 'cmp AL' занимает меньше места 
                                       ; чем  'cmp AH' !

    cmp  AL, 4Bh                       ; Клавиша влево?
    jnz  @1
    mov  DX, -2
  @1:
    cmp  AL, 4Dh                       ; Клавиша вправо?
    jnz  @2
    mov  DX, CX                        ; CX = 2
  @2:
    cmp  AL, 50h                       ; Клавиша ввниз?
    jnz  @3
    mov  DX, AX                        ; AX = 50h = 80
  @3:
    cmp  AL, 48h                       ; Клавиша вверх?
    jnz  @4
    mov  DX, -80
  @4:
    xor  AH, AH                       
    int  16h                           ; Очистка буфера клавиатуры

    cmp  AL, 27                        ; Проверка на 'Esc'
    jnz GAME_LOOP

END_GAME:

    mov  AX, 0003h
    int  10h

    ret

Code ends
end start