nasm汇编实现贪吃蛇


title: nasm汇编实现贪吃蛇
date: 2019-12-20 18:43:10


0. 前言

出于汇编语言课程设计要求,设计一个由nasm汇编语言编写的贪吃蛇程序,可在“裸机”上运行。

详细代码见github

1. 需求分析

  • 一个正常的贪吃蛇程序
  • 由nasm汇编语言编写
  • 在“裸机”上单独运行,或由自创加载器加载运行

2. 数据结构设计

需要设定的全局变量如下:

  • snake: 蛇身,由N个结点组成(由于纯汇编只有静态数组,所以必须固定蛇身长度的上限进行内存分配)。每个结点4字节,包含的数据如下:

    • 结点位置:
      • 行号,1字节
      • 列号,1字节
    • 方向,1字节
    • 图案,1字节
  • snake_len: 蛇长度,4字节

  • dir: 方向,1字节

  • speed: 蛇前进速度,1字节

  • fruit_pos: 果子位置,2字节:

    • 行号,1字节
    • 列号,1字节
  • score: 分数,4字节

  • xxx_msg: 各类提示信息,字符串形式

  • is_game_over: 游戏是否结束,1字节

全局常量如下:

  • snake_len_max: 蛇身最大长度
  • snake_head_pat: 蛇头图案
  • snake_node_pat: 蛇身结点图案

3. 程序流程架构

在贪吃蛇程序中,应该包含两个“线程”,线程A负责等待用户按键,线程B负责 snake 的前进、检查、更新等操作。

两个线程不受另一方影响,比如线程A在等待用户按键而停滞时,线程B会让 snake 不断前进。

那么问题来了,汇编怎么实现多线程呢?

其实,我们平时遇见的多线程(多进程),本质上是快速交替运行的程序。而在某一个时刻,只有一个程序在CPU运行,但由于快速(毫秒级)交替运行,所以我们看起来像是同时运行的。究其本质,是由操作系统根据一个定时器中断,每过一会儿(毫秒)就帮我们切换运行程序,从而营造出来的假象。(不考虑多CPU)

所以,问题的关键在于定时器中断。首先,它并不是由操作系统提供,而是由硬件产生,所以在没有操作系统的“裸机”上,也能实现多线程/进程。

综上所述,我们只需要将线程B交给定时器中断调用,而线程A由自己运行,那么就可以实现两者同时运行、互不影响。

在下述流程中,Begin即线程A,new_int_1CH即线程B。

Begin:
    clear() 清屏
    printStr() 打印提示信息
    等待用户按键。。。
    设置 new_int_1CH() 函数为 INT 1CH 中断程序。使得每过一段时间就会执行 new_int_1CH() 函数
    while 全局变量 is_game_over == 0:
        等待用户按键。。。
        根据按键设置全局变量 dir
    printStr() 打印游戏结束信息
    retf

new_int_1CH:
    snakeMove() 蛇前进
    snakeShow() 显示蛇
    snakeCheck() 检查蛇是否撞到自己或者边界
    if 撞到:
        还原 INT 1CH 中断程序(在关中断的环境下进行)
        设置全局变量 is_game_over = 1
    else:
        if 吃到果子:
            蛇尾结点++
            蛇长度++
            分数++
            速度++
            fruitShow() 显示下一个果子

自顶向下设计,不考虑子函数的实现细节。

4. 难点分析

  • 定时器,定时移动snake
  • 生成随机数

解决方案:

  • INT 8定时器中断,每过55ms就会被触发一次。在INT 8中断程序中,会调用INT 1CH中断,而原本的INT 1CH程序只包含一条返回语句。所以,只需重写INT 1CH中断程序,即可实现定时器功能。

  • 获取随机数:

    mov ax, 0h					; 间隔定时器
    out 43h, al					; 通过端口43h
    in al, 40h
    in al, 40h
    in al, 40h					; 访问3次,保证随机性
    mov bl, 20
    div bl						; ax/bl(20) = al......ah
    mov al, ah					; 余数
    mov ah, 0
    add al, 1					; 1-20的随机数
    

5. 具体实现

代码见github

由于生成的贪吃蛇二进制程序超过512字节,不能单独做为MBR程序,所以需要由加载器加载,方能运行。

加载器代码见dou-loader

运行截图如下:

4

输入7,进入贪吃蛇程序:

1

Enter键开始:

2

w,d,s,a键,上右下左移动贪吃蛇。撞到边界或者自身,游戏结束:

3

6. 心得

项目总结:

  • 贪吃蛇程序的分析——2小时
  • 编写贪吃蛇程序——8小时
  • 代码行数——580

此次项目的完成进度超出预算,其原因如下:

  • 前期基础准备,加载器、时钟中断、键盘中断、IO中断等程序的编写,充分锻炼了汇编代码编写能力。
  • 编码前的项目程序分析十分关键,这使得编码有目的、有依据,而不是凭空想象。其实,这就是软件工程的作用之处,需求分析、概要设计、详细设计、难点解决等。
  • 相对完善、便于理解的注释,一手编码一手注释,很关键。
  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dounineli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值