分享

Dwing写的471字节俄罗斯方块(teris)汇编程序源代码

 skywood 2008-02-26

记得自己最早玩的一款游戏就是俄罗斯方块,那种拿在手上黑白的机器,整部机器上只有这么一个游戏。不像现在可以有成百上千个。不过当时就一直好奇,这个游 戏为什么叫做“俄罗斯”方块……后来才知道俄罗斯方块的发明者,是当时还被称为”苏联”的联邦科学员阿莱克斯?帕吉托夫(Alexey Pazhitnov ),最后该游戏的代理权最终还是被任天堂获得,将它与GB搭配在一起后,产生了令人意想不到的效果,获得了巨大的成功。

到了今天俄罗斯方块的原理差不多已经到了“世人皆知”的地步了(对不起,夸张了点),不过很多计算机专业或者对此有兴趣的爱好者,都自己动手写过这 个游戏,Dwing,不少用汇编的人都知道这个名字,是一个汇编牛人,他写了一个编译后仅仅471字节的俄罗斯方块,可谓经典之作。该程序发布在 Dwing的主页上,不过好像嵌入了一点我觉的“不友好”的代码,所以在这里不给出这个外部链接了。有兴趣的可以自己Google一下Dwing,很容易 找到的。下面是这个经典的471字节俄罗斯方块汇编程序源代码及详细注释:

1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            45
            46
            47
            48
            49
            50
            51
            52
            53
            54
            55
            56
            57
            58
            59
            60
            61
            62
            63
            64
            65
            66
            67
            68
            69
            70
            71
            72
            73
            74
            75
            76
            77
            78
            79
            80
            81
            82
            83
            84
            85
            86
            87
            88
            89
            90
            91
            92
            93
            94
            95
            96
            97
            98
            99
            100
            101
            102
            103
            104
            105
            106
            107
            108
            109
            110
            111
            112
            113
            114
            115
            116
            117
            118
            119
            120
            121
            122
            123
            124
            125
            126
            127
            128
            129
            130
            131
            132
            133
            134
            135
            136
            137
            138
            139
            140
            141
            142
            143
            144
            145
            146
            147
            148
            149
            150
            151
            152
            153
            154
            155
            156
            157
            158
            159
            160
            161
            162
            163
            164
            165
            166
            167
            168
            169
            170
            171
            172
            173
            174
            175
            176
            177
            178
            179
            180
            181
            182
            183
            184
            185
            186
            187
            188
            189
            190
            191
            192
            193
            194
            195
            196
            197
            198
            199
            200
            201
            202
            203
            204
            205
            206
            207
            208
            
;2006年新年公开我写的471字节俄罗斯方块汇编程序源代码及详细注释!
            ;471 bytes GAME! By Dwing
            ;Only for DOS/Win9x/WinME/DosBox(注意不能直接在Win2000以上系统运行)
            .model tiny
            .386
            .code
            $shape  equ 008h
            $backg  equ 0dbh
            $up     equ 72
            $left   equ 75
            $right  equ 77
            $down   equ 80
            org 100h
            start:  int 10h                 ;设置显示模式0(40*25*16色字符模式)
            push 0b800h             ;字符缓冲区段=b800h
            pop ds                  ;ds=b800h
            push ds
            pop es                  ;es=b800h
            xchg ax,di              ;di=0000h
            mov ax,0700h+$backg     ;开始画边框,ax=字符(0dbh)及属性(灰色)
            mov cx,ax               ;cx=数量
            rep stosw               ;覆盖全屏
            mov ax,0e30h            ;开始画数码框,ax=字符(‘0‘)及属性(黄色)
            mov cl,6                ;cl=数字个数(6)
            mov di,2*(40*23+17)     ;di=数字显示屏幕偏移位置
            rep stosw               ;显示数码
            xor ax,ax               ;开始画中间空框,ax=空字符
            mov di,2*(40*2+15)      ;di=空框第一行屏幕偏移位置
            @nextbl:mov cl,10               ;cl=每行块数(10)
            rep stosw               ;画一行空格
            add di,2*(15+15)        ;计算下一行屏幕偏移位置
            cmp di,2*(40*22+15)     ;判断是否画完最后一行(共20行)
            jb  short @nextbl       ;没画完则循环
            @rernd: in  al,40h              ;开始随机选择方块类型,al=时间随机值
            and al,0111b            ;al只取0-7
            jz  short @rernd        ;如果是0则重新选择(只选1-7,共7种)
            dec ax                  ;1-7变为0-6
            mov bx,2*(40*2+15+4)    ;方块起始屏幕偏移位置
            jnz short @t            ;如果不是0(长条形方块需特殊处理)则跳转
            mov bx,2*(40+15+4)      ;长条形方块的起始屏幕偏移位置上移一行
            @t:     xchg ax,bp              ;bp=方块起始屏幕偏移位置
            call @isok              ;判断新产生的方块能否放置
            jz  short @goon         ;能放置则跳转
            @end:   call @dispb             ;不能放置情况:先显示方块
            push cs
            pop ds                  ;ds=当前程序段
            lea dx,msg1             ;dx="GAMEOVER"信息地址
            mov ah,9                ;ah=9(显示字符串)
            int 21h                 ;显示"GAMEOVER"
            @esc:   in  al,60h              ;读键盘
            dec al                  ;"ESC"扫描码=1
            jnz short @esc          ;如果没有按"ESC"则跳回继续读键盘
            mov ax,3                ;ax=DOS默认显示模式(3)
            int 10h                 ;设置显示模式3(80*25*16色字符模式)
            retn                    ;退出
            @goon:  mov cl,0ffh             ;新方块能放置情况:先进入延时状态
            cmp cl,40h              ;cl=循环等待次数
            jae short @wait         ;确认cl不小于40
            mov cl,40h
            @wait:  call @dispb             ;显示当前新方块
            push cx                 ;进入等待状态
            xor cx,cx               ;cx=等待时间(微秒)低字
            mov dx,1000             ;dx=等待时间(微秒)高字
            mov ah,86h
            int 15h                 ;等待
            pop cx                  ;退出等待状态
            @t4:    mov ah,1
            int 16h                 ;判断键盘缓冲区是否有字符
            jz  short @loop         ;没有按键则跳出键盘处理部分
            xor ax,ax
            call @disp              ;清除新方块的显示
            int 16h                 ;读取键盘缓冲区字符=>ah
            mov al,ah               ;al=ah
            cmp al,$up              ;判断是否是上方向键
            jnz short @k1           ;不是则跳转
            push bp                 ;保存当前新方块的摆放形状
            movzx bp,cs:[bp+bkv]    ;改变新方块的摆放形状
            call @isok              ;判断是否能放置
            jz  short @loop_        ;能放置则跳出键盘处理部分
            pop bp                  ;不能放置则恢复新方块原来形状
            loop @wait              ;继续下一次等待
            @k1:    push bx                 ;保存当前新方块的位置
            cmp al,$left            ;判断是否是左方向键
            jnz short @k2           ;不是则跳转
            dec bx                  ;新方块左移一个位置(2个字节)
            dec bx
            @test:  call @isok              ;判断是否能放置
            jz  short @loop_        ;能放置则跳出键盘处理部分
            pop bx                  ;不能放置则恢复新方块原来位置
            loop @wait              ;继续下一次等待
            @k2:    cmp al,$right           ;判断是否是右方向键
            jnz short @k3           ;不是则跳转
            inc bx                  ;新方块右移一个位置(2个字节)
            inc bx
            jmp short @test         ;剩下的处理同"左方向键"
            @k3:    pop bx                  ;恢复新方块原来位置
            cmp al,1                ;判断是否是ESC键
            jz  short @end          ;如果是则跳转到退出程序段
            jmp short @ok           ;如果是其他按键则跳出延时状态
            @loop_: pop ax                  ;清除保存的新方块位置
            @loop:  loop @wait              ;继续下一次等待
            @ok:    push ax                 ;保存按键扫描码
            xor ax,ax               ;延时过后进入方块下落部分
            call @disp              ;清除新方块的显示
            add bx,2*40             ;新方块下移一个位置(2个字节)
            call @isok              ;判断是否能放置
            pop ax                  ;恢复按键扫描码
            jnz short @down         ;如果不能放置新方块则跳转
            cmp al,$down            ;判断是否是下方向键
            jz  short @ok           ;如果是则继续下落
            jmp short @goon         ;不是则进入下一次延时
            @down:  sub bx,2*40             ;恢复新方块原来位置
            call @dispb             ;显示新方块
            xor ax,ax               ;进入判断是否有一行已满
            mov dx,ax               ;ax=dx=0
            mov si,2*(40*2+15)      ;si=中间空框的起始屏幕偏移位置
            @nextl: mov di,si               ;di=当前判断的屏幕偏移位置
            mov cl,11               ;判断10次(10+1)
            repnz scasw             ;扫描一行
            jz  short @skip         ;如果有空位则跳出
            pusha                   ;进入消除一行部分
            mov si,di
            sub si,2*40             ;si=上一行屏幕偏移位置
            mov cx,si               ;cx=移动字符个数
            std
            rep movsb               ;移下一行
            cld
            mov di,2*(40*2+15)      ;di=中间空框最上一行的屏幕偏移位置
            mov cl,10               ;一行10个方块
            rep stosw               ;清除最上一行
            popa                    ;退出消除一行部分
            inc dx                  ;分数基值+1
            add dh,dl               ;累计当前分数
            @skip:  add si,2*40             ;下一行偏移位置
            cmp si,2*(40*22)        ;判断是否判断完所有行
            jb  short @nextl        ;没有则继续下一行判断
            and dx,dx               ;判断是否有得到当前的分数
            jz  short @t_           ;没有则跳过
            @t00:   mov di,2*(40*23+21)     ;数码位屏幕偏移位置(第2位)
            @t0:    mov byte ptr[di],30h    ;置0
            dec di                  ;进一位(倒退2个字节长度)
            dec di
            cmp di,2*(40*23+20)     ;判断是否进入第3位
            jnz short @t000         ;如果不是则跳过
            dec byte ptr cs:[@goon+1];每100分等待次数减1(加速)
            @t000:  inc byte ptr[di]        ;当前数码位+1
            cmp byte ptr[di],3ah    ;判断数码位是否超过9
            jz  short @t0           ;如果是则跳转(进位)
            dec dh                  ;当前分数累计值-1
            jnz short @t00          ;如果分数没加完则继续累加
            @t_:    jmp @rernd              ;继续产生下一个新方块
            @isok:  mov si,bp               ;判断是否能放置方块子模块
            shl si,2                ;si=方块形状标号*4(占4个字节)
            xor ax,ax
            mov dx,ax               ;ax=dx=0
            add si,offset bks       ;si=方块形状位置描述指针
            push cx                 ;保存cx
            mov cl,4                ;cl=方块数(4)
            @nextb: db 2eh                  ;lodsb cs: (al<=cs:[si])
            lodsb                   ;载入方块位置描述(位置偏移)
            mov di,ax
            or  dx,[di+bx]          ;判断小方块是否冲突
            loop @nextb             ;继续判断下一个位置描述
            pop cx                  ;恢复cx
            retn                    ;返回
            @dispb: mov al,$shape           ;显示方块子模块,al=方块形状标号
            mov ah,cs:[bp+bkc]      ;ah=方块颜色值
            @disp:  mov si,bp
            shl si,2                ;si=方块形状标号*4(占4个字节)
            push cx                 ;保存cx
            mov cl,4                ;cl=方块数(4)
            @nextb_:movzx di,cs:[si+bks]    ;取方块描述
            mov [di+bx],ax          ;显示一个小方块
            inc si                  ;si=下一个位置描述
            loop @nextb_            ;继续画下一个小方块
            pop cx                  ;恢复cx
            retn                    ;返回
            bkc     db  2                   ;方块颜色值
            db  9,12,13,14, 11,10
            db  9,9,9,      12,13
            db  11,11,11,   10,10,10
            db  2
            bkv     db  18                  ;方块形状链表
            db  7,10,11,4,  12,15
            db  8,9,1,      2,3
            db  13,14,5,    16,17,6
            db  0                   ;下面是方块形状描述
            bks     db 40*2,41*2,42*2,43*2  ;  ****                 0
            db  1*2,40*2,41*2,42*2  ;   *     **   **    ** 基本形状*7
            db  1*2, 2*2,40*2,41*2  ;  ***   **     **   ** 1-4
            db  0*2, 1*2,41*2,42*2  ;
            db  0*2, 1*2,40*2,41*2  ;
            db  0*2,40*2,41*2,42*2  ;    *       *
            db  2*2,40*2,41*2,42*2  ;    ***   ***          5-6
            db  1*2,40*2,41*2,81*2  ;   *         *         扩展形状*12
            db 40*2,41*2,42*2,81*2  ;  **   ***   **
            db  1*2,41*2,42*2,81*2  ;   * *  *  * *         7-9
            db  0*2,40*2,41*2,81*2  ;     **   **
            db  1*2,40*2,41*2,80*2  ;      *   *            10-11
            db  1*2,41*2,80*2,81*2  ;    *        **
            db 40*2,41*2,42*2,82*2  ;    *   ***  *
            db  1*2, 2*2,41*2,81*2  ;   **     *  *         12-14
            db  0*2, 1*2,41*2,81*2  ;*  **        *
            db 40*2,41*2,42*2,80*2  ;*   *   ***  *
            db  1*2,41*2,81*2,82*2  ;*   *   *    **        15-17
            db  2*2,42*2,82*2,122*2 ;*                      18
            msg1    db 9,9,‘GAMEOVER‘,9,9,‘$‘
            end start

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多