記得自己最早玩的一款游戲就是俄羅斯方塊,那種拿在手上黑白的機器,整部機器上只有這么一個(gè)游戲。不像現在可以有成百上千個(gè)。不過(guò)當時(shí)就一直好奇,這個(gè)游 戲為什么叫做“俄羅斯”方塊……后來(lái)才知道俄羅斯方塊的發(fā)明者,是當時(shí)還被稱(chēng)為”蘇聯(lián)”的聯(lián)邦科學(xué)員阿萊克斯?帕吉托夫(Alexey Pazhitnov ),最后該游戲的代理權最終還是被任天堂獲得,將它與GB搭配在一起后,產(chǎn)生了令人意想不到的效果,獲得了巨大的成功。
到了今天俄羅斯方塊的原理差不多已經(jīng)到了“世人皆知”的地步了(對不起,夸張了點(diǎn)),不過(guò)很多計算機專(zhuān)業(yè)或者對此有興趣的愛(ài)好者,都自己動(dòng)手寫(xiě)過(guò)這 個(gè)游戲,Dwing,不少用匯編的人都知道這個(gè)名字,是一個(gè)匯編牛人,他寫(xiě)了一個(gè)編譯后僅僅471字節的俄羅斯方塊,可謂經(jīng)典之作。該程序發(fā)布在 Dwing的主頁(yè)上,不過(guò)好像嵌入了一點(diǎn)我覺(jué)的“不友好”的代碼,所以在這里不給出這個(gè)外部鏈接了。有興趣的可以自己Google一下Dwing,很容易 找到的。下面是這個(gè)經(jīng)典的471字節俄羅斯方塊匯編程序源代碼及詳細注釋?zhuān)?/p>
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年新年公開(kāi)我寫(xiě)的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 ;開(kāi)始畫(huà)邊框,ax=字符(0dbh)及屬性(灰色) mov cx,ax ;cx=數量 rep stosw ;覆蓋全屏 mov ax,0e30h ;開(kāi)始畫(huà)數碼框,ax=字符(‘0‘)及屬性(黃色) mov cl,6 ;cl=數字個(gè)數(6) mov di,2*(40*23+17) ;di=數字顯示屏幕偏移位置 rep stosw ;顯示數碼 xor ax,ax ;開(kāi)始畫(huà)中間空框,ax=空字符 mov di,2*(40*2+15) ;di=空框第一行屏幕偏移位置 @nextbl:mov cl,10 ;cl=每行塊數(10) rep stosw ;畫(huà)一行空格 add di,2*(15+15) ;計算下一行屏幕偏移位置 cmp di,2*(40*22+15) ;判斷是否畫(huà)完最后一行(共20行) jb short @nextbl ;沒(méi)畫(huà)完則循環(huán) @rernd: in al,40h ;開(kāi)始隨機選擇方塊類(lèi)型,al=時(shí)間隨機值 and al,0111b ;al只取0-7 jz short @rernd ;如果是0則重新選擇(只選1-7,共7種) dec ax ;1-7變?yōu)?-6 mov bx,2*(40*2+15+4) ;方塊起始屏幕偏移位置 jnz short @t ;如果不是0(長(cháng)條形方塊需特殊處理)則跳轉 mov bx,2*(40+15+4) ;長(cháng)條形方塊的起始屏幕偏移位置上移一行 @t: xchg ax,bp ;bp=方塊起始屏幕偏移位置 call @isok ;判斷新產(chǎn)生的方塊能否放置 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 ;讀鍵盤(pán) dec al ;"ESC"掃描碼=1 jnz short @esc ;如果沒(méi)有按"ESC"則跳回繼續讀鍵盤(pán) mov ax,3 ;ax=DOS默認顯示模式(3) int 10h ;設置顯示模式3(80*25*16色字符模式) retn ;退出 @goon: mov cl,0ffh ;新方塊能放置情況:先進(jìn)入延時(shí)狀態(tài) cmp cl,40h ;cl=循環(huán)等待次數 jae short @wait ;確認cl不小于40 mov cl,40h @wait: call @dispb ;顯示當前新方塊 push cx ;進(jìn)入等待狀態(tài) xor cx,cx ;cx=等待時(shí)間(微秒)低字 mov dx,1000 ;dx=等待時(shí)間(微秒)高字 mov ah,86h int 15h ;等待 pop cx ;退出等待狀態(tài) @t4: mov ah,1 int 16h ;判斷鍵盤(pán)緩沖區是否有字符 jz short @loop ;沒(méi)有按鍵則跳出鍵盤(pán)處理部分 xor ax,ax call @disp ;清除新方塊的顯示 int 16h ;讀取鍵盤(pán)緩沖區字符=>ah mov al,ah ;al=ah cmp al,$up ;判斷是否是上方向鍵 jnz short @k1 ;不是則跳轉 push bp ;保存當前新方塊的擺放形狀 movzx bp,cs:[bp+bkv] ;改變新方塊的擺放形狀 call @isok ;判斷是否能放置 jz short @loop_ ;能放置則跳出鍵盤(pán)處理部分 pop bp ;不能放置則恢復新方塊原來(lái)形狀 loop @wait ;繼續下一次等待 @k1: push bx ;保存當前新方塊的位置 cmp al,$left ;判斷是否是左方向鍵 jnz short @k2 ;不是則跳轉 dec bx ;新方塊左移一個(gè)位置(2個(gè)字節) dec bx @test: call @isok ;判斷是否能放置 jz short @loop_ ;能放置則跳出鍵盤(pán)處理部分 pop bx ;不能放置則恢復新方塊原來(lái)位置 loop @wait ;繼續下一次等待 @k2: cmp al,$right ;判斷是否是右方向鍵 jnz short @k3 ;不是則跳轉 inc bx ;新方塊右移一個(gè)位置(2個(gè)字節) inc bx jmp short @test ;剩下的處理同"左方向鍵" @k3: pop bx ;恢復新方塊原來(lái)位置 cmp al,1 ;判斷是否是ESC鍵 jz short @end ;如果是則跳轉到退出程序段 jmp short @ok ;如果是其他按鍵則跳出延時(shí)狀態(tài) @loop_: pop ax ;清除保存的新方塊位置 @loop: loop @wait ;繼續下一次等待 @ok: push ax ;保存按鍵掃描碼 xor ax,ax ;延時(shí)過(guò)后進(jìn)入方塊下落部分 call @disp ;清除新方塊的顯示 add bx,2*40 ;新方塊下移一個(gè)位置(2個(gè)字節) call @isok ;判斷是否能放置 pop ax ;恢復按鍵掃描碼 jnz short @down ;如果不能放置新方塊則跳轉 cmp al,$down ;判斷是否是下方向鍵 jz short @ok ;如果是則繼續下落 jmp short @goon ;不是則進(jìn)入下一次延時(shí) @down: sub bx,2*40 ;恢復新方塊原來(lái)位置 call @dispb ;顯示新方塊 xor ax,ax ;進(jìn)入判斷是否有一行已滿(mǎn) 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 ;進(jìn)入消除一行部分 mov si,di sub si,2*40 ;si=上一行屏幕偏移位置 mov cx,si ;cx=移動(dòng)字符個(gè)數 std rep movsb ;移下一行 cld mov di,2*(40*2+15) ;di=中間空框最上一行的屏幕偏移位置 mov cl,10 ;一行10個(gè)方塊 rep stosw ;清除最上一行 popa ;退出消除一行部分 inc dx ;分數基值+1 add dh,dl ;累計當前分數 @skip: add si,2*40 ;下一行偏移位置 cmp si,2*(40*22) ;判斷是否判斷完所有行 jb short @nextl ;沒(méi)有則繼續下一行判斷 and dx,dx ;判斷是否有得到當前的分數 jz short @t_ ;沒(méi)有則跳過(guò) @t00: mov di,2*(40*23+21) ;數碼位屏幕偏移位置(第2位) @t0: mov byte ptr[di],30h ;置0 dec di ;進(jìn)一位(倒退2個(gè)字節長(cháng)度) dec di cmp di,2*(40*23+20) ;判斷是否進(jìn)入第3位 jnz short @t000 ;如果不是則跳過(guò) dec byte ptr cs:[@goon+1];每100分等待次數減1(加速) @t000: inc byte ptr[di] ;當前數碼位+1 cmp byte ptr[di],3ah ;判斷數碼位是否超過(guò)9 jz short @t0 ;如果是則跳轉(進(jìn)位) dec dh ;當前分數累計值-1 jnz short @t00 ;如果分數沒(méi)加完則繼續累加 @t_: jmp @rernd ;繼續產(chǎn)生下一個(gè)新方塊 @isok: mov si,bp ;判斷是否能放置方塊子模塊 shl si,2 ;si=方塊形狀標號*4(占4個(gè)字節) 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 ;繼續判斷下一個(gè)位置描述 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個(gè)字節) push cx ;保存cx mov cl,4 ;cl=方塊數(4) @nextb_:movzx di,cs:[si+bks] ;取方塊描述 mov [di+bx],ax ;顯示一個(gè)小方塊 inc si ;si=下一個(gè)位置描述 loop @nextb_ ;繼續畫(huà)下一個(gè)小方塊 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 |
聯(lián)系客服