You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

汇编(DosBox)贪吃蛇游戏:如何基于定时器生成伪随机苹果

贪吃蛇游戏:用系统定时器生成苹果伪随机数的入门讲解

我正在为学校制作贪吃蛇游戏,需要用伪随机数生成苹果的位置。教材指出要基于定时器、使用内存地址0040:006Ch实现,但我搞不懂它的讲解方式,希望有人用最简单的方式解释。我是汇编入门新手,使用DosBox环境,当前代码仅实现了用WASD控制'*'移动及边界限制,代码如下:

IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
; Your variables here
; --------------------------
    saveal db ' '


CODESEG
proc black
body:
    mov [es:si], ax
    add si, 2
    cmp si, 25*80*2
    jnz body
  ret
endp black

proc up
    
    mov di, 80*2
    cmp si, di
    jb not_move_up
    
    mov ah, 0
    mov al, ' '
    mov [es:si], ax
    sub si, 80*2
    mov ah, 156
    mov al, '*'
    mov [es:si], ax
not_move_up:
  ret
endp up

proc down

    mov di, (24*80*2)-1
    cmp si, di
    jg not_move_down
    
    mov ah, 0
    mov al, ' '
    mov [es:si], ax
    add si, 80*2
    mov ah, 156
    mov al, '*'
    mov [es:si], ax
not_move_down:
  ret
endp down
proc left

    mov dx, 0
    mov bx, si
    mov ax, si
    mov si, 80*2
    div si
    mov si, bx
    cmp dx,0
    jz not_move_left
    
    mov ah, 0
    mov al, ' '
    mov [es:si], ax
    sub si, 2
    mov ah, 156
    mov al, '*'
    mov [es:si], ax
not_move_left:
  ret
endp left
proc right

    mov dx, 0
    mov bx, si
    mov ax, si
    mov si, 80*2
    div si
    mov si, bx
    cmp dx,158
    jz not_move_right

    mov ah, 0
    mov al, ' '
    mov [es:si], ax
    add si, 2
    mov ah, 156
    mov al, '*'
    mov [es:si], ax
not_move_right:
  ret
endp right
start:
    mov ax, @data
    mov ds, ax
; --------------------------
; Your code here
; --------------------------
    mov ax, 0b800h
    mov es, ax
    
    mov si,0
    mov al, ' '
    mov ah, 0
    call black
    mov si, (12*80+40)*2
    mov al, '*'
    mov ah, 156
    mov [es:si], ax
    
yesOrno:
    mov ah, 1h
    int 21h
    
    mov [byte ptr saveal], al
    cmp [byte ptr saveal], 'w'
    jz w
    cmp [byte ptr saveal], 'a'
    jz a
    cmp [byte ptr saveal], 's'
    jz s
    cmp [byte ptr saveal], 'd'
    jz d
    cmp [byte ptr saveal], 'q'
    jmp exit
    
w:
    call up
    jmp yesOrno
s:
    call down
    jmp yesOrno 
a:
    call left
    jmp yesOrno
d:
    call right
    jmp yesOrno
    
exit:
    mov ax, 4c00h
    int 21h
END start

一、为什么用0040:006Ch?

  • 这个内存地址是DOS系统里系统定时器的计时值,是个16位的数,会以每秒约18.2次的速度自动递增,涨到65535后循环归零。
  • 它的变化完全无规律(对我们的程序来说),所以拿来当伪随机数的“种子”刚好——每次读它的值,都能得到一个看起来随机的数。

二、怎么用它生成苹果位置?

1. 读取定时器数值

要访问这个远地址,用这段代码:

mov ax, 0040h   ; 定时器所在的段地址是0040h
mov es, ax      ; 把段地址加载到es寄存器
mov ax, [es:006Ch]  ; 读取0040:006Ch的16位值到ax

现在ax里就是当前的随机源数值。

2. 转换成合法的屏幕坐标

屏幕是25行×80列,行号范围024,列号范围079,用除法取余数把随机数压缩到这个范围:

生成随机行号:

mov bx, 25       ; 总行数
div bx           ; ax除以bx,dx里就是余数(0~24,刚好是合法行号)
mov apple_row, dx ; 把行号存到自定义变量里

生成随机列号:

mov ax, [es:006Ch]  ; 可以再读一次定时器,或者把之前的ax做个小变换(比如ax=ax+100),避免行和列完全绑定
mov bx, 80       ; 总列数
div bx           ; dx里是余数(0~79,合法列号)
mov apple_col, dx ; 存列号

注意:要在DATASEG里先定义apple_row db ?和apple_col db ?这两个变量

3. 绘制苹果到屏幕

显存段是0B800h,每个字符占2字节(字符+属性),计算偏移量后写入苹果字符:

mov ax, 0B800h
mov es, ax
mov ax, apple_row
mov bx, 80
mul bx           ; ax = 行号×80
add ax, apple_col ; ax = 行号×80 + 列号
shl ax, 1        ; ax = 上面的结果×2(每个字符占2字节)
mov si, ax       ; si指向苹果的显存位置
mov al, 'O'      ; 苹果用'O'表示,你可以换其他字符
mov ah, 127      ; 苹果的显示属性(亮白色,可自行调整)
mov [es:si], ax  ; 把苹果写到屏幕上

三、额外注意

  • 生成苹果后要检查位置是否和蛇身重叠,如果重叠就重新生成一次。
  • 不要在极短时间内连续读取同一个定时器值生成行和列,否则行和列会有固定关联,随机性变差。

内容的提问来源于stack exchange,提问作者yarden

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:54:53