这是我学BIOS阶段用X86汇编写的贪吃蛇游戏,虽然现在不做BIOS了,还是无比怀念那段学习岁月。
和大家共享,代码如下,有点长,呵呵
特点:在DOS下和windows系统下都可以运行,得到10分,会升级,升级时蜂鸣器会响。
;===========================================================[]
; Function :snake
; Designer :zzobin
; Create Date :2009.3.13
;-----------------------------------------------------------[]
;----------------------| Program Start |---------------------
.model SMALL
.386
;DATA SEGMENT USE16
.data
;BODY DB '-O#' ;3个
BODY DB '-*O' ;3个
DB 50 DUP('a')
;设置蛇的每个字符的初始位置坐标 (行号,列号)
COOR DB 13,23, 13,24, 13,25, 13,26
DB 13,27, 13,28, 13,29, 13,30
DB 13,31, 13,32, 13,33, 13,34
DB 13,35, 13,36
;设置蛇最大可增加 50 个长度
TAIL DB 100 DUP(?)
;设置蛇的当前长度,初始为3
LENG DB 3
LEVEL DB 1
DIRECTION DB 72
FOOD DB 10,10
SCOINFO DB 'SCORE:$'
SCORE DB 0H
SCOCHAR DB 4 DUP('0')
DB '$'
PAUSEINFO DB 'Pagedown to PAUSE$'
EXITINFO DB 'Esc to EXIT $'
;CTRINFO DB 'Change Direction$'
;CTRINFO2 DB 'with Dirction Key$'
CTRINFO DB 'Move ',18H,0,19H,0,1AH,0,1BH,'$'
CTRINFO2 DB 'to Change Direction$'
LEVELINFO DB 'level:$'
NEXTLEVEL DB 'SUCCEED TO NEXT LEVEL!$'
N DW 12000 ;屏幕刷新速度
TEN2 DW 10
MUS_FREG DW 262,262,294,262,349
DW 330,262,262,294,262
DW 392,349,262,262,523
DW 440,349,262,262,466
DW 466,440,262,392,349,-1
MUS_TIME DW 50,50,100,100,100
DW 100,100,50,50,100,100
DW 100,100,100,50,50,100
DW 100,100,100,100,100,50
DW 50,100,100,100,100,100
;DATA ENDS
;STACK SEGMENT STACK
; DB 100 DUP(?)
;STACK ENDS
.code
;-------------------------------------------------------------------------------
;(1) 清空键盘缓冲区
CKBUF macro
push ds
push ax
push bx
MOV AL, 0BH
MOV AH, 0CH
INT 21H
pop bx
pop ax
pop ds
endm
;-------------------------------------------------------------------------------
;(2) 产生0-n的随机数宏定义
;返回值存ah寄存器
rand macro n
push cx
push dx
xor ah,ah
int 1ah
mov ax,dx
and ax,07fh
mov dl,n
div dl
pop dx
pop cx
endm
;-------------------------------------------------------------------------------
;CODE SEGMENT USE16
;ASSUME CS:CODE,DS:DATA,SS:STACK
ORG 100H
.STARTUP
;MOV AX,DATA
;MOV DS,AX
CALL CLEARS
CALL GENFOOD
CALL SHOWINFO
;设置CTRINFO光标位置
PUSH SI
MOV AH,02H
MOV BH,0
MOV DH, 1
MOV DL, 60
INT 10H
;显示CTRINFO
MOV AH,9
MOV DX,OFFSET CTRINFO
INT 21H
;设置CTRINFO2光标位置
PUSH SI
MOV AH,02H
MOV BH,0
MOV DH, 2
MOV DL, 60
INT 10H
;显示CTRINFO2
MOV AH,9
MOV DX,OFFSET CTRINFO2
INT 21H
;设置PAUSEINFO光标位置
PUSH SI
MOV AH,02H
MOV BH,0
MOV DH, 5
MOV DL, 60
INT 10H
;显示PAUINFO
MOV AH,9
MOV DX,OFFSET PAUSEINFO
INT 21H
;设置EXITINFO光标位置
PUSH SI
MOV AH,02H
MOV BH,0
MOV DH, 4
MOV DL, 60
INT 10H
;显示EXITINFO
MOV AH,9
MOV DX,OFFSET EXITINFO
INT 21H
CALL SHOWLEVEL
;-------------------------------------------
;MOV CX,300000
;L1: PUSH CX
.repeat
CALL DELAY
CALL MOVESTEP
CALL SHOWBODY
;POP CX
;LOOP L1
.until 0
SCAN:
MOV AH,1
INT 16H
JZ SCAN
SCAN2:
MOV AH,1
INT 16H
JZ SCAN2
LAST:
MOV AH, 4CH
INT 21H
;===================================================
;(1) 设置彩色文本方式+清屏+清除光标的子程序
CLEARS PROC
;设置屏幕显示方式为80×25的彩色文本方式
MOV AH,00H
MOV AL,3
INT 10H
; 先用蓝色清屏
MOV AH,6
MOV AL,0
MOV BH,10H
MOV CX,0
MOV DL,59
MOV DH,24
INT 10H
;清除光标
MOV AH,01H
MOV CH,20H
INT 10H
RET
CLEARS ENDP
;-------------------------------------------------------------------------------
;(2) 从COORD为尾部的坐标开始,按照BODYY中的字符,
; 写内存LENGT中表示数字个字符到屏幕上的子程序
SHOWBODY PROC
MOV SI,OFFSET LENG
MOV CL, [SI]
MOV CH, 0H
MOV SI,OFFSET COOR
MOV DI,OFFSET BODY
SL1: ;设置光标位置
MOV AH,02H
MOV BH,0
MOV DH,[SI]
MOV DL,[SI+1]
INT 10H
;在当前光标位置处写字符
MOV AH,09H
PUSH CX ;保存CX的值
MOV AL,[DI]
MOV BH,0
MOV BL,40H;1FH ;红色
MOV CX,1
INT 10H
POP CX
ADD SI,2
ADD DI,1
LOOP SL1
RET
SHOWBODY ENDP
;-------------------------------------------------------------------------------
;(3)延时子程序
DELAY PROC
MOV CX,N
DL2:
PUSH CX
MOV CX,N
DL1:
LOOP DL1
POP CX
LOOP DL2
MOV AH,1
INT 16H
MOV DX,N
JNZ DL3
JMP DL4
DL3: CALL GETCHAR
CKBUF
DL4:
RET
DELAY ENDP
;-------------------------------------------------------------------------------
;(4)按照参数方向移动一步,同时擦去尾巴 的子程序
;即直接改变COOR中的坐标 ,LENGT为蛇当前长度
MOVESTEP PROC
MOV SI,OFFSET COOR ;先擦尾巴
MOV AH,02H
MOV BH,0
MOV DH,[SI]
MOV DL,[SI+1]
INT 10H
;在当前光标位置处写空白
MOV AH,09H
MOV AL,0H
MOV BH,0
MOV BL,1FH
MOV CX,1
INT 10H
;先将除头部外的坐标 前一个 放到 后一个 从后向前
MOV SI,OFFSET LENG
MOV CL, [SI]
MOV CH, 0H
DEC CX
MOV SI,OFFSET COOR
MLL: MOV AX, WORD PTR [SI+2]
MOV WORD PTR [SI],AX
ADD SI,2
LOOP MLL
;然后根据 DIRECTION 的不同值改变头部坐标
; 判断是否到达边界并修改坐标
;此时 SI 指的是头部坐标的内存位置
MOV DI,OFFSET DIRECTION
MOV DL,[DI]
CMP DL,77
JE ML0
CMP DL,72
JE ML1
CMP DL,75
JE ML2
CMP DL,80
JE ML3
ML0: ;INC BYTE PTR [SI+1]
MOV AL,[SI+1]
XOR AH,AH
INC AX
MOV BL,60
DIV BL
MOV [SI+1],AH
JMP MLEND1
ML1: ;DEC BYTE PTR [SI]
MOV AL,[SI]
XOR AH,AH
DEC AX
ADD AX,25
MOV BL,25
DIV BL
MOV [SI],AH
JMP MLEND1
ML2: ;DEC BYTE PTR [SI+1]
MOV AL,[SI+1]
XOR AH,AH
DEC AX
ADD AX,60
MOV BL,60
DIV BL
MOV [SI+1],AH
JMP MLEND1
ML3: ;INC BYTE PTR [SI]
MOV AL,[SI]
XOR AH,AH
INC AX
MOV BL,25
DIV BL
MOV [SI],AH
MLEND1: ;判断是否碰到食物,若是,则根据当前方向增长头部
MOV AX,WORD PTR [SI]
MOV DI,OFFSET FOOD
MOV BX,[DI]
CMP AX,BX
JNE MLEND2
;;;蜂鸣器
in al,61h
or al,3
out 61h,al
mov al,0b6h;控制字
out 43h,al
mov ax,1500
out 42h,al
mov al,ah
out 42h,al
call delay1
in al,61h
and al,0fch
out 61h,al
;;;
MOV DI,OFFSET LENG
MOV AL,[DI]
XOR AH,AH
DEC AX
INC BYTE PTR [DI]
MOV DI,OFFSET BODY
ADD DI,AX
;MOV BYTE PTR [DI], 'O'
MOV BYTE PTR [DI], '*'
;MOV BYTE PTR [DI+1], '#'
MOV BYTE PTR [DI+1], 'O'
MOV DI,OFFSET SCORE
INC BYTE PTR [DI]
CALL SHOWINFO
MOV AL, SCORE;变速
.IF AL==10
MOV AH, 3
MOV LENG, AH
MOV EBX, "O*-"
MOV DWORD PTR BODY, EBX
;清屏
MOV AH,6
MOV AL,0
MOV BH,10H
MOV CX,0
MOV DL,59
MOV DH,24
INT 10H
MOV AH,02H
MOV BH,0
MOV DH, 10
MOV DL, 22
INT 10H
MOV AH,9
MOV DX,OFFSET NEXTLEVEL
INT 21H
;升级播放音乐
PUSH DS
SUB AX,AX
PUSH AX
LEA SI,MUS_FREG
LEA BP,DS:MUS_TIME
FREG : MOV DI,[SI]
CMP DI,-1
JE END_MUS
MOV DX,DS:[BP]
MOV BX,1400
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
MOV AL,0B6H
OUT 43H,AL
MOV DX,12H
MOV AX,533H*896
DIV DI
OUT 42H,AL
MOV AL,AH
OUT 42H,AL
IN AL,61H
MOV AH,AL
OR AL,3
OUT 61H,AL
WAIT1: MOV CX,8FF0H
DELAY0: LOOP DELAY0
DEC BX
JNZ WAIT1
MOV AL,AH
OUT 61H,AL
POP DI
POP DX
POP CX
POP BX
POP AX
ADD SI,2
ADD BP,2
JMP FREG
END_MUS:
CALL delay1
CALL delay1
CALL delay1
;清屏
MOV AH,6
MOV AL,0
MOV BH,10H
MOV CX,0
MOV DL,59
MOV DH,24
INT 10H
XOR AH, AH
MOV SCORE, AH
CALL SHOWINFO
MOV BX, 12000
SUB BX, 2000
.IF BX < 5000
MOV BX, 4000
.endif
MOV N, BX
INC LEVEL
MOV AH,LEVEL
.IF AH == 5
MOV LEVEL, AH
.endif
CALL SHOWLEVEL
.endif
CALL SHOWLEVEL
;根据方向修改增长后的头部坐标 ,此时 SI 指向原来的头部
MOV DI,OFFSET DIRECTION
MOV AL,[DI]
CMP AL,77
JE ML00
CMP AL,72
JE ML01
CMP AL,75
JE ML02
CMP AL,80
JE ML03
ML00: MOV AL,[SI+1]
XOR AH,AH
INC AX
MOV BL,60
DIV BL
MOV [SI+3],AH
MOV BL,[SI]
MOV [SI+2],BL
JMP MFOOD
ML01: MOV AL,[SI]
XOR AH,AH
DEC AX
ADD AX,25
MOV BL,25
DIV BL
MOV [SI+2],AH
MOV BL,[SI+1]
MOV [SI+3],BL
JMP MFOOD
ML02: MOV AL,[SI+1]
XOR AH,AH
DEC AX
ADD AX,60
MOV BL,60
DIV BL
MOV [SI+3],AH
MOV BL,[SI]
MOV [SI+2],BL
JMP MFOOD
ML03: MOV AL,[SI]
XOR AH,AH
INC AX
MOV BL,25
DIV BL
MOV [SI+2],AH
MOV BL,[SI+1]
MOV [SI+3],BL
MFOOD:
CALL GENFOOD
MLEND2:
;
RET
MOVESTEP ENDP
;-------------------------------------------------------------------------------
;(5) 读取键盘输入并根据输入和原来的方向改变DIRECTION 的子程序 ,
; 并判断是否暂停
GETCHAR PROC NEAR
MOV AH,0H
INT 16H
cmp ah,01 ;为ESC键吗?
JE GEL2
CMP AH,81 ;先判断是否是Pagedown暂停
JE GEL1
MOV BL,AH
XOR BH,BH
MOV SI,OFFSET DIRECTION
MOV AL,[SI]
XOR AH,AH
ADD AX,BX
CMP AX, 152
JE GEND
MOV [SI],BL
JMP GEND
GEL1: CKBUF
MOV AH,0H
INT 16H
CMP AH,01
JE GEL2
CMP AH,81
JNE GEL1
JMP GEND
GEL2: MOV AH,4CH
INT 21H
GEND:
;CKBUF
RET
GETCHAR ENDP
;-------------------------------------------------------------------------------
;(6) 在 FOOD 内存 随机产生一个 坐标,并显示食物
GENFOOD PROC NEAR
GENL1:
rand 24
MOV BL,AH
rand 59
MOV BH,AH
MOV SI,OFFSET LENG
MOV CX,[SI]
MOV SI,OFFSET COOR
GENL2:
CMP BX,WORD PTR [SI] ;坐标相等
JE GENL1 ;直到吞食食物后重新随机显示食物
ADD SI,2
LOOP GENL2
MOV SI,OFFSET FOOD
MOV [SI],BX
;设置光标位置
MOV AH,02H
MOV BH,0
MOV DH,[SI]
MOV DL,[SI+1]
INT 10H
;在当前光标位置处写字符
MOV AH,09H
;MOV AL,'@'
MOV AL,'*'
MOV BH,0
MOV BL,1FH
MOV CX,1
INT 10H
RET
GENFOOD ENDP
;-------------------------------------------------------------------------------
; (7) 显示信息子程序
SHOWINFO PROC NEAR
;设置SCOINFO光标位置
PUSH SI
MOV AH,02H
MOV BH,0
MOV DH, 13
MOV DL, 67
INT 10H
;显示INFO
MOV AH,9
MOV DX,OFFSET SCOINFO
INT 21H
;转化SOCOE为SCORECHAR并显示
MOV SI,OFFSET SCOCHAR+3
MOV DI,OFFSET SCORE
MOV AL,[DI]
XOR AH,AH
MOV DX, 0H
MOV CX, 4
SLL1:DIV TEN2
MOV DI,AX
MOV AL,DL
ADD AL,30H
MOV [SI],AL
MOV AX,DI
DEC SI
MOV DX,0H
LOOP SLL1
MOV AH,9
MOV DX,OFFSET SCOCHAR
INT 21H
POP SI
RET
SHOWINFO ENDP
;SHOW LEVEL
SHOWLEVEL PROC NEAR
;设置LEVELINFO光标位置
MOV AH,02H
MOV BH,0
MOV DH, 14
MOV DL, 67
INT 10H
MOV AH,9
MOV DX,OFFSET LEVELINFO
INT 21H
MOV DI,OFFSET LEVEL
MOV AL, [DI]
ADD AL, 30H
MOV DL, AL
MOV AH, 02H
INT 21H
RET
SHOWLEVEL endp
;================================================
;Fountion:delay for a moment
;Input:None
;Output:None
;-----------------------------------------------------------
delay1 proc
pusha
mov ax,0100h
@1:
mov cx,0ffffh
@2:
dec cx
jne @2
dec ax
jne @1
popa
ret
delay1 endp
.EXIT
END
运行效果图如下: