?? zlfsnakev1.00.asm
字號(hào):
; 常量定義
EXITKEY = 1BH ; 退出鍵 ESC 的ASCII碼
TOP = 4 ; 左上角行坐標(biāo)
BUTTOM = 19 ; 右下角行坐標(biāo)
LEFT = 16 ; 左上角列坐標(biāo)
RIGHT = 64 ; 右下角列坐標(biāo)
SnakeLen = 64 ; 蛇長,暫時(shí)沒有用,但可供以后作為判斷勝得的條件
SNODE STRUC ; 聲明一個(gè)蛇結(jié)點(diǎn)結(jié)構(gòu)
nextY DB 0 ; 行坐標(biāo)
nextX DB 0 ; 列坐標(biāo)
char DB '*' ; 字符
color DB 0AH ; 顏色
SNODE ENDS
; 數(shù)據(jù)段
DSEG SEGMENT
colorBox DB 01H,02H,03H,04H,0EH,07H,05H ; 顏色盒
colorNum DB 7 ; 顏色數(shù),供產(chǎn)生隨機(jī)顏色函數(shù)用
currLen DB 4 ; 當(dāng)前有效長度,初始為4個(gè)節(jié)點(diǎn)
currPos DB 4DH ; 初始方向,向右
sHead SNODE <11,41,'O',0BH> ; 蛇頭
SNODE <11,40,'*',04H>
SNODE <11,39,'*',02H>
SNODE <11,38,'*',01H>
SNODE 60 DUP(<>)
sTail SNODE <0,0,' ',0> ; 蛇尾,用于覆蓋最后一個(gè)節(jié)點(diǎn)
food SNODE <> ; 食物點(diǎn)
DSEG ENDS
; 代碼段
CSEG SEGMENT 'code'
ASSUME CS:CSEG, DS:DSEG
START:
MOV AX,DSEG ; 哎,居然會(huì)忘記寫這兩行
MOV DS,AX ; 害我慘死了這么久
MOV CH,3 ; 開一個(gè)紅色窗口
MOV CL,15 ; 作邊框
MOV DH,20
MOV DL,65
MOV BH,4CH
MOV AL,0
MOV AH,6
INT 10H
MOV CH,TOP ; 開一個(gè)黑色窗口
MOV CL,LEFT ; 作為界面
MOV DH,BUTTOM
MOV DL,RIGHT
MOV BH,07H
MOV AL,0
MOV AH,6
INT 10H
CALL setFood ; 拋食
moving:
CALL setSnake ; 設(shè)置各節(jié)點(diǎn)將要出現(xiàn)的位置
CALL drawSnake ; 畫出各節(jié)點(diǎn)
CALL checkIfEat ; 檢查是否吃到食物
CALL delay ; 延時(shí)
JMP moving ; 循環(huán)
;===================================================================
; 子程序名: drawSnake
; 功能: 在屏幕上繪出蛇各節(jié)點(diǎn)
; 入口參數(shù): 無
; 出口參數(shù): 無
drawSnake PROC
PUSH SI ; 保護(hù)寄存器
PUSH AX
PUSH BX
PUSH CX
PUSH DX
XOR CX,CX ; CX賦當(dāng)前有效長度
MOV CL,currLen
MOV SI,OFFSET sHead ; SI指向蛇頭
draw:
MOV BH,0 ; 設(shè)置光標(biāo)位置
MOV DH,[SI].nextY
MOV DL,[SI].nextX
MOV AH,2
INT 10H
PUSH CX ; 保護(hù)好CX,LOOP draw要用到
MOV BH,0 ; 在光標(biāo)位置畫出相應(yīng)節(jié)點(diǎn)
MOV AL,[SI].char
MOV BL,[SI].color
XOR CX,CX
MOV CX,1
MOV AH,9
INT 10H
POP CX
CALL checkIfSelfMurder ; 檢查蛇頭是否咬中蛇身
ADD SI,TYPE SNODE ; SI指向下一個(gè)節(jié)點(diǎn)
LOOP draw
drawTail: ; 畫出蛇尾,覆蓋原來的痕跡
MOV BH,0
MOV DH,sTail.nextY
MOV DL,sTail.nextX
MOV AH,2
INT 10H
MOV AL,sTail.char
MOV BL,sTail.color
XOR CX,CX
MOV CX,1
MOV AH,9
INT 10H
POP DX ; 恢復(fù)寄存器
POP CX
POP BX
POP AX
POP SI
RET
drawSnake ENDP
;========================================================
; 子程序名: setNextPos
; 功能: 確定下一次移動(dòng)的方向,檢查是否需要退出
; 入口參數(shù): 無
; 出口參數(shù): 無
setNextPos PROC
PUSH AX
again0:
MOV AH,1
INT 16H
JZ ggSNP ; 無數(shù)據(jù)可讀,轉(zhuǎn)
MOV AH,0
INT 16H
CMP AL,EXITKEY ; 讀到退出鍵,退出
JZ ggMain0
CMP AH,4DH ; 右箭頭(小鍵盤 6),轉(zhuǎn)
JZ turnRight0
CMP AH,4BH ; 左箭頭(小鍵盤 4),轉(zhuǎn)
JZ turnLeft0
CMP AH,50H ; 上箭頭(小鍵盤 8),轉(zhuǎn)
JZ turnUp0
CMP AH,48H ; 下箭頭(小鍵盤 2),轉(zhuǎn)
JZ turnDown0
JMP again0 ; 否則,重新讀取
turnRight0:
CMP currPos,4BH ; 當(dāng)前方向是向左
JZ again0 ; 轉(zhuǎn)(不能逆行)
MOV currPos,4DH ; 置方向?yàn)橛? JMP ggSNP
turnLeft0: ; 以下處理都同turnRight0
CMP currPos,4DH
JZ again0
MOV currPos,4BH
JMP ggSNP
turnUp0:
CMP currPos,50H
JZ again0
MOV currPos,48H
JMP ggSNP
turnDown0:
CMP currPos,48H
JZ again0
MOV currPos,50H
JMP ggSNP
ggMain0: ; 退出程序
MOV AH,4CH
INT 21H
ggSNP: ; 退出子程序
POP AX
RET
setNextPos ENDP
;==========================================================
; 子程序名: setHead
; 功能: 設(shè)置蛇頭下一次將要移動(dòng)到的位置
; 入口參數(shù): 無
; 出口參數(shù): 無
setHead PROC
PUSH DI
MOV DI,OFFSET sHead
CALL setNextPos ; 設(shè)置前進(jìn)方向
CMP currPos,4DH ; 右向,轉(zhuǎn)
JZ turnRight1
CMP currPos,4BH ; 左向,轉(zhuǎn)
JZ turnLeft1
CMP currPos,48H ; 向上,轉(zhuǎn)
JZ turnUp1
CMP currPos,50H ; 向下,轉(zhuǎn)
JZ turnDown1
turnRight1:
INC [DI].nextX ; 列坐標(biāo)++
JMP ggSH
turnLeft1:
DEC [DI].nextX ; 列坐標(biāo)--
JMP ggSH
turnUp1:
INC [DI].nextY ; 這里好象反了,可是
JMP ggSH ; 這樣確實(shí)可以工作正常啊(???)
turnDown1:
DEC [DI].nextY ; 好象也反了(???)
JMP ggSH
ggSH:
POP DI
RET
setHead ENDP
;=================================================================
; 子程序名: setSnake
; 功能: 設(shè)置蛇身各節(jié)點(diǎn)下一次將要移動(dòng)到的位置
; 入口參數(shù): 無
; 出口參數(shù): 無
setSnake PROC
PUSH AX
PUSH DI
PUSH SI
PUSH CX
MOV DI,OFFSET sHead ; DI指向蛇頭
MOV SI,DI
SUB SI,TYPE SNODE ; SI指向蛇頭前一節(jié)
XOR CX,CX
MOV CL,currLen
DEC CL
scan0:
ADD DI,TYPE SNODE ; DI指向蛇尾
ADD SI,TYPE SNODE ; SI指向倒數(shù)第二個(gè)節(jié)點(diǎn)
LOOP scan0
MOV AL,[DI].nextX ; 設(shè)置sTail,以便覆蓋
MOV sTail.nextX , AL
MOV AL,[DI].nextY
MOV sTail.nextY , AL
XOR CX,CX
MOV CL,currLen
DEC CL
ReScan0: ; 由后開始往前掃描,每個(gè)節(jié)點(diǎn)下一次要運(yùn)行的
MOV AL,[SI].nextX ; 位置就是它前一個(gè)節(jié)點(diǎn)當(dāng)前所在位置
MOV [DI].nextX , AL
MOV AL,[SI].nextY
MOV [DI].nextY , AL
SUB DI,TYPE SNODE
SUB SI,TYPE SNODE
LOOP ReScan0
CALL setHead ; 設(shè)置蛇頭
CALL checkIfOutside ; 檢查是否越界,是,則從另一邊出來
POP CX
POP SI
POP DI
POP AX
RET
setSnake ENDP
;=======================================================
; 子程序名: checkIfSelfMurder
; 功能: 檢查蛇頭是否咬到蛇身
; 入口參數(shù): 無
; 出口參數(shù): 無
checkIfSelfMurder PROC
PUSH AX
PUSH DX
MOV DL,sHead.nextX
MOV DH,sHead.nextY
CALL checkIfBodyNode ; 檢查蛇頭是否是蛇身的一部分
CMP AX,0
JZ ggMain1 ; 是,結(jié)束程序
JMP ggCISM
ggMain1:
MOV AH,4CH
INT 21H
ggCISM:
POP DX
POP AX
RET
checkIfSelfMurder ENDP
;=======================================================
; 子程序名: Delay
; 功能: 延時(shí)(進(jìn)行AX * CX次循環(huán))
; 入口參數(shù): 無
; 出口參數(shù): 無
delay PROC
PUSH CX
PUSH AX
MOV AX,0000100111111111B
; MOV AX,0FFFFH
MoreTick:
MOV CX,1111111111111111B
OneTick:
LOOP OneTick
DEC AX
JNZ MoreTick
POP AX
POP CX
RET
delay ENDP
;======================================================================
; 子程序名: checkIfOutside
; 功能: 檢查是否越界
; 入口參數(shù): 無
; 出口參數(shù): 無
checkIfOutside PROC
CMP sHead.nextY,TOP-1
JNA fromButtom ; 超過頂線,從下面出來
CMP sHead.nextY,BUTTOM+1
JNB fromTop ; 超過底線,從上面出來
CMP sHead.nextX,LEFT-1
JNA fromRight ; 超過左線,從右邊出來
CMP sHead.nextX,RIGHT+1
JNB fromLeft ; 超過右線,從左邊出來
JMP ggCIO
fromButtom:
MOV sHead.nextY,BUTTOM ; 頭結(jié)點(diǎn)從最下邊開始出來
JMP ggCIO
fromTop:
MOV sHead.nextY,TOP ; 同上
JMP ggCIO
fromRight:
MOV sHead.nextX,RIGHT
JMP ggCIO
fromLeft:
MOV sHead.nextX,LEFT
JMP ggCIO
ggCIO:
RET
checkIfOutside ENDP
;=========================================================
; 子程序名: zlfRand
; 功能: 產(chǎn)生一個(gè)隨機(jī)數(shù)
; 入口參數(shù): AL = 下限, BL = 上限
; 出口參數(shù): AL = 隨機(jī)數(shù)
; 公式: (種子 * 23 + 89) % (上限 - 下限) + 下限
zlfRand PROC
PUSH BX
PUSH CX
PUSH DX
PUSH AX
MOV AH,2CH ; 獲取系統(tǒng)時(shí)間,做為種子
INT 21H
; MOV AL,DL ; 這里本來用百秒會(huì)達(dá)到更加隨機(jī)的效果
MOV AL,DH ; 但總是會(huì)溢出,就先用秒來做吧,AL = 種子
MOV CL,23
MUL CL ; AL * 23,結(jié)果在AX中
ADD AX,89
MOV CL,BL
POP BX ; BL為下限
SUB CL,BL
INC CL ; CL = 上限 - 下限
DIV CL ; 除,余數(shù)在AH中
ADD AH,BL
MOV AL,AH
POP DX
POP CX
POP BX
RET
zlfRand ENDP
;=================================================================
; 子程序名: checkIfBodyNode
; 功能: 檢查是否是蛇身上的一個(gè)點(diǎn)(不包括蛇頭)
; (因?yàn)樵跈z查是否自噬的時(shí)候會(huì)用的這里,所以不能包括蛇頭)
; 入口參數(shù): DL = X(列), DH = Y(行)
; 出口參數(shù): AX = 1(不是), AX = 0(是)
checkIfBodyNode PROC
PUSH SI
PUSH CX
MOV SI,OFFSET sHead
ADD SI,TYPE SNODE
XOR CX,CX
MOV CL,currLen
DEC CL
DEC CL
nextNode: ; 逐個(gè)掃描,比較每個(gè)節(jié)點(diǎn)的nextX,nextY是否與
CMP DL,[SI].nextX ; DL,DH完全相同
JNZ unEqual
CMP DH,[SI].nextY
JNZ unEqual
XOR AX,AX
JMP ggCIBN
unEqual:
ADD SI,TYPE SNODE
LOOP nextNode
XOR AX,AX
MOV AX,1
ggCIBN:
POP CX
POP SI
RET
checkIfBodyNode ENDP
;===================================================================
; 子程序名: setFood
; 功能: 設(shè)置食物點(diǎn)
; 入口參數(shù): 無
; 出口參數(shù): 無
setFood PROC
PUSH AX
PUSH BX
PUSH DX
PUSH SI
again1: ; 開始撒種,呵呵
XOR AX,AX
XOR BX,BX
XOR DX,DX
MOV AL,TOP ; 設(shè)置入口參數(shù):上限
MOV BL,BUTTOM ; 設(shè)置入口參數(shù):下限
CALL zlfRand ; 獲取隨機(jī)行號(hào)
MOV DH,AL ; 行號(hào)
MOV AL,LEFT ; 設(shè)置入口參數(shù)
MOV BL,RIGHT
CALL zlfRand ; 獲取隨機(jī)列號(hào)
MOV DL,AL ; 列號(hào)
CALL checkIfBodyNode ; 檢查是否撒到蛇身上了
CMP AX,0 ; 是,再撒過
JZ again1
CMP DL,sHead.nextX ; 檢查是否撒到蛇頭上了
JNZ noHead
CMP DH,sHead.nextY
JNZ noHead
JMP again1 ; 是,再撒過
noHead:
MOV food.nextY , DH
MOV food.nextX , DL
MOV AL,0 ; 獲取一種隨機(jī)顏色
MOV BL,colorNum
CALL zlfRand ; 隨機(jī)數(shù)在AL中
MOV SI,OFFSET colorBox
XOR AH,AH
ADD SI,AX
MOV AH,BYTE PTR [SI] ; 這里不能直接賦mov food.color, [si],
MOV food.color , AH ; 變量之間不能直接賦值
drawFood: ; 把食物點(diǎn)畫出來
MOV BH,0
MOV DH,food.nextY
MOV DL,food.nextX
MOV AH,2
INT 10H
MOV AL,food.char
; MOV AL,'*'
MOV BL,food.color
MOV CX,1
MOV AH,9
INT 10H
POP SI
POP DX
POP BX
POP AX
RET
setFood ENDP
;=================================================================
; 子程序名: addToTail
; 功能: 在蛇尾加上一個(gè)節(jié)點(diǎn)
; 入口參數(shù): 無
; 出口參數(shù): 無
addToTail PROC
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
MOV SI,OFFSET sHead
MOV DI,SI
ADD DI,TYPE SNODE
XOR CX,CX
MOV CL,currLen
DEC CL
scan1:
ADD DI,TYPE SNODE ; DI指向最后一個(gè)的下一個(gè)
ADD SI,TYPE SNODE ; SI最后一個(gè)
LOOP scan1
MOV AL,[SI].nextX ; 新添加節(jié)點(diǎn)下一次的位置
MOV [DI].nextX , AL ; 就是原來的最后的一個(gè)節(jié)點(diǎn)
MOV AL,[SI].nextY
MOV [DI].nextY , AL
MOV AL,food.color ; 顏色就是食物的顏色
MOV [DI].color , AL
MOV AL,food.char ; 字符就是食物的字符
MOV [DI].char , AL
INC currLen
drawNewTail: ; 畫出新添加的節(jié)點(diǎn)
MOV DH,[DI].nextY
MOV DL,[DI].nextX
MOV BH,0
MOV AH,2
INT 10H
MOV AL,[DI].char
MOV BL,[DI].color
MOV CX,1
MOV AH,9
INT 10H
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
RET
addToTail ENDP
;================================================================
; 子程序名: checkIfEat
; 功能: 檢查是否吃到食物
; 入口參數(shù): 無
; 出口參數(shù): 無
checkIfEat PROC
PUSH AX
MOV AL,food.nextX ; 其實(shí)就是判斷蛇頭坐標(biāo)與
CMP sHead.nextX , AL ; 食物坐標(biāo)是否重合而已
JNZ noEat
MOV AL,food.nextY
CMP sHead.nextY , AL
JNZ noEat
CALL addToTail ; 吃到食物了,添加到蛇尾
CALL setFood ; 重新撒種
noEat:
POP AX
RET
checkIfEat ENDP
;==================================================================
CSEG ENDS
END START
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -