1. 程式人生 > >8086彙編初學之貪吃蛇

8086彙編初學之貪吃蛇

前言

一直沒想過要去學習彙編,覺得需要用匯編的場合無非三種:
1. 與硬體結合很緊密高階語言做不到
2. 時空效率要求甚高演算法層面已不能優化到
3. 逆向破解等只能用某些途徑看其彙編指令
其餘情況下,用匯編無異於有炮不用偏用鳥槍。
本來準備等自己需求以上場合時再去學,但因為學校舉辦的彙編比賽,計算機學院都要參加,也算是一個由頭,於是開始了我的第一個彙編程式。

執行效果

程式碼只有400行,功能很簡略,實現了最基本的遊戲流程,看執行效果
這裡寫圖片描述

概述

本質上用匯編去寫一個貪吃蛇和用其他語言去實現沒什麼區別,不過是換一種方式表達,當然,是一種更加麻煩的方式。
以前用c++實現過

C++貪吃蛇C++俄羅斯方塊。所以對於這類小遊戲,該怎麼切是知道了,剩下的事就是找傢伙了。

要實現這類簡易的小遊戲,需要二點:
1. 定時器
2. 非阻塞接收按鍵
有上面兩者便可以搞定一切。
但在彙編下,為這兩點,耽擱了不少時間。不對,是三點,還有生成隨機數(原本很容易的事都變得麻煩了起來)。

定時器

事實上,查了很多資料,但還是不知道怎樣去實現定時器,所以這個需求只能變通的解決。
用空迴圈來控制時間。

非阻塞接受按鍵

getInput:
    mov al, 0
    mov ah, 1
    int 16h;檢視鍵盤緩衝區是否有資料
cmp ah, 1;ah為0表示有,否則沒有 je getInputEnd mov al, 0 mov ah, 0 int 16h;從緩衝區讀取資料 ;此時值已經在ax裡了,做你想做的 getInputEnd: ret

隨機數

    mov ax, 0h;間隔定時器
    out 43h, al;通過埠43h
    in al, 40h;
    in al, 40h;
    in al, 40h;訪問3次,保證隨機性

    ;如果對範圍並不需要精確,可以直接與運算來獲得,
    ;否則,用div取餘
    mov
bl, 18 div bl mov al, ah mov ah, 0;此時ax的值就是0~18的

程式碼

assume cs:code,ds:data,ss:stack

data segment
    sfood dw 0
    sdct dw 0
    sbody dw 400 dup(0)
data ends

stack segment
    dw 20 dup(0)
stack ends

code segment

start:
    mov ax, data
    mov ds, ax

    mov ax, stack
    mov ss, ax
    mov sp, 20

    mov ax, 0b800h
    mov es, ax

    mov si, 4 ;儲存資料段偏移量

    mov cx, 4;初始蛇長度
    mov ax, 0A04h

    s:;初始化蛇
        mov ds:[si], ax
        add si, 2
        inc al
        loop s

    mov ax, 4d00h;向右
    mov ds:[2], ax;初始化方向

    call clearBg;清屏
    call outBg;輸出地圖邊框
    call outBody;輸出蛇
    call creatFood;輸出食物

    mov cx, 30
    Game:
        push cx

        call updateBody

        mov cx, 0Fh
        aaaa1:
            push cx
            mov cx, 0FFFh
            bbbb:
                push cx
                call getInput
                pop cx
                loop bbbb
            pop cx
            loop aaaa1

        ;jmp GameEnd

        jmp Game


    GameEnd:    ;退出
        ;call outBody
        mov ax, 4c00h
        int 21h


updateBody:

    mov ax, ds:[2]
    mov di, si
    sub di, 2
    cmp ax, 4800h
    je shang

    mov ax, ds:[2]
    cmp ax, 5000h
    je xia

    mov ax, ds:[2]
    cmp ax, 4b00h
    je zuo

    mov ax, ds:[2]
    cmp ax, 4d00h
    je you

    shang:
        mov ax, ds:[di]
        sub ah, 1
        jmp checkBody

    xia:
        mov ax, ds:[di]
        add ah, 1
        jmp checkBody
    zuo:
        mov ax, ds:[di]
        sub al, 1
        jmp checkBody

    you:
        mov ax, ds:[di]
        add al, 1
        ;mov ds:[di], ax
        jmp checkBody

checkBody:
    push ax

    ;判斷蛇頭是否碰到地圖邊界
    cmp ah, 0
    je GameEnd
    cmp ah, 20
    je GameEnd
    cmp al, 0
    je GameEnd
    cmp al, 20
    je GameEnd

    ;判斷蛇頭是否碰到蛇身
    mov cx, si
    sub cx, 6
    mov di, 4

    s0: 
        mov bx, ds:[di]
        cmp bx, ax
        je GameEnd

        add di, 2
        sub cx, 1
        loop s0

    pop ax

    ;判斷蛇頭是否吃到食物
    mov bx, ds:[0]
    cmp ax, bx
    je addBody

    jmp updateStart

updateStart:
    mov cx, si
    sub cx, 6
    mov di, 4

    push ax

    mov dl, ' ';字元
    mov dh, 0;顏色
    mov bx, ds:[di]
    call outStr

    s5: 
        mov dx, ds:[di+2]
        mov ds:[di], dx

        add di, 2
        sub cx, 1
        loop s5

    mov dl, ' ';字元
    mov dh, 71h;顏色
    mov bx, ds:[di]
    call outStr

    pop ax
    mov ds:[di], ax

    mov dl, ' ';字元
    mov dh, 44h;顏色
    mov bx, ds:[di]
    call outStr


updateEnd:
    ret

addBody:
    mov dl, ' ';字元
    mov dh, 71h;顏色
    mov bx, ds:[di]
    call outStr

    mov ax, ds:[0]
    mov ds:[si], ax

    mov dl, ' ';字元
    mov dh, 44h;顏色
    mov bx, ds:[si]
    call outStr

    add si, 2

    call creatFood

    jmp updateEnd

getInput:;獲取鍵盤輸入

    mov al, 0
    mov ah, 1
    int 16h;接收鍵盤
    cmp ah, 1
    je getInputEnd

    mov al, 0
    mov ah, 0
    int 16h;
    mov cx, ax;鍵盤值在ax
    ;判斷輸入
    cmp cx, 4800h
    je gshang

    cmp cx, 5000h
    je gxia

    cmp cx, 4b00h
    je gzuo

    cmp cx, 4d00h
    je gyou

    jmp getInputEnd

    gshang:
        mov ax, ds:[2]
        cmp ax, 5000h
        je getInputEnd
        jmp fx

    gxia:
        mov ax, ds:[2]
        cmp ax, 4800h
        je getInputEnd
        jmp fx

    gzuo:
        mov ax, ds:[2]
        cmp ax, 4d00h
        je getInputEnd
        jmp fx

    gyou:
        mov ax, ds:[2]
        cmp ax, 4b00h
        je getInputEnd
        jmp fx

    fx:;更改方向標誌

        mov ds:[2], cx

    getInputEnd:
        ret;結束



outBody:
    mov cx, si
    sub cx, 6
    mov di, 4
    s1: 
        mov ax, ds:[di]

        mov dl, ' ';字元
        mov dh, 71h;顏色

        mov bl, al;列
        mov bh, ah;行
        call outStr

        add di, 2
        sub cx, 1
        loop s1
    mov dl, ' '
    mov dh, 44h
    mov ax, ds:[di]
    mov bl, al
    mov bh, ah
    call outStr
    ret

outBg:
    mov dl, ' ';字元
    mov dh, 71h;顏色

    mov bl, 0;列
    mov bh, 0;行

    mov cx, 20
    row:
        push cx

        push bx
        call outStr;上邊界
        pop bx

        push bx
        add bh, 20
        call outStr;下邊界
        pop bx

        inc bl;列加1

        pop cx

        loop row

    mov bl, 0;
    mov bh, 0;
    mov cx, 21
    col:
        push cx

        push bx
        call outStr;左邊界
        pop bx

        push bx
        add bl, 20
        call outStr;右邊界
        pop bx

        inc bh;行加1

        pop cx

        loop col
    ret

outStr: ;在指定位置輸出字元

    mov al, 80
    mul bh;行乘以80
    mov bh, 0

    add bl, bl;

    add ax, bx;加上列即為偏移量

    push si
    mov si, ax
    add si, si

    mov es:[si], dl
    mov es:[si+1], dh

    mov es:[si+2], dl
    mov es:[si+3], dh

    pop si
    ret

creatFood:;生成食物

    call getFoodPosition

    mov dl, ' '
    mov dh, 071h
    mov bx, ds:[0]

    call outStr

    ret


getFoodPosition:;獲取食物位置
    f1: 
        call getRand
        mov ds:[0], al
        call getRand
        mov ds:[1], al

        mov cx, si
        sub cx, 4
        mov di, 4
        s11: 
            mov ax, ds:[di]

            cmp ax, ds:[0]
            je f1

            add di, 2
            sub cx, 1
            loop s11

    ret

getRand:;獲取隨機數 範圍1~19

    mov ax, 0h;間隔定時器
    out 43h, al;通過埠43h
    in al, 40h;
    in al, 40h;
    in al, 40h;訪問3次,保證隨機性

    mov bl, 18
    div bl 

    mov al, ah
    mov ah, 0

    inc al

    ret

clearBg:    ;清屏
    mov ax, 3h
    int 10h
    ret


code ends

end start