汇编网首页登录博客注册
youthangel的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
文章收藏

[2013-01-01 08:19] 汇编版贪吃蛇(学完王爽老师的教材后写的,有注释)

;说明:运行环境XP或者DOSBOX,Win7不可以
;     编译环境masm 6.11以上版本
;能用的区域是,255*200,因为画不上去,把计分和计时放在右
;70pix大的位置
;移动过程,
;游戏结束标志
;没有解决的bug,食物坐标的产生
;需要改进的地方,字符串的显示
     comment            ;
   控制函数:
                1、获取键盘并修改方向标志位
                2、按标志位移动每个节点
                3、检测蛇的死亡
                4、获取蛇头将来位置的颜色值
                5、把食物放在5的倍数的位置上
                6、修改、显示计分计时
                活动范围:5-250,5-195
;
;补充知识
;1 、MOV AH,0 ;读时钟计数器值
;INT 1AH
;2、随机数 out 43h, al
;in al, 40h


;#mode=dos
.model        small
        data  segment
      snack:  db        150,150,'$'         ;以行列的方式存,方便调用
              dw        160 dup(0)    ;此处需空出足够的空间,否则会修改方向标志
      drect:  db        4dh           ;
       life:        db        1;生命值 1代表活着 0代表死亡

       food:  db        8 dup(0)

      times:  db        "time",'$'
       time:  db        "90",'$' ;上限90s
        temp: db        0;临时记录秒
      marks:  db        "mark",'$'
       mark:  db        "00",'$'  ;一节一分,60分过关
        data  ends
.code
      start:
              call      init        ;初始化                                                        
       goon:
              call      delay;延时
              ;call        ctime;改变时间
              mov       ch,0
              call      show_snack;擦除影子
              call      move;移动
   ;判断是否还活着
                   mov        ax,data
                   mov        ds,ax
                   mov        bx,life
                   mov        al,[bx]
                   cmp        al,0
                   je        home;如果蛇死亡退出
                   
              mov       ch,2              
              call      show_snack;显示
              mov       ah,0bh
              int       21h
              cmp       al,0        ;检测是否有输入
              je        goon        ;没有的话继续
              call      get_key     ;有的话进行处理              
              jmp       goon
         home:  
        
        ;返回16色文本模式      
              mov       ax,0001h
              int       10h
              
              mov        ax,cs
              mov        ds,ax
              mov        dx,offset mes
              mov        ah,9
              int        21h
              jmp        back2
         mes: db "Game over",'$'
         back2:
         ;暂停           
              mov       ah,0
              int       16h
        ;退出              
              mov       ax,4c00h
              int       21h
;------------------------------------------
;子程序的功能:
;        改变时间
;------------------------------------------
ctime:
;获取时间
push ax
push bx
push dx
push ds
mov ah,0
int 1ah;秒在dh中
mov ax,data
mov ds,ax
mov bx,offset temp
mov dl,[bx]
sub dl,dh
jz retc;相同的话退出
mov bx,offset time
mov ax,[bx]
sub ax,3030h
xchg al,ah
sub ax,1
xchg al,ah
add ax,3030h
mov [bx],ax
call stime
retc:
pop ds
pop dx
pop bx
pop ax
ret

;------------------------------------------
;子程序的功能:
;        移动每个节点
;--------------------------------------------------              
       move:
              push      ax
              push      bx
              push        cx
              push      ds
              push      dx
                
              mov       ax,data     ;指向数据段
              mov       ds,ax
                
        ;取得方向标志,修改所有节点的坐标
              mov       bx,drect
              mov       ah,[bx]
              mov       bx,snack    ;取出蛇头准备移动
              mov       dx,[bx]     ;保存蛇头
                ;进行比较
              cmp       ah,48h
              je        up          ;上
              cmp       ah,50h
              je        down        ;下
              cmp       ah,4bh
              je        left        ;左
              cmp       ah,4dh
              je        right       ;右
         up:
              mov       ax,[bx]     ;取出来              
              sub       al,5        ;修改
              cmp        al,4
              jna        dead   
              
              push        ax
              push        bx
              push        dx
              mov        bh,0;页号
              mov        dx,0
              sub        al,3;保证关键点在中部
              mov        dl,al;行
              mov        cx,0
              mov        cl,ah;列
              mov        ah,0dh;功能号
              int        10h;颜色在al中
              
              pop        dx
              pop        bx
              pop        cx;用cx保存取颜色前的ax
              cmp        al,2;蛇的颜色是2
              je        dead
              cmp        al,3;食物颜色是3
              je        eat
              
              mov       [bx],cx     ;写回去,cx中是当前蛇头的位置
              jmp       show_next       
       down:
              mov       ax,[bx]     ;取出来
              add       al,5        ;修改
              cmp        al,195
              jnb        dead;死亡             
             
             push        ax
              push        bx
              push        dx
              mov        bh,0;页号
              mov        dx,0
              add        al,3;保证关键点在中部
              mov        dl,al;行
              mov        cx,0
              mov        cl,ah;列
              mov        ah,0dh;功能号
              int        10h;颜色在al中
              
              pop        dx
              pop        bx
              pop        cx;用cx保存取颜色前的ax
              cmp        al,2;蛇的颜色是2
              je        dead
              cmp        al,3;食物颜色是3
              je        eat
              
              mov       [bx],cx     ;写回去
              jmp       show_next
       left:
              mov       ax,[bx]     ;取出来
              sub       ah,5        ;修改
              cmp        ah,4
              jna        dead
            
              push        ax
              push        bx
              push        dx
              mov        bh,0;页号
              mov        dx,0
              sub        ah,3;保证关键点在中部
              mov        dl,al;行
              mov        cx,0
              mov        cl,ah;列
              mov        ah,0dh;功能号
              int        10h;颜色在al中
              
              pop        dx
              pop        bx
              pop        cx;用cx保存取颜色前的ax
              cmp        al,2;蛇的颜色是2
              je        dead
              cmp        al,3;食物颜色是3
              je        eat
              
              mov       [bx],cx     ;写回去
              jmp       show_next
      right:
              mov       ax,[bx]     ;取出来
              add       ah,5        ;修改
              cmp        ah,250
              jnb        dead
             
             push        ax
              push        bx
              push        dx
              mov        bh,0;页号
              mov        dx,0
              add        ah,3;保证关键点在中部
              mov        dl,al;行
              mov        cx,0
              mov        cl,ah;列
              mov        ah,0dh;功能号
              int        10h;颜色在al中
              
              pop        dx
              pop        bx
              pop        cx;用cx保存取颜色前的ax
              cmp        al,2;蛇的颜色是2
              je        dead
              cmp        al,3;食物颜色是3
              je        eat
              
              mov       [bx],cx     ;写回去
              jmp       show_next      
      dead:
                      mov        bx,life
                      mov        al,[bx]
                      mov        al,0
                      mov        [bx],al;修改为死亡
                      jmp        retnext
                ;移动每个节点,第一个节点已经移动
  show_next:
              add       bx,2
              mov       ax,[bx]     ;取出下一个节点坐标
              cmp       al,'$'
              je        retnext
              xchg      dx,ax       ;跟上一个节点坐标交换
              mov       [bx],ax     ;在写回去
              jmp       show_next
                           
    retnext:
              pop       dx
              pop       ds
              pop        cx
              pop       bx
              pop       ax
              ret
              
        eat:
            ;把当前蛇头位置放回去
        ;保存蛇头ax
        ;取出下一个节点
                mov        [bx],cx
        next:   
                add        bx,2
                mov        ax,[bx]                        
                xchg        dx,ax;交换节点,保存在dx中
                mov        [bx],ax
                cmp        dl,'$'
                je        return;
                jmp        next
        return:
                add        bx,2
                mov        [bx],dx;把最后一个节点放回去
                call        show_food;吃完以后产生一个食物
                call        chgmark;修改分数
                jmp        retnext
                
;-------------获取按键子程序----------------------
;子程序的功能:
;        根据键盘值的上下左右修改方向标志
;--------------------------------------------------                
chgmark:
push ax
push ds
push bx
mov ax,data
mov ds,ax
mov bx,offset mark
mov ax,[bx]
xchg al,ah;高低位互换
inc ax
xchg al,ah
mov [bx],ax
call        smark
pop bx
pop ds
pop ax
ret
;-------------获取按键子程序----------------------
;子程序的功能:
;        根据键盘值的上下左右修改方向标志
;--------------------------------------------------     
    get_key:
              push      ax
              push      bx
              push      ds
              mov       ax,data
              mov       ds,ax
              mov       bx,drect
                    
              mov       ah,0
              int       16h                                       
                
              cmp       ah,50h
              je        down1       ;下
              cmp       ah,4dh
              je        right1      ;右
              cmp       ah,48h
              je        up1         ;上
              cmp       ah,4bh
              je        left1       ;左
              
      retsw:
              pop       ds
              pop       bx
              pop       ax
              ret
              ;如果键盘方向和当前方向相反,退出
        up1:
              mov       al,[bx]     ;取出来
              cmp        al,50h
              je        retsw
              mov       al,48h        ;修改
              mov       [bx],al     ;写回去
              jmp       retsw
      down1:
              mov       al,[bx]     ;取出来
              cmp        al,48h
              je        retsw
              mov       al,50h        ;修改
              mov       [bx],al     ;写回去
              jmp       retsw
              
     right1:
              mov       al,[bx]     ;取出来
              cmp        al,4bh
              je        retsw
              mov       al,4dh        ;修改
              mov       [bx],al     ;写回去
              jmp       retsw
              
      left1:
              mov       al,[bx]     ;取出来
              cmp        al,4dh
              je        retsw
              mov       al,4bh        ;修改
              mov       [bx],al     ;写回去
              jmp       retsw    
;--------------------------------------------------
;子程序的功能延时0.5s
;--------------------------------------------------       
      delay:
                
              push      ax
              push      bx
              push      cx
              mov       bx,4
                ;执行完33144次是0.5s
      again:  mov       cx,33144
      waitf:
              in        al,61h      ;跟61h端口的pb4有关
              and       al,10h
              cmp       al,ah
              je        waitf
              mov       ah,al
              loop      waitf
              dec       bx
              jnz       again
              pop       cx
              pop       bx
              pop       ax
              ret
;----------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------------------
;                                           以下为各种显示子函数
;                init、bound、show_snack、show_food、rec、line、pixel
;----------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------------------


;----------------初始化子程序------------------------
;子程序的功能:
;        修改显示模式、显示蛇、墙体、食物、计时、分数
;参数:无
;--------------------------------------------------
       init:
        ;显示time
                push        ax
                push        cx
                push        ds
                push         bx
              mov       ax,0013h
              int       10h         ;设置图形显示模式320*200 256色VGA
                
             call          stime
             call         smark
              mov       ch,2
              call      show_snack
              call      show_food
              call      bound
              
                ;mov ah,0
                ;int 1ah;秒在dh中
                ;mov ax,data
                ;mov ds,ax
                ;mov bx,offset temp
                ;mov [bx],dh
                
              pop        bx
              pop        ds
              pop        cx
              pop        ax
              ret
;----------------显示时间子程序------------------------
;子程序的功能:
;        修改计时
;参数:无
;--------------------------------------------------              
        stime:
                push ax
                push bx
                push dx
                push ds
              mov       ah,2
              mov       bh,0
              mov       dh,2        ;行
              mov       dl,34       ;列
              int       10h
                    
              mov       ax,data
              mov       ds,ax
              mov       dx,times
              mov       ah,9
              int       21h
                    
              mov       ah,2
              mov       bh,0
              mov       dh,7        ;行
              mov       dl,34       ;列
              int       10h
                                                            
              mov       dx,time     ;时间值
              mov       ah,9
              int       21h 
              
              pop        ds
              pop         dx
              pop         bx
              pop        ax
        ret
;----------------显示分数程序----------------------
;子程序的功能:
;        修改分数
;参数:无
;--------------------------------------------------         
        smark:        
                ;显示mark
                push ax
                push bx
                push dx
                push ds
              mov       ah,2
              mov       bh,0
              mov       dh,90       ;行
              mov       dl,50       ;列
              int       10h
                
                mov       ax,data
              mov       ds,ax                                        
              mov       dx,marks
              mov       ah,9
              int       21h
                    
              mov       ah,2
              mov       bh,0
              mov       dh,96       ;行
              mov       dl,50       ;列
              int       10h
                                        
              mov       dx,mark     ;分值
              mov       ah,9
              int       21h
              
              pop        ds
              pop         dx
              pop         bx
              pop        ax
        ret
;----------------显示边界线程序------------------------
;子程序的功能:
;        画出可用屏幕的边界线,蓝色为蛇的活动范围
;-----------------------------------------------------        
      bound:
              push      ax
              push      bx
              push      si
              push      di
              push      cx
                
                ;下
              mov       bx,0
              mov       ax,199      ;(0,199)
              mov       si,255
              mov       di,199      ;(255,199)
              mov       ch,5
              call      line
              
              mov       bx,4
              mov       ax,196      ;(4,196)
              mov       si,251
              mov       di,196      ;(251,196)
              call      line
                                
                ;左
              mov       bx,0
              mov       ax,0        ;(0,0)
              mov       si,0
              mov       di,199      ;(0,199)
              call      line
              
              mov       bx,4
              mov       ax,4       ;(4,4)
              mov       si,4
              mov       di,196      ;(4,196)
              call      line
                
                ;上
              mov       bx,0
              mov       ax,0        ;(0,0)
              mov       si,255
              mov       di,0        ;(255,0)
              call      line
              
              mov       bx,4
              mov       ax,4        ;(4,4)
              mov       si,251
              mov       di,4        ;(251,4)
              call      line
                
                ;右
              mov       bx,255
              mov       ax,0        ;(255,0)
              mov       si,255
              mov       di,199      ;(255,199)
              call      line
              
              mov       bx,251
              mov       ax,4        ;(251,4)
              mov       si,251
              mov       di,196      ;(251,196)
              call      line
                
        ;多出来的65pix
                ;右
              mov       bx,319
              mov       ax,0        ;(319,0)
              mov       si,319
              mov       di,199      ;(319,199)
              mov       ch,4
              call      line
                ;左
              mov       bx,256
              mov       ax,0        ;(255,0)
              mov       si,256
              mov       di,199      ;(256,199)
              call      line
                ;上
              mov       bx,256
              mov       ax,0        ;(256,0)
              mov       si,319
              mov       di,0        ;(319,0)
              call      line
                ;下
              mov       bx,256
              mov       ax,199      ;(256,119)
              mov       si,319
              mov       di,199      ;(319,199)
              call      line
                
              pop       cx
              pop       di
              pop       si
              pop       bx
              pop       ax
              ret
;----------------显示蛇身子程序------------------------
;子程序的功能:
;        在屏幕上显示蛇身
;参数:
;        snack地址标号的坐标数据遇,'$'结束
;        蛇身颜色,ch
;-----------------------------------------------------                                        
 show_snack:
              push      ax          ;保护现场
              push      ds
              push      bx
              push      cx
                
              mov       ax,data
              mov       ds,ax
              mov       bx,0
 show_again:
              mov       ax,snack
              add       bx,ax
              mov       ax,[bx]
              cmp       al,'$'
              je        retsnack
              call      rec
              add       bx,2
              jmp       show_again
   retsnack:
              pop       cx
              pop       bx
              pop       ds          ;恢复现场
              pop       ax
              ret

;----------------显示食物子程序------------------------
;子程序的功能:
;        在屏幕上随机显示一个食物(不能和蛇身重合)
;参数:无
;算法:
;        利用40端口产生随机数,并把这个坐标记录放在food的结构体中
;-----------------------------------------------------        
  show_food:
              push      ax
              push      bx          ;保护现场
              push      ds
              push      cx
                  
              xor al, al
              out 43h, al
              in  ax,40h
              
              mov       bl,190      ;再大就要超出屏幕了
              div       bl          ;得到不大于190的余数
              mov        al,ah
              mov        ah,0
              mov        bl,5
              div        bl;用得到的不大于5的余数除以5在乘以5(我同学想到的)              
              mov        ah,0
              mul        bl;乘以5                            
              mov       bh,al;保存得到的横坐标
              
              xor al, al
              out 43h, al
              in        ax,40h
              mov       bl,245      ;再大就要超出边界了
              div       bl ;用得到的不大于5的余数除以5在乘以5(我同学想到的)              
              mov       al,ah
              mov        ah,0
              mov        bl,5
              div        bl              
              mul        bl;得到纵坐标在al中             
              mov       ah,bh      ;行列坐标放在bx中,接下来是查找是否是蛇身的某个节点
              mov       bx,data
              mov       ds,bx
              mov       bx,food
              add        ax,0505h;保证食物不在墙体上出现
              mov       [bx],ax     ;保存食物的位置,也可以不保存
              mov       ch,3
              call      rec
                
              pop       cx
              pop       ds
              pop       bx
              pop       ax          ;恢复现场
              ret
                
;----------------画矩形子程序------------------------
;子程序的功能:
;        在指定左上角和右下角坐标画矩形
;参数:
;        左上角坐标(ah,al)列行 < 右下角坐标(bl,bh)颜色值ch
;        (bx,ax)列行 (si,di)
;--------------------------------------------------
        rec:
              push      ax
              push      bx
              push      cx          ;保护现场
              push      dx
              push      si
              push      di
              mov       bl,ah
              mov       bh,al
              add       bx,0404h    ;算出右下角的坐标
        ;以左上角为主
              push      ax
              push      bx
                ;左线(ah,al) (ah,bh)        
              mov       dx,bx       ;保存bx
              mov       bx,0
              mov       bl,ah
              mov       ah,0        ;开始坐标准备完毕
                
              mov       si,bx
              push      dx
              mov       cl,dh
              mov       dx,0
              mov       dl,cl
              mov       di,dx
              pop       dx          ;结束坐标准备完毕
              push      ax
              push      bx          ;下面要用ax,bx
              call      line
              pop       bx
              pop       ax
                  ;上线
              mov       di,ax
              mov       dh,0
              mov       si,dx
              call      line
              pop       bx
              pop       ax          ;ax,bx恢复为刚进入子程序时的状态
          ;以右下角为主     
                  ;右线
              mov       dx,ax
              mov       ax,0
              mov       al,bh
              mov       bh,0
              mov       si,bx
              mov       di,ax       ;结束坐标完毕
              mov       bx,si
              mov       al,dl
              push      di
              push      si
              call      line
              pop       si
              pop       di
                 ;下线  
              mov       bl,dh
              mov       ax,di
              call      line
          
              pop       di          ;恢复现场
              pop       si
              pop       dx
              pop       cx
              pop       bx
              pop       ax
              ret
;----------------画线子程序------------------------
;子程序的功能:
;        在指定坐标画线,只能画水平和垂直的线
;参数:
;        起点坐标(bx,ax)列行,终点坐标(si,di)颜色值ch
;--------------------------------------------------
       line:
              push      ax
              push      bx
              push      si
              push      di
              push      cx          ;保护现场
              push      dx
                
              cmp       di,ax
              je        level       ;水平画线
              cmp       si,bx       ;求差
              je        perp        ;垂直画线
      level:                        ;水平线
              sub       si,bx       ;si代表要画的的总列数,bx代表但前要画的列(行在ax中),颜色在ch中
              inc       si          ;相减会少一
       putl:
              call      pixel       ;调用子程序,显示一个点
              inc       bx          ;指向下一列
              dec       si          ;列数减一
              jnz       putl        ;重复调用画点,连成线
       back:
              pop       dx          ;恢复现场
              pop       cx
              pop       di
              pop       si
              pop       bx
              pop       ax
              ret
             
       perp:                        ;垂直线
              sub       di,ax       ;di代表要画的的总列数,bx代表但前要画的列(行在ax中),颜色在ch中
              inc       di          ;相减会少一
       putp:
              call      pixel       ;调用子程序,显示一个点
              inc       ax          ;指向下一列
              dec       di          ;列数减一
              jnz       putp        ;重复调用画点,连成线
              jmp       short back
                
;----------------画点子程序------------------------
;画点子程序的功能:
;        在指定坐标画点
;参数:
;        坐标(bx,ax)列行,颜色值ch
;--------------------------------------------------
      pixel:
              push      ax
              push      bx
              push      dx
              push      di
              push      es          ;保护现场,ax,bx本来不用的,为了方便以后的调用就保护了
              
              mov       dx,0a000h   ;图形的开始内存,相当于文本模式的0b800h
              mov       es,dx
              mov       dx,320
              mul       dx          ;算出第n行的内存地址dx:ax
              add       ax,bx       ;算出n行中的m列
              mov       di,ax
              mov       es:[di],ch  ;给这个单元赋颜色值
              
              pop       es          ;恢复现场
              pop       di
              pop       dx
              pop       bx
              pop       ax
              ret
              end       start
评论次数(2)  |  浏览次数(26407)  |  类型(冥思苦想) |  收藏此文  | 

[  游客   发表于  2013-01-04 18:36  ]

很不错。

[  游客   发表于  2013-01-19 08:43  ]

楼主好厉害,挺一下!

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码