Dwing写的471字节俄罗斯方块(

来源:百度文库 编辑:神马文学网 时间:2024/04/29 23:38:19
记得自己最早玩的一款游戏就是俄罗斯方块,那种拿在手上黑白的机器,整部机器上只有这么一个游戏。不像现在可以有成百上千个。不过当时就一直好奇,这个游戏为什么叫做“俄罗斯”方块……后来才知道俄罗斯方块的发明者,是当时还被称为”苏联”的联邦科学员阿莱克斯?帕吉托夫(AlexeyPazhitnov ),最后该游戏的代理权最终还是被任天堂获得,将它与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