;**************************** LIFE.ASM -- Life simulation, VERY FAST!
; This is the enhanced version.
Ideal
Model Tiny
CodeSeg
P386
Org 100h
Proc Prog
mov ax,13h ;Set mode 13h
int 10h
mov dx,03C8h ;Change color 78h
mov al,78h
out dx,al
inc dx
mov al,10h ;Set to dark gray
out dx,al
out dx,al
out dx,al
mov [CurX],160 ;Cursor at center
mov [CurY],100
push 0 ;ES = 0
pop es
mov eax,[es:046Ch] ;Seed RNG
mov [RandNum],eax
mov ax,cs ;DS, ES = virtual video
add ax,1000h
mov ds,ax
mov es,ax
xor di,di ;Zero DI
mov cx,32768 ;32K dwords
xor ax,ax ;Clear memory
rep stosw
push 0A000h ;ES = video memory
pop fs
mov di,321 ;DI = 321
mov cx,200 ;200 rows
RandOLoop: mov si,318 ;318 pixels/row
RandLoop: call Rand ;Get random number
stosb ;Store byte
imul ax,28h ;Write to screen
mov [fs:di-321],al
dec si ;Loop on pixel loop
jnz RandLoop
add di,2 ;Loop on row loop
loop RandOLoop
mov di,320 ;DI = 320
mov cx,64000 ;64000 bytes
InitLoop: xor ah,ah ;Get boundary count
mov al,[di+1]
and al,1
add ah,al
mov al,[di-1]
and al,1
add ah,al
mov al,[di+319]
and al,1
add ah,al
mov al,[di-319]
and al,1
add ah,al
mov al,[di+320]
and al,1
add ah,al
mov al,[di-320]
and al,1
add ah,al
mov al,[di+321]
and al,1
add ah,al
mov al,[di-321]
and al,1
add ah,al
shl ah,1 ;Shift left 1
and ah,0Fh
or [di],ah ;Set count
inc di ;Loop back
loop InitLoop
mov di,320 ;Set up for loop
mov cx,64000
SetupLoop: mov al,[di] ;Copy to high bits
shl al,4
or [di],al
inc di ;Loop back
loop SetupLoop
xor bp,bp ;Zero BP
MainLoop: mov di,321 ;Set up for LifeLoop
mov cx,200
LifeOLoop: mov dx,318 ;318 pixels/row
LifeLoop: mov al,[di] ;Get cell value
and al,0Fh ;AL = boundary count
jz LifeLB ;Empty cell?
shr al,1
jnc LifeDead ;Test current cell
sub al,2 ;Alive, check boundary
cmp al,2
jb DoScreen
mov al,-20h ;Set to flip cell
jmp LifeFlip
LifeDead: cmp al,3 ;Dead, check boundary
jne LifeLB
mov al,20h ;Set to flip cell
LifeFlip: add [di+1],al ;Change boundary counts
add [di-1],al
add [di+319],al
add [di-319],al
add [di+320],al
add [di-320],al
add [di+321],al
add [di-321],al
mov al,[di] ;Flip the cell
xor al,10h
mov [di],al
and al,1 ;Check new cell
cmp al,1 ;Off, set to 0
sbb al,al ;On, set to 28h
and al,28h
jmp Scr01 ;Go set pixel
DoScreen: mov al,[fs:di-320] ;Get current color
cmp al,37h ;Check to maximum
jae LifeLB
inc ax ;Increment color
Scr01: mov [fs:di-320],al ;Write color
LifeLB: inc di ;Loop on pixels
dec dx
jnz LifeLoop
xor ax,ax ;Loop on rows
stosw
loop LifeOLoop
mov di,318 ;Set up for CleanLoop
mov cx,16001 ;Mis-alignment is for pairing!
CleanLoop: mov ax,[di] ;Get values
mov dx,[di+2]
and ax,0F0F0h
and dx,0F0F0h
mov bx,ax ;Copy to both digits
shr bx,4
mov si,dx
shr si,4
or ax,bx
or dx,si
mov [di],ax ;Store values
mov [di+2],dx
add di,4 ;Loop back
dec cx
jnz CleanLoop
test bp,bp ;Check wait flag
jz MainLB
mov ah,86h ;Delay 1/5 second
mov cx,0003h
mov dx,0D40h
int 15h
MainLB: mov ah,1 ;Check for key
int 16h
jz MainLoop ;Loop if no key
GetKey: xor ah,ah ;Get the key
int 16h
cmp ah,01h ; Esc = quit
je Quit
cmp ah,10h ; Q = quit
je Quit
cmp ah,19h ; P = pause
je GetKey
cmp ah,1Fh ; S = slow
jne $+4
not bp
cmp ah,12h ; E = edit
jne MainLoop
call DrawCur ;Draw cursor
EditLoop: xor ah,ah ;Get a key
int 16h
cmp ah,2Eh ; 'C'?
je ClearField
cmp ah,48h ; Up?
je MoveUp
cmp ah,50h ; Down?
je MoveDown
cmp ah,4Bh ; Left?
je MoveLeft
cmp ah,4Dh ; Right?
je MoveRight
cmp ah,1Ch ; Enter?
je EditDone
cmp ah,39h ; Space?
jne EditLoop
FlipCell: imul bx,[cs:CurY],320 ;BX = buffer offset
add bx,[cs:CurX]
add bx,320
mov al,[bx] ;Flip the cell
xor al,11h
mov [bx],al
mov ah,20h ;AH = 20h if on
test al,1 ; -20h if off
jnz $+4
neg ah
add [bx+1],ah ;Change boundary counts
add [bx-1],ah
add [bx+319],ah
add [bx-319],ah
add [bx+320],ah
add [bx-320],ah
add [bx+321],ah
add [bx-321],ah
shr al,1 ;Check new cell
sbb al,al ;Off, set to 0
and al,28h ;On, set to 28h
mov [fs:bx-320],al ;Set screen pixel
jmp EditLoop
ClearField: mov di,320 ;Clear life buffer
mov cx,32000
xor ax,ax
rep stosw
push fs ;ES = video memory
pop es
xor di,di ;Clear the screen
mov cx,32000
xor ax,ax
rep stosw
push ds ;ES = data segment
pop es
call DrawCur ;Redraw cursor
jmp EditLoop
MoveUp: mov ax,[cs:CurY] ;AX = Y
dec ax ;Move up
jl EditLoop
call EraseCur ;Redraw cursor
mov [cs:CurY],ax
call DrawCur
jmp EditLoop
MoveDown: mov ax,[cs:CurY] ;AX = Y
inc ax ;Move down
cmp ax,200
jae EditLoop
call EraseCur ;Redraw cursor
mov [cs:CurY],ax
call DrawCur
jmp EditLoop
MoveLeft: mov ax,[cs:CurX] ;AX = X
dec ax ;Move left
jle EditLoop
call EraseCur ;Redraw cursor
mov [cs:CurX],ax
call DrawCur
jmp EditLoop
MoveRight: mov ax,[cs:CurX] ;AX = offset
inc ax ;Move right
cmp ax,318
jae EditLoop
call EraseCur ;Redraw cursor
mov [cs:CurX],ax
call DrawCur
jmp EditLoop
EditDone: call EraseCur ;Erase cursor
mov di,320 ;Set up for CleanLoop
mov cx,64000
ECleanLoop: mov al,[di] ;Get value
mov ah,al
shr al,4 ;Copy to both digits
and ah,0F0h
or al,ah
mov [di],al ;Store value
inc di ;Loop back
loop ECleanLoop
jmp MainLoop ;Start main loop
Quit: mov ax,3 ;Set text mode
int 10h
ret ;Return
EndP Prog
;**************************** DrawCur -- Draw editing cursor
Proc DrawCur
pusha ;Save all registers
imul bx,[cs:CurY],320 ;BX = offset
add bx,[cs:CurX]
mov ax,7878h ;Draw cursor
add [fs:bx-640],al
add [fs:bx-320],al
add [fs:bx+320],al
add [fs:bx+640],al
add [fs:bx-2],ax
add [fs:bx+1],ax
popa ;Restore registers
ret ;Return
EndP DrawCur
;**************************** EraseCur -- Erase the cursor
Proc EraseCur
pusha ;Save all registers
imul bx,[cs:CurY],320 ;BX = offset
add bx,[cs:CurX]
mov ax,7878h ;Erase cursor
sub [fs:bx-640],al
sub [fs:bx-320],al
sub [fs:bx+320],al
sub [fs:bx+640],al
sub [fs:bx-2],ax
sub [fs:bx+1],ax
popa ;Restore registers
ret ;Return
EndP EraseCur
;**************************** Rand -- Generate random number 0 or 1
Proc Rand
imul eax,[cs:RandNum],015A4E35h
inc eax
mov [cs:RandNum],eax
xchg dx,ax
ror eax,16
xor ax,dx
ror ax,11
and ax,1
ret
EndP Rand
RandNum dd ? ;Random number
CurX dw ? ;Current position
CurY dw ?
End Prog