8086 贪吃蛇
运行环境:MsDos 7.1 或 DOSBox
键盘方向键控制
演示
汇编代码
assume cs:code, ds:data, ss:stack; gpu prop byte
; 7 6 5 4 3 2 1 0
; BL R G B I R G B
; | \_____/ | \_____/
; 闪烁 背景 高亮 前景; game map: 25 x 25
; snake bodys max: 23 x 23data segmentscore dw 0 ; game scorescpre db 'score:' ; [6] score prefixdead db 'game over!' ; [10] game overfood dw 0 ; snake food: x|ysdct db 0 ; snake direction 0001-up 0010-down 0100-left 1000-rightslen db 0 ; snake lengthbody dw 529 dup(0) ; snake bodys: x|y, ...
data endsstack segmentdw 20 dup(0)
stack endscode segment
start:mov ax, datamov ds, ax ; init data segmov ax, 0b800h mov es, ax ; save gpu base addrmov ax, stackmov ss, axmov sp, 20 ; init stackcall clearmov ah, 24mov al, 24push axcall draw_mapcall create_snakecall draw_snakecall create_foodcall draw_foodcall start_gamecall show_scoreend_game:call game_overmov ax, 4c00hint 21h; # start game
; void -> void
start_game:mov cx, 50
sg0:call listen_key call clear_lastcall move_snakecall is_deadcall draw_snakecall is_eatcall show_scorecall sleeploop sg0ret; # show game over alert
; void -> void
game_over:push axpush cxpush simov si, 28mov cx, 10 ; string length
go0:mov ax, simov ah, almov al, 12push axmov ah, 00000111bmov al, dead[si - 28]push axcall draw_charinc siloop go0pop sipop cxpop axret; # is the snake dead
; void -> void
is_dead:push axpush cxpush simov ax, body[0] ; get headcmp ah, 0 ; touch the edgeje end_gamecmp ah, 24je end_gamecmp al, 0je end_gamecmp al, 24je end_gamemov ch, 0mov cl, slendec cxmov si, 2 ; start with secondid0: ; touch self bodymov ax, body[si]cmp body[0], axje end_gameadd si, 2loop id0pop sipop cxpop axret; # add snake body
; void -> void
add_body:push axpush simov ah, 0mov al, sleninc almov slen, al ; add bodymov si, axadd si, simov ax, body[si - 4]mov body[si - 2], axinc scorecall create_foodcall draw_foodpop sipop axret; # is snake eat food
; void -> void
is_eat:push axmov ax, foodcmp ax, body[0]jne nt0call add_body
nt0:pop axret; show game score
; void -> void
show_score:push axpush bxpush simov si, 28mov cx, 6 ; string length
po0: ; draw score prefixmov ax, simov ah, almov al, 2push axmov ah, 00000111bmov al, scpre[si - 28]push axcall draw_charinc siloop po0mov si, 0mov ax, score
sl0:mov bh, 0mov bl, 10div blmov bx, axmov bl, bhmov bh, 0push bx ; save digitinc si ; count digitscmp al, 0 ; no more digitje se0mov ah, 0 ; next digitjmp short sl0
se0:mov cx, simov si, 34 ; show start x
sn0:pop bx ; get each digitadd bx, 30H ; get digit asciimov ax, simov ah, almov al, 2push axmov ah, 00000111bmov al, blpush axcall draw_char ; draw each digitinc siloop sn0pop sipop bxpop axret; # listen to keys
; void -> void
listen_key:push axmov ah, 1mov al, 0int 16h ; keboard interruptcmp ah, 1je lk0mov ax, 0int 16hcmp ax, 4800h ; press upje kupcmp ax, 5000h ; press downje kdowncmp ax, 4b00h ; press leftje kleftcmp ax, 4d00h ; press rightje krightjmp short lk0kup:cmp sdct, 0010b ; direction conflictje lk0mov sdct, 0001b ; set directionjmp short lk0kdown:cmp sdct, 0001bje lk0mov sdct, 0010bjmp short lk0kleft:cmp sdct, 1000bje lk0mov sdct, 0100bjmp short lk0kright:cmp sdct, 0100bje lk0mov sdct, 1000blk0:pop axret; # clear last snake body
; void -> void
clear_last:push axpush simov ah, 0mov al, slenmov si, axadd si, simov ax, body[si - 2] ; last bodypush axmov ah, 00000000bmov al, ' 'push axcall draw_char ; clearpop sipop axret; # update snake bodys
; void -> void
move_snake:push axpush cxpush simov ch, 0mov cl, slendec cxmov ah, 0mov al, slenmov si, axadd si, si
ms0: mov ax, body[si - 4]mov body[si - 2], axsub si, 2loop ms0mov ax, body[0] ; upd headcmp sdct, 0001b ; upje upcmp sdct, 0010b ; downje downcmp sdct, 0100b ; leftje leftcmp sdct, 1000b ; rightje rightup:dec aljmp short uokdown:inc aljmp short uokleft:dec ahjmp short uokright:inc ahjmp short uokuok:mov body[0], axpop sipop cxpop axret; # draw snake to map
; void -> void
draw_snake:push cxpush sipush axmov ch, 0mov cl, slenmov si, 0
ds0:mov ax, body[si]push axmov ah, 01110000bmov al, ' 'push axcall draw_char ; draw bodyadd si, 2loop ds0pop axpop sipop cxret; # create snake
; fixed: snake size is 3
; void -> void
create_snake:push cxpush sipush axmov sdct, 1000b ; set direct is rightmov ah, 1mov al, 1mov slen, 2 ; set snake lengthmov ch, 0mov cl, slenmov si, 0mov ah, 6 ; set snake head xmov al, 4 ; set snake head y
c0:mov body[si], axdec ahadd si, 2loop c0pop axpop sipop cxret; draw food to map
; void -> void
draw_food:push ax mov ax, foodpush axmov ah, 00101000bmov al, ' 'push axcall draw_char ; draw foodpop axret; # create a food
; fixed: map width and height
; void -> void
create_food:push axpush bxpush cxpush dxpush sire0:mov bx, 23push bxcall rand ; get xinc dx ; range: 1-[23]mov ah, dlpush bxcall rand ; get yinc dxmov al, dlmov ch, 0mov cl, slenmov si, 0
sb0: ; for snake bodycmp ax, body[si]je re0 ; conflict with body, create againadd si, 2loop sb0mov food, ax ; save food xypop sipop dxpop cxpop bxpop axret; # rand number
; 0: range -> dx: 0~(range)
rand:push bpmov bp, sppush axmov ax, 0hout 43h, alin al, 40hin al, 40hin al, 40hmov bx, [bp + 4]div blmov dh, 0mov dl, ahpop axpop bpret 2; # sleep tiem
; void -> void
sleep:push cxmov cx, 50000s0:push cxmov cx, 20s1:loop s1pop cxloop s0pop cxret; # draw game map
; 0: width|height -> void
draw_map:push bpmov bp, sp; draw toppush cxpush axpush bxpush dxmov dx, [bp + 4] ; get widthmov ax, 0mov ch, 0mov cl, dh ; set widthinc cld0:mov bh, al ; draw topmov bl, 0push bxmov bh, 00010000bmov bl, ' 'push bxcall draw_charmov bh, al ; draw bottommov bl, dlpush bxmov bh, 00010000bmov bl, ' 'push bxcall draw_charinc alloop d0mov cl, dl ; set heightdec cl ; inside content heightmov al, 1d1:mov bh, 0 ; draw leftmov bl, alpush bxmov bh, 00010000bmov bl, ' 'push bxcall draw_charmov bh, dh ; draw bottommov bl, alpush bxmov bh, 00010000bmov bl, ' 'push bxcall draw_charinc alloop d1pop dxpop bxpop axpop cxpop bpret 2; # draw char to screen
; 0: x|y, 1: prop|char -> void
draw_char:push bpmov bp, sppush axpush bxpush simov bx, [bp + 6]mov ah, 0mov al, 0a0hmul bl ; set ymov bl, bhmov bh, 0add bl, bladd bl, bladd ax, bx ; set xmov si, axmov ax, [bp + 4]mov es:[si], ax ; set prop and charcmp al, ' 'jne jm0mov es:[si + 2], ax ; for edge, double draw.jm0: ; for normal charpop sipop bxpop axpop bpret 4; # clear screen
; void -> void
clear:mov ax, 3hint 10hretcode ends
end start