学校强制要求参加汇编语言程序设计大赛
要求实现 贪吃蛇+画等边三角形 双任务系统。
详见ppt和报告--------->>>>>下载点这里
一、比赛要求:
1、双窗口要求:
将显示器的屏幕划分成大小相等的左右两个显示窗口,并画出每个显示窗口的边框,窗口大小适中。
在左边显示窗口,能够运行简单的贪吃蛇游戏,即采用键盘按键控制贪吃蛇前进方向,如“W、S、A、D”键分别为上下左右方向控制按键,以贪吃蛇碰触窗口边框为游戏终止条件,以“R”键为游戏重新开始。若游戏进行当中无键按下,则贪吃蛇保持当前方向不变直至撞墙。
在右边显示窗口,能够画出等边三角形,要求:三角形位置在该显示区域的中部,参数边长由键盘输入确定。每次根据输入的参数,在该窗口将三角形重新绘制出来。
初始工作窗口为左边显示窗口,以后每按一次Tab键切换至旁边显示窗口。当某个显示窗口被选中时,则光标在该窗口底部闪烁,键盘输入对当前窗口有效。整个系统按ESC键退出,返回DOS操作系统界面。
2、设计提示:
使用8086CPU汇编语言,编写任务调度管理程序,对两个任务(两个窗口)进行管理和调度,能够实现任务之间的切换,保存上下文信息。任务调度程序可以使用硬件定时中断,通过中断服务程序完成,或者可以使用循环程序来完成。
若左窗口贪吃蛇游戏正在进行时,切换到右窗口,则贪吃蛇游戏可以暂停,也可以继续运行(只是按键不起作用),这个由程序设计者自行决定。
任务可以有多种形式,不局限于以上两种,运行任务时应该能够通过屏幕显示运行状态或结果,并通过键盘进行交互。
二、架构
参考了libco的上下文切换原理,我们以协程的概念设计了如下架构:
1.snake函数和tri函数抽象成两个协程。
2.两个协程独立工作互不影响,除了处理tab和esc事件只调用了一次yield以外,其他任何逻辑不做任何改变。
3.一个协程调用yield,yield返回后,当前协程上下文没有发生任何变化,就像yield什么都没干一样(就像进程切换一个道理)。只是忙里抽闲运行了一段其他协程罢了。
4.snake和tri的架构都是一个死循环,程序的切换和结束(esc)由yield处理。
5.所有协程(其实就两个协程)共享 data segment、code segment,每个协程都有自己的stack segment。
6.由于只有两个协程,所以不设额外的调用栈、调度器以及额外的一些复杂的设施。
顶层调用图
画等边三角形模块流程图
贪吃蛇模块流程图
运行时如图
控制方法:
运行时进入画等边三角形模块,输入2~320的整数即画出图像,可循环输入,回车后清屏重画;tab键切换至贪吃蛇模块,wasd键控制移动,再按tab键回到画图模块。
完整代码:
作者名单:GreyBtfly、SJY、LSY、welkin.、LSX、LKW
DELAY_TIME EQU 02h ;延时时间参数
MAXBODY EQU 100
HIGHT EQU 20
WIDE EQU 30 ;0~WIDE , or wide+1
WIN_LENTH EQU 10 ;获胜长度
;HEAD_CHAR EQU '#'
BODY_CHAR EQU '*'
SNASTACKOFFSET EQU 127
TRISTACKOFFSET EQU 127
kEsc EQU 27
kTab EQU 9
FOOD EQU '+'
SCx EQU 0
SCy EQU HIGHT+1
;tri
triScr_x EQU 320
triScr_w EQU 320
triScr_h EQU 350 ;设置屏幕属性,保证图形在近似中央
;整体设计:GreyBtfly
DATAS SEGMENT
;此处输入数据段代码
;debug
s db '12345$'
stri db 'tri$'
ssna db 'snack$'
;debug end
;printInt
printInt_div DW 10000, 1000, 100, 10, 1
printInt_res DB 0,0,0,0,0,"$" ;存放五位数ASCII码
;end
;main
space db ' $'
;end
;snake
;全局变量
HEAD_CHAR db '#'
m db 0
x db 0
y db 0
fx db 0
fy db 0
ta db 0
blength db 2
sbody_move db 0
sbody db MAXBODY dup(0)
pause db 'press r to reload$'
;局部变量
win db 0
de db 0
gameover db 0
fe db 0
winMSG db 'Gameover...$'
loseMSG db 'You are winner!$'
;end
;tri
tribx dw 0
triYd dw 173
triXd dw 100
triP dw 0 ;以上三个算法需要的变量
triFlag db 0 ;第n次调用triHypotenuse
triEx dw 0 ;记录本次画线终点横坐标
triLeftX dw 0 ;记录左端点横坐标
triRightX dw 0 ;记录右端点横坐标
triHengY dw 0 ;记录底边总左边 (以上三个供画横线函数使用)
triLenth dw 0 ;记录边长(代码必须要覆盖AX)
note db '>=2 and <=320:$'
;end
;yield
yFunc db 0 ;0 is tri
stack_tri_sp dw 0
stack_snake_sp dw 0
;end
;rand
rseed dw ?
rcnt dw ?
;end
DATAS ENDS
STACK_SNAKE segment
SStack db 12