printchar macro n
mov dl,n
mov ah,2
int 21h
endm
Your printchar macro uses the DOS.PrintChar function 02h. For the purpose of your snake game, it's not useful and could sometimes be harmful that this DOS function also emits a carriage return / linefeed. You should use the BIOS.WriteCharacter function 0Ah instead.
printchar macro n
mov cx, 1
mov bh, 0
mov al, n
mov ah, 0Ah ; BIOS.WriteCharacter
int 10h
endm
Colliding with a star
To detect a collision all it takes is reading from the video memory using BIOS.ReadCharacterAndAttribute function 08h. You do this right between going to the next position (gotoxy) and displaying another star (printchar).
gotoxy x,y
mov bh, 0
mov ah, 08h ; BIOS.ReadCharacterAndAttribute
int 10h ; -> AX
cmp ax, 0720h ; Is this position unoccupied? (0720h means a WhiteOnBlack space character)
jne LEND ; No
printchar '*'
Crashing into the border
If you would draw the rectangle (0,0) - (79,23), you would not have to verify exceeding the coordinates at label L2 because the above collision detection would also take care of that.
Next is a quick solution to draw a white rectangle:
mov dx, 174Fh ; (79,23)
xor cx, cx ; (0,0)
mov bh, 77h ; WhiteOnWhite
mov ax, 0600h ; BIOS.ClearWindow
int 10h
mov dx, 164Eh ; (78,22)
mov cx, 0101h ; (1,1)
mov bh, 07h ; WhiteOnBlack
mov ax, 0600h ; BIOS.ClearWindow
int 10h
One final tip
Be consistent about retrieving a key from the user. Your program mixes the DOS function 07h and the Keyboard BIOS function 00h. I would suggest you use the Keyboard BIOS function all the time.
[edit]
Your completed code with corrections and even more improvements.
Please note that I have increased the size for the stack. 64 bytes is a bit small and can easily get you into trouble with certain BIOS and/or DOS system calls.
gotoxy macro x, y
mov dl, x
mov dh, y
mov bh, 0
mov ah, 02h ; BIOS.SetCursor
int 10h
endm
printchar macro n
mov cx, 1
mov bh, 0
mov al, n
mov ah, 0Ah ; BIOS.WriteCharacter
int 10h
endm
printstring macro n
lea dx, n
mov ah, 09h ; DOS.PrintString
int 21h
endm
.model small
.stack 512
.data
x db 40
y db 12
delta dw 0FF00h ; deltax = 0 deltay = -1
msg1 db "GAME OVER !!!$"
.code
main:
mov ax, @data
mov ds, ax
mov dx, 174Fh ; (79,23)
xor cx, cx ; (0,0)
mov bh, 77h ; WhiteOnWhite
mov ax, 0600h ; BIOS.ClearWindow
int 10h
mov dx, 164Eh ; (78,22)
mov cx, 0101h ; (1,1)
mov bh, 07h ; WhiteOnBlack
mov ax, 0600h ; BIOS.ClearWindow
int 10h
gotoxy x, y
printchar '*'
mov ah, 00h ; BIOS.GetKey
int 16h ; -> AX
Again:
mov ax, delta
add x, al
add y, ah
gotoxy x, y
mov bh, 0
mov ah, 08h ; BIOS.ReadCharacterAndAttribute
int 10h ; -> AX
cmp ax, 0720h ; Is this position unoccupied?
jne Done ; No
printchar '*'
mov ah, 01h ; BIOS.TestKey
int 16h ; -> AX ZF
jz Again ; No key available
mov ah, 00h ; BIOS.GetKey
int 16h ; -> AX
mov bx, 0FF00h ; deltax = 0 deltay = -1
cmp al, 'w' ; Up
je SetDelta
mov bx, 0100h ; deltax = 0 deltay = 1
cmp al, 's' ; Down
je SetDelta
mov bx, 00FFh ; deltax = -1 deltay = 0
cmp al, 'a' ; Left
je SetDelta
mov bx, 0001h ; deltax = 1 deltay = 0
cmp al, 'd' ; Right
jne Again
SetDelta:
mov delta, bx
jmp Again
Done:
gotoxy 35, 12
printstring msg1
mov ah, 00h ; BIOS.GetKey
int 16h ; -> AX
mov ax ,4C00h ; DOS.Terminate
int 21h
end main