主题:[原创]汇编版贪吃蛇
这个在Emu8086v3.07下调试通过
; This is the snake game...
;
; It's better to set the
; "step delay" to "0" before
; running, it requires fast
; processing.
;
; You can control the snake
; using arrow keys on your
; keyboard.
;
; All other keys will stop
; the snake.
;
; Press ESC to exit.
#make_COM#
ORG 100h
; jump over data section:
JMP start
; ------ DATA section ------
s_size EQU 7
; the snake coordinates
; (from head to tail)
; low byte is left, high byte
; is top - [top, left]
snake DW s_size DUP(0)
tail DW ?
; direction constants
; (BIOS key codes):
LEFT EQU 4Bh
RIGHT EQU 4Dh
UP EQU 48h
DOWN EQU 50h
; current snake direction:
cur_dir DB RIGHT
wait_time DW 0
; ------ CODE section ------
start:
CALL SayThis
DB "==== HOW TO PLAY ====", 13, 10
DB "It's better to set the", 13, 10
DB '"step delay" to "0" before', 13, 10
DB "running, it requires fast", 13, 10
DB "processing.", 13, 10, 13, 10
DB "You can control the snake", 13, 10
DB "using arrow keys on your", 13, 10
DB "keyboard.", 13, 10, 13, 10
DB "All other keys will stop", 13, 10
DB "the snake.", 13, 10, 13, 10
DB "Press ESC to exit.", 13, 10
DB "====================", 13, 10, 13, 10
DB "Press any key to start...", 0
; wait for any key:
MOV AH, 00h
INT 16h
; hide text cursor:
; (emulator shows
; text cursor only when
; it wait for input, so
; this is optional)
MOV AH, 1
MOV CH, 2Bh
MOV CL, 0Bh
INT 10h
game_loop:
; === select first video page
MOV AL, 0 ; page number.
MOV AH, 05h
INT 10h
; === show new head:
MOV DX, snake[0]
; set cursor at DL,DH
MOV AH, 02h
INT 10h
; print '*' at the location:
MOV AL, '*'
MOV AH, 09h
MOV BL, 0Eh ; attribute.
MOV CX, 1 ; single char.
INT 10h
; === keep the tail:
MOV AX, snake[s_size * 2 - 2]
MOV tail, AX
CALL move_snake
; === hide old tail:
MOV DX, tail
; set cursor at DL,DH
MOV AH, 02h
INT 10h
; print ' ' at the location:
MOV AL, ' '
MOV AH, 09h
MOV BL, 0Eh ; attribute.
MOV CX, 1 ; single char.
INT 10h
check_for_key:
; === check for player commands:
MOV AH, 01h
INT 16h
JZ no_key
MOV AH, 00h
INT 16h
CMP AL, 1Bh ; ESC - key?
JE stop_game ;
MOV cur_dir, AH
no_key:
; === wait a few moments here:
; get number of clock ticks
; (about 18 per second)
; since midnight into CX:DX
MOV AH, 00h
INT 1Ah
CMP DX, wait_time
JB check_for_key
ADD DX, 4
MOV wait_time, DX
; === eternal game loop:
JMP game_loop
stop_game:
; show cursor back:
MOV AH, 1
MOV CH, 0Bh
MOV CL, 0Bh
INT 10h
RET
; ------ functions section ------
; This procedure creates the
; animation by moving all snake
; body parts one step to tail,
; the old tail goes away:
; [Last part (tail)]-> goes away
; [Part i] -> [Part i+1]
; ....
move_snake PROC NEAR
; set ES to BIOS info segment:
MOV AX, 40h
MOV ES, AX
; point DI to tail
MOV DI, s_size * 2 - 2
; move all body parts
; (last one simply goes away)
MOV CX, s_size-1
move_array:
MOV AX, snake[DI-2]
MOV snake[DI], AX
SUB DI, 2
LOOP move_array
CMP cur_dir, LEFT
JE move_left
CMP cur_dir, RIGHT
JE move_right
CMP cur_dir, UP
JE move_up
CMP cur_dir, DOWN
JE move_down
JMP stop_move ; no direction.
move_left:
MOV AL, b.snake[0]
DEC AL
MOV b.snake[0], AL
CMP AL, -1
JNE stop_move
MOV AL, ES:[4Ah] ; col number.
DEC AL
MOV b.snake[0], AL ; return to right.
JMP stop_move
move_right:
MOV AL, b.snake[0]
INC AL
MOV b.snake[0], AL
CMP AL, ES:[4Ah] ; col number.
JB stop_move
MOV b.snake[0], 0 ; return to left.
JMP stop_move
move_up:
MOV AL, b.snake[1]
DEC AL
MOV b.snake[1], AL
CMP AL, -1
JNE stop_move
MOV AL, ES:[84h] ; row number -1.
MOV b.snake[1], AL ; return to bottom.
JMP stop_move
move_down:
MOV AL, b.snake[1]
INC AL
MOV b.snake[1], AL
CMP AL, ES:[84h] ; row number -1.
JBE stop_move
MOV b.snake[1], 0 ; return to top.
JMP stop_move
stop_move:
RET
move_snake ENDP
; Procedure to print a null terminated
; string at current cursor position.
; The ZERO TERMINATED string should be
; defined just after the CALL.
; For example:
;
; CALL SayThis
; db 'Hello World!', 0
;
; Address of string is stored in the Stack
; as return address.
; Procedure updates value in the Stack to
; make return after string definition.
SayThis PROC NEAR
MOV CS:temp1, SI ; re-store SI register.
POP SI ; get return address (IP).
PUSH AX ; store AX register.
next_char:
MOV AL, CS:[SI]
INC SI ; next byte.
CMP AL, 0
JZ printed
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char ; loop.
printed:
POP AX ; re-store AX register.
; SI should point to next command after
; the CALL instruction and string definition:
PUSH SI ; save new return address into the Stack.
MOV SI, CS:temp1 ; re-store SI register.
RET
temp1 DW ? ; variable to store original value of SI register.
SayThis ENDP
END
; This is the snake game...
;
; It's better to set the
; "step delay" to "0" before
; running, it requires fast
; processing.
;
; You can control the snake
; using arrow keys on your
; keyboard.
;
; All other keys will stop
; the snake.
;
; Press ESC to exit.
#make_COM#
ORG 100h
; jump over data section:
JMP start
; ------ DATA section ------
s_size EQU 7
; the snake coordinates
; (from head to tail)
; low byte is left, high byte
; is top - [top, left]
snake DW s_size DUP(0)
tail DW ?
; direction constants
; (BIOS key codes):
LEFT EQU 4Bh
RIGHT EQU 4Dh
UP EQU 48h
DOWN EQU 50h
; current snake direction:
cur_dir DB RIGHT
wait_time DW 0
; ------ CODE section ------
start:
CALL SayThis
DB "==== HOW TO PLAY ====", 13, 10
DB "It's better to set the", 13, 10
DB '"step delay" to "0" before', 13, 10
DB "running, it requires fast", 13, 10
DB "processing.", 13, 10, 13, 10
DB "You can control the snake", 13, 10
DB "using arrow keys on your", 13, 10
DB "keyboard.", 13, 10, 13, 10
DB "All other keys will stop", 13, 10
DB "the snake.", 13, 10, 13, 10
DB "Press ESC to exit.", 13, 10
DB "====================", 13, 10, 13, 10
DB "Press any key to start...", 0
; wait for any key:
MOV AH, 00h
INT 16h
; hide text cursor:
; (emulator shows
; text cursor only when
; it wait for input, so
; this is optional)
MOV AH, 1
MOV CH, 2Bh
MOV CL, 0Bh
INT 10h
game_loop:
; === select first video page
MOV AL, 0 ; page number.
MOV AH, 05h
INT 10h
; === show new head:
MOV DX, snake[0]
; set cursor at DL,DH
MOV AH, 02h
INT 10h
; print '*' at the location:
MOV AL, '*'
MOV AH, 09h
MOV BL, 0Eh ; attribute.
MOV CX, 1 ; single char.
INT 10h
; === keep the tail:
MOV AX, snake[s_size * 2 - 2]
MOV tail, AX
CALL move_snake
; === hide old tail:
MOV DX, tail
; set cursor at DL,DH
MOV AH, 02h
INT 10h
; print ' ' at the location:
MOV AL, ' '
MOV AH, 09h
MOV BL, 0Eh ; attribute.
MOV CX, 1 ; single char.
INT 10h
check_for_key:
; === check for player commands:
MOV AH, 01h
INT 16h
JZ no_key
MOV AH, 00h
INT 16h
CMP AL, 1Bh ; ESC - key?
JE stop_game ;
MOV cur_dir, AH
no_key:
; === wait a few moments here:
; get number of clock ticks
; (about 18 per second)
; since midnight into CX:DX
MOV AH, 00h
INT 1Ah
CMP DX, wait_time
JB check_for_key
ADD DX, 4
MOV wait_time, DX
; === eternal game loop:
JMP game_loop
stop_game:
; show cursor back:
MOV AH, 1
MOV CH, 0Bh
MOV CL, 0Bh
INT 10h
RET
; ------ functions section ------
; This procedure creates the
; animation by moving all snake
; body parts one step to tail,
; the old tail goes away:
; [Last part (tail)]-> goes away
; [Part i] -> [Part i+1]
; ....
move_snake PROC NEAR
; set ES to BIOS info segment:
MOV AX, 40h
MOV ES, AX
; point DI to tail
MOV DI, s_size * 2 - 2
; move all body parts
; (last one simply goes away)
MOV CX, s_size-1
move_array:
MOV AX, snake[DI-2]
MOV snake[DI], AX
SUB DI, 2
LOOP move_array
CMP cur_dir, LEFT
JE move_left
CMP cur_dir, RIGHT
JE move_right
CMP cur_dir, UP
JE move_up
CMP cur_dir, DOWN
JE move_down
JMP stop_move ; no direction.
move_left:
MOV AL, b.snake[0]
DEC AL
MOV b.snake[0], AL
CMP AL, -1
JNE stop_move
MOV AL, ES:[4Ah] ; col number.
DEC AL
MOV b.snake[0], AL ; return to right.
JMP stop_move
move_right:
MOV AL, b.snake[0]
INC AL
MOV b.snake[0], AL
CMP AL, ES:[4Ah] ; col number.
JB stop_move
MOV b.snake[0], 0 ; return to left.
JMP stop_move
move_up:
MOV AL, b.snake[1]
DEC AL
MOV b.snake[1], AL
CMP AL, -1
JNE stop_move
MOV AL, ES:[84h] ; row number -1.
MOV b.snake[1], AL ; return to bottom.
JMP stop_move
move_down:
MOV AL, b.snake[1]
INC AL
MOV b.snake[1], AL
CMP AL, ES:[84h] ; row number -1.
JBE stop_move
MOV b.snake[1], 0 ; return to top.
JMP stop_move
stop_move:
RET
move_snake ENDP
; Procedure to print a null terminated
; string at current cursor position.
; The ZERO TERMINATED string should be
; defined just after the CALL.
; For example:
;
; CALL SayThis
; db 'Hello World!', 0
;
; Address of string is stored in the Stack
; as return address.
; Procedure updates value in the Stack to
; make return after string definition.
SayThis PROC NEAR
MOV CS:temp1, SI ; re-store SI register.
POP SI ; get return address (IP).
PUSH AX ; store AX register.
next_char:
MOV AL, CS:[SI]
INC SI ; next byte.
CMP AL, 0
JZ printed
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char ; loop.
printed:
POP AX ; re-store AX register.
; SI should point to next command after
; the CALL instruction and string definition:
PUSH SI ; save new return address into the Stack.
MOV SI, CS:temp1 ; re-store SI register.
RET
temp1 DW ? ; variable to store original value of SI register.
SayThis ENDP
END