邹伟汇编实验报告.docx
《邹伟汇编实验报告.docx》由会员分享,可在线阅读,更多相关《邹伟汇编实验报告.docx(60页珍藏版)》请在冰点文库上搜索。
邹伟汇编实验报告
汇编报告
个人信息:
邹伟200630473261 2006级计算机科学与技术2班计算机科学与工程学院
报告说明:
上次实验课做的是2.2,在一个字符串中搜寻子字符串,两层循环就可以解决了,此次报告根据自己的兴趣编了个简单的游戏,模仿经典游戏俄罗斯方块。
左右方向键控制方块的水平位置,上方向键旋转方块,END键水平翻转之。
有简单的积分功能,并能根据得分多少调整游戏难度,即方块下落速度。
游戏甚少创新,权为练笔。
程序说明:
游戏有一个依得分而改变的周期,在每一个周期中,用10h号BIOS中断调用检查键盘缓冲是否为空,若不为空,则读出缓冲数据,根据输入指示,调整游戏内部状态,最后根据内部记录的状态用适当的方法表现在屏幕上。
1.主程序流程:
1.初始化游戏环境:
a)清除得分,清空屏幕,初始化相关数据结构
b)产生两个方块组,一个为即将显示的,一个为下一个要显示的。
2.进入游戏循环:
a)延时,达到一定的游戏周期,在此期间也检查用户输入
b)根据输入,应用相应功能,如:
ESC键则跳至4,控制方向键则检查并改变当前方块位置响应输入,F3键主动提高游戏关数,DEL键游戏暂停……。
c)根据b)中更新的内部数据状态,执行相应检查,如:
是否满行?
是否游戏结束?
是否游戏完成?
……
3.无条件跳转至2.
4.退出程序
2.附加说明:
a)随机数的的产生,首先从CMOS实时钟读取的秒数作为随机数的初始值,其后再根据线性同余法产生下一个数。
b)游戏区域暂定为12*20,为了纪录区域中每个格子是否已被方块占据,用了一个长度为20的字数组,每个字的一位代表区域中的一个方格,这样计算满行时容易判断,设/置位也较为容易。
不过由于16位汇编指令中并没有bt之类位操作指令所以,测试某位是否置位时,也相当令人不快。
c)为了更好的控制方块左右移动以及完成旋转水平、翻转等操作,在方块组中选取了一个方块作为参照点,极大简化了编写代码的过程。
d)游戏难度,具体到此游戏就是方块自动下落的速度,通过设置延时长短控制,随着得分的增加,Level也增加,所对应的延时缩短,下落速度加快,为了减小游戏复杂度,在较高关数时方块组形状(共16种,其中2种相同,为仅一个格的穿透方块,设为2增加出现概率)趋于正常。
e)输入的获取,首先调用INT10h的1号功能,判断键盘缓冲区是否为空,若不为空再用0号功能读取,以读取到的输入改变内部状态,即方块位置、游戏状态等。
编写步骤:
1.先构思出一个大概的框架
2.将构建出的框架上.逐步分解
3.逐步添加子程序
4.不断添加代码、DEBUG,最后测试。
结果(部分画面截图):
游戏操作说明:
←方块组左移↑旋转
→右移↓急速下落
End水平翻转Delete暂停
F2主动提升程序关数
F3与F2相反
F1下落方块组颜色一致或不一致
左图为程序开始运行时,
得分为0,当前关为0
得分规则:
2*一次性消去的行数-1
左图为游戏暂停中,得分为126
已接近通过要求。
继续运行后,
将使游戏达到完成状态。
左图为游戏结束时显示的一个随机画面^_^,
按任意键重新开始
游戏完成(通关),显示的画面与此差不多,随
后退出程序。
分析与讨论:
1.虽然是用汇编语言编写代码,现代一些优秀的编程思想仍然是极为有用的,如面向对象,能很大程度为编写代码提供导航。
思维决不局限于所用的编程语言,绝大部分编程语言在功能上是完全可以等价的,而思维决定一切,C到C++的发展,功能上并无不同,不过在语法上C++为我们提供了便利,对事物的理解也更为直观。
如果用VC++写此程序就不用那么艰难了。
不过,编写代码过程中很多体悟却不能仅通过几行高级语言的代码所能得到的。
2.程序虽说不算大,但为了更好的控制其变化,我使用了tortoiseSVN工具,其对版本的控制程度非同一般,源代码交给它,非常放心。
同时IDE用的是MasmPlus,至少它提供了语法高亮显示、子程序快速跳转(其实也不够快)、快速检索等功能。
3.Makefile文件的使用也省了不少事,通常是交待它一下怎样通过编译、连接出最终可执行文件后就不用管它了。
所以说好的工具仍是不可忽视的。
结论:
所谓万事开头难,像汇编这样非常不让人省心的语言,看来看去就那几个单调的指令,阅读别人的代码,总有些乏味,只有真正开始自己编写时,才能知道其实它并不难,相反它把所有细节全部展现在我们面前,不像有些高级语言为了通用性,隐藏了很多细节。
在用高级语言编写代码的时候,总觉得有些糊涂度日。
不过话说回来,两者之间的生产效率却不是汇编所能企及的。
在用汇编写代码时,每一条指令的执行都能直接感受其变化到,这时候需要有十分的耐心。
有时候一个不留神寄存器写错了名,半天没得到自己想要的结果还不知道错在哪。
我在编写此程序过程中,就曾有写错的时候,浪费了不少时间。
所以随时DEBUG是必须的,一旦错误扩大了范围,要找到它是要费很多手脚的。
最后,在编任何或大或小的程序之前都需要事先有个清晰的规划,然而我却通常是想到哪写到哪,最后做了不少无用功,可惜了那宝贵的时间。
源代码:
共4个文件,说明如下:
1.makefile :
编译出可执行文件的一些规则,需make工具来解析。
2.game.h :
程序中所需的各种常量及一些数据结构的定义,集中管理,便于
修改
3.entry.asm:
程序的入口点,包含开始一个游戏的无穷循环。
4.game.asm:
程序主体,一个代码段一个数据段一个堆栈段。
●文件名称:
makefile
文件说明:
在命令行上直接运行make即可生成最终可执行文件cnb.exe
-------makefile----start----------
#此文件用于描述源程序之间的相互关系并自动完成维护编译工作,简单而有效
#解析此文件需要make工具,MinGW(C++IDE)中带有
ASM=ml
ASM=ml
LINK=ml
MODEL_FLAG=/c/nologo
MODELS=entry.objgame.obj
all:
cnb.exe
%.obj:
%.ASMgame.h
$(ASM)$(MODEL_FLAG)$<
cnb.exe:
$(MODELS)
$(LINK)/Fecnb.exe$(MODELS)
cnb
clean:
rm*.obj
cls
dir
-----------makefile--------end--------
●文件名称:
game.h
---------game.h---start--------
;摘要:
程序中所需的各种常量及一些数据结构的定义,集中管理,便于修改
;游戏状态
GS_RUNNINGequ0
GS_PAUSEDequ1
GS_OVERequ2
;最高可达到的关数
LEVEL_LIMITTequ15
;游戏区域起始位置及大小
GM_LEFTequ25
GM_TOPequ4
GM_WIDTHequ12
GM_HEIGHTequ20
GM_MASKequ(1SHLGM_WIDTH-1)
;功能键扫描码
KEY_ESCequ1h;ESC
KEY_LEFTequ4bh;LEFT
KEY_RIGHTequ4dh;RIGHT
KEY_DOWNequ50h;DOWN
KEY_TURNequ4fh;End
KEY_PAUSEequ53h;Delete
KEY_ROLATEequ48h;UP
KEY_QUICKLYequ3dh;F3
KEY_SLOW_DOWNequ3ch;F2
KEY_COLOR_SAMEequ3bh;F1
CHAR_CLEARequ'';擦除字符,空格
CHAR_BRICKequ2;方块外形,头形
;0黑1深蓝2绿3蓝4红5紫6黄7灰白,最高位置1则高亮显示
COLOR_CLEAR equ0h
COLOR_DIED_BRICKequ08h
COLOR_TITTLEequ7;
COLOR_NUMBERequ3or8
;屏幕上各说明文字或装饰物的坐标,皆为相对游戏场地左上角
X_NEXT_BRICKequ-5
Y_NEXT_BRICKequ3
Y_LBOUND_CHARequ17
Y_RBOUND_CHARequ16
Y_BOUND_COLORequ2or8;blue
X_UBOUND_CHARequ15
X_DBOUND_CHARequ15
X_BOUND_COLORequ2or8;green
X_STARTequ(GM_WIDTH-1)/2
Y_STARTequ-1
X_SCORE_STRequ-10
X_LEVEL_STRequX_SCORE_STR
X_adjustLevelDelt_STRequX_SCORE_STR-4
Y_SCORE_STRequ5
Y_LEVEL_STRequY_SCORE_STR+2
Y_adjustLevelDelt_STRequY_LEVEL_STR+2
X_SCORE_POSequ-3
X_LEVEL_POSequX_SCORE_POS
X_adjustLevelDelt_POSequX_SCORE_POS
Y_SCORE_POSequY_SCORE_STR+1
Y_LEVEL_POSequY_LEVEL_STR+1
Y_adjustLevelDelt_POS
equY_adjustLevelDelt_STR+1
X_GAME_OVERequ-10
X_JUDGE_STRequX_GAME_OVER+5
X_GAME_NAMEequGM_WIDTH/2-4
Y_GAME_NAMEequ-1
Y_GAME_OVERequ-3
Y_JUDGE_STRequY_GAME_OVER+1
;相应键所对应的相应功能入口地址的偏移
DIR_RIGHTequ0
DIR_LEFTequ2*1
DIR_DOWNequ2*2
DIR_ROTATEequ2*3
DIR_DOWN_COMPLETEequ2*4
DIR_TURNequ2*5
KEY_WRONG_DIRequ2*11
;坐标结构
Posstruc
pos_bXdb?
pos_bYdb?
Posends
;单个方块
Brickstruc
;相对基块的坐标
b_sPosPos<>
Brickends
;方块组ManyBrickstruc
;方块个数
mb_bCntdw?
;容量固定为4
mb_sBrickBrick4dup(<>)
;多个方块中所选取的基块的坐标,也是相对游戏场左上角而言
mb_sPosPos<>
;此元素的颜色
mb_bColordb?
ManyBrickends
;游戏类,
GameAppstruc
;玩家得分
ga_scoredw?
;游戏状态
ga_statedw?
;游戏地图,相应位置位则有方块在此
ga_mapdwGM_HEIGHTdup(0FFFFh)
GameAppends
--------game.h--------end-----------
●文件名称:
entry.asm
--------entry.asm-----start---------
;Copyleft(c)2007,Godreservedallrights.
;
;当前版本:
0.2
;作者:
邹伟
;完成日期:
2007年12月21日
;摘要:
整个程序从start开始执行,并从main_quit退出
publicmain_quit,restart_the_game
externGA_gameInit:
far,GA_gameCircle:
far,setDSAndES:
far,stackPoint:
byte
assumecs:
EntryCode
EntryCodesegment
start:
callsetDSAndES
restart_the_game:
movsp,offsetstackPoint
main_do_forerer:
callGA_gameInit
;进入游戏循环,直到结束、完成或主动退出
callGA_gameCircle
jmpmain_do_forerer
;按ESC键或整个游戏完成时,跳到这里
main_quit:
;清除屏幕
movah,00h
moval,03h
int10h
;返回DOS
movax,4c00h
int21h
EntryCodeends
endstart
---------entry.asm-----end-----------
●文件名称:
game.asm
---------game.h-------start----------
;Copyleft(c)2007,Godreservedallrights.
;
;当前版本:
0.11
;作者:
邹伟
;完成日期:
2007年12月23日
;摘要:
各主要子程序都在此间
;说明:
程序中用于输出字符的位置未加说明则默认为相对于游戏区域左上角即(GM_LEFT,GM_TOP)
publicsetDSAndES,GA_gameInit,
GA_gameCircle,stackPoint
externmain_quit:
far,restart_the_game:
far
includegame.h
;设置块坐标的宏
assignPosmacrox,y
mov(Brickptr[si]).b_sPos.pos_bX,x
mov(Brickptr[si]).b_sPos.pos_bY,y
addsi,sizeBrick
endm
assignBasemacrox,y
mov(ManyBrickptr[di]).mb_sPos.pos_bX,x
mov(ManyBrickptr[di]).mb_sPos.pos_bY,y
endm
assumecs:
GameCode,
ds:
MainData,
ss:
StackSpase
GameCodesegment
;游戏循环---不断获取输入,根据与定义规则合理的转化为输出
GA_gameCircleprocfar
GA_gameCircle_again:
movdir,KEY_WRONG_DIR
leabx,levelFPS
movdi,level
adddi,challenge
cmpdi,LEVEL_LIMITT
jbelevel_ok
movdi,LEVEL_LIMITT
level_ok:
shldi,1
movcx,[bx+di]
wast_time:
calldelay
cmpdir,KEY_WRONG_DIR
jemay_be_life_is_long
callBrick_goNext
movdir,KEY_WRONG_DIR
callManyBrick_drawSelf
may_be_life_is_long:
loopwast_time
cmpdir,KEY_WRONG_DIR
jzuser_press_no_dir_key
callBrick_goNext
user_press_no_dir_key:
movdir,DIR_DOWN
callBrick_goNext
cmpgame.ga_state,GS_OVER
jzGA_over
callManyBrick_drawSelf
jmpGA_gameCircle_again
GA_over:
calldoGameOver
ret
GA_gameCircleendp
;每次游戏开始时的初始化调用
GA_gameInitprocfar
callclrScreen
;hidethecursor
movch,020h
movcl,020h
movah,01h
int10h
;初始化随机序列的第一个数,读取BIOS提供的当前秒
xoral,al
out70h,al
inax,71h
movseed,ax
;初始化,如:
得分,游戏状态,游戏地图
movchallenge,0
movgame.ga_score,0
movgame.ga_state,GS_RUNNING
leadi,game.ga_map
movcx,GM_HEIGHT
cld
xorax,ax
repstosw
movnextNO,0
callMB_gernicNext
callMB_gernicNext
calldrawNextBrick
callmoreBeautiful
;showsomestrings
movsi,offsetscoreStr
movdl,X_SCORE_STR
movdh,Y_SCORE_STR
movcx,6
callshowStr
movsi,offsetlevelStr
movdl,X_LEVEL_STR
movdh,Y_LEVEL_STR
movcx,6
callshowStr
movsi,offsetlevelDeltStr
movdl,X_adjustLevelDelt_STR
movdh,Y_adjustLevelDelt_STR
movcx,10
callshowStr
movsi,offsetusageStr
movdl,-GM_LEFT
movdh,-4
movcx,usageStrCNT
callshowStr
movsi,offsetusageStrEx
movdl,-GM_LEFT
movdh,-3
movcx,usageStrExCNT
callshowStr
movsi,offsetlinkToCoderStr
movdl,-GM_LEFT
movdh,-2
movcx,linkToCoderCNT
callshowStr
;showsomedigitials
callshowScore
callcalcLevel
callshowadjustLevelDelt
ret
GA_gameInitendp
;全局初始化,调用一次,设置DS,ES指向同一个数据段,程序运行过程中不再改变
setDSAndESprocfar
movax,MainData
movds,ax
moves,ax
ret
setDSAndESendp
;判断游戏区域(dl,dh)位置是否为空
;in:
dl-->x,dh-->y
;out:
flagregister
isPosNotEmptyproc
pushdx
pushbx
pushax
pushcx
pushdi
pushsi
movsi,curMB
movsi,(ManyBrickptr[si]).mb_bCnt
;ax--mask,第dl位置1
movax,1
movcl,dl
shlax,cl
leadi,game.ga_map
;map+2*dh
xorbh,bh
movbl,dh
shlbl,1
only_one_brick:
andax,[bx+di]
jeis_pos_empty_out
cmpsi,1
jneis_pos_empty_out
cmpbx,(2*GM_HEIGHT-2)
jeis_pos_empty_out_pre
addbx,2
jmponly_one_brick
;ensuretheresultiscorrect
is_pos_empty_out_pre:
cmpbx,0
is_pos_empty_out:
popsi
popdi
popcx
popax
popbx
popdx
ret
isPosNotEmptyendp
;判断游戏是否结束
isGameOverproc
pushbx
movbx,curMB
cmp(ManyBrickptr[bx]).mb_sPos.pos_bY,Y_START
jnestill_alive
;游戏的确结束了
movgame.ga_state,GS_OVER
calldoGameOver
still_alive:
popbx
ret
isGameOverendp
;游戏结束后,调用此过程,显示一些提示信息,待等用户下一步指示,重玩或退出
doGameOverproc
callclrScreen
callmoreBeautiful
movsi,offsetgameOverStr
movcx,45
movdl,X_GAME_OVER;x
movdh,Y_GAME_OVER;y
callshowStr
movax,game.ga_score
movcx,43
callAXModCX
andax,3
movdi,ax
shldi,1
movcx,judgeCnt[di]
movsi,judgeTable[di]
movdl,X_JUDGE_STR
movdh,Y_JUDGE_STR
callshowStr
moval,CHAR_BRICK
wait_for_restart: