【问题标题】:Assembly - how to use fewer variables汇编 - 如何使用更少的变量
【发布时间】:2016-06-17 08:37:08
【问题描述】:

我正在制作“连接四人”游戏。我有一块 4x4 的方板。对于板上的每个图块,我必须绘制一个具有 x 值和 y 值的圆盘(方形)。问题是我必须制作 32 个变量或很多程序,这些程序一直在改变这两个变量,但这些选项似乎效率很低,而且代码会很长。如果您对如何提高效率有任何建议,请告诉。

*注意 - 我正在使用 x86 汇编和 TASM 代码如下:

proc CheckPlayer1Number
    mov ah, 7
    int 21h
    cmp al, 31h
    je CheckColumn1
    jmp CheckPlayer1Number
endp CheckPlayer1Number

proc CheckColumn1
    cmp [FirstColumnArray], 0
    je ChangeColumnNumber1 
endp CheckColumn1

proc ChangeColumnNumber1
    inc [FirstColumnArray]
    mov [Player1Drawx], 25h
    mov [Player1Drawy], 87h
    jmp DrawPlayer1Disc
endp ChangeColumnNumber1

DrawPlayer1Loop:
    mov bh,0h
    mov cx,[Player1Drawx]
    mov dx,[Player1Drawy]
    mov al,[player1disccolor]
    mov ah,0ch
    int 10h
    inc [Player1Drawx]
    cmp cx, [Player1Drawx + 14h]
    jl DrawPlayer1Loop

DrawPlayer1Disc: 
    mov bh, 0h
    inc [Player1Drawy] 
    cmp dx, [Player1Drawy + 14h]
    jl DrawPlayer1Loop

我只编程了一点,只是为了看看代码是否有效。

感谢您的帮助。

【问题讨论】:

  • 如果没有关于代码结构的更多细节,不可能有人能回答这个问题。在任何情况下,一个常见的技巧是避免使用全局变量并使用本地变量。
  • 您使用哪种语言?

标签: assembly x86 dos tasm x86-16


【解决方案1】:

使用数组而不是单独的变量?就像由四个 (x,y) 值组成的四个数组组成的数组。那么你只需要数组的基地址,然后你就可以通过偏移量获取数组的所有元素。

在 C 中会是这样的

struct Disc
{
    int x;
    int y;
};

struct Disc array[4][4];

C 是一种非常低级的语言,接近于“金属”,并且在某些情况下(尤其是在其历史早期)可以被视为一种非常先进的宏汇编程序。

C 中的数组是连续的、连续的内存块,每个元素一个接一个,因此很容易计算数组中特定元素的偏移量。事实上,这就是 C 编译器为您所做的事情,这也是数组索引在 C 中从零开始而不是像在同一时代的许多其他高级语言中那样从 1 开始的原因。

对于一个简单的数组,例如

int a[4];

数组中每个元素的偏移量是索引乘以数据的大小。要获取元素 0(即 a[0]),请执行 0 * sizeof(int),要获取第二个元素,请执行 1 * sizeof(int)

现在获取我上面展示的结构数组的数组,您使用相同的原理来计算从内存开始的偏移量:索引乘以元素大小。

如果我们向后开始,结构是两个int 成员,在典型的 32 位机器上总共是 8 个字节(每个成员是一个 4 字节(32 位)整数,两个成员)。这意味着内部数组是 8 个字节乘以 4 个元素,即 32 个字节。要获取数组中的特定元素,请将索引乘以 8(结构大小)并将其作为偏移量添加到数组的开头。

对于外部数组,每个元素是 32 字节(每个元素是 4 个结构的数组),这意味着上面显示的 array 的总大小是 128 字节。要获取该数组中的元素,您可以将基于零的索引乘以 32。

使用上面的方法,获取array[i][j] 的结构(对于ij 的任意但在范围内的值)你得到array 的基地址,添加i * 32到达内部数组,然后添加j * 4 以到达实际结构。在伪代码(不是真正的 C)中,它看起来像

structure = array + i * 32 + j * 4

这为您提供了特定结构的地址。现在获取结构的成员是一样的。成员 x 位于偏移量 0,成员 y 位于偏移量 4(前一个成员的大小)。再次使用伪代码:

x = structure
y = structure + 4

因此,要处理您的板,您只需要三个“变量”:外部数组的基地址,以及索引ij

我的 x86 程序集生锈了,很久以前我就使用过它,但是计算偏移量并将正确的结构变量移动到寄存器中很容易 IIRC。

【讨论】:

  • 感谢大家的帮助。首先,我使用的是 Assembly x86 和 TASM。其次,我上传了我的代码,以便您更好地理解。 Ped7g 我不太明白你的解释。我还有另一个问题。我需要输入 1-4 之间的数字。假设我想要 4。它首先检查我是否输入了 1。如果没有,它将检查我是否按了 2 等等,所以发生的情况是我必须按 4 次才能到达数字 4。我该如何解决它它不会那样做吗?
  • @KatomPower:C 是一种有用的方式来表达内存中的数据布局,并描述您的 asm 的一般用途。回复:输入:听起来您需要将代码修复为输入一次并以多种方式检查该输入。如果您了解任何其他编程语言,请先“思考”在更高级别上发生的事情,然后再用 asm 实现它。
  • @KatomPower 为我的回答添加了一点解释
  • @KatomPower 再读一遍,让我知道你不明白的部分(特定的句子,或单词,或想法)。请在我的回答下发表评论,以便我收到您的评论通知。抱歉,“不明白”太宽泛了,我无法专注于任何事情。
【解决方案2】:

32 个变量通常相当于 32 项大小的单个变量(数组)。

而不是使用变量名square_3_1_x,您会想到一个“映射函数”,例如,您将 4x4 方格寻址为每行 0,1,2..。

所以对于 1..4 范围内的行/列,square(row,column) 索引是 ((row-1)*4+(column-1))。

然后使用 *2 和 +0 表示 x / +1 表示 y3_1_x163_2_y19

或 +0 表示 x 和 +16 表示 y3_1_x83_2_y25)。

或者你能想到的任何你自己喜欢的映射。

假设您想在 32b x86 汇编程序(NASM 语法)中获取磁盘在第 3 行 (1..4) 和第 2 列 (1..4) 的 [x,y] 位置(我喜欢你的做法) '不要指定你的平台和语法,所以回答的人可以选择他们想要的任何东西,然后你必须理解完全陌生的语法,并将其转换为你的最终来源,你非常慷慨):

discPositions: times 32 dd 0   ; 16+16 for x+y couples (16 = 4x4).

GetDiscPosition:
  ; input: row (1..4) in eax, column (1..4) in ebx
  ; output: x position in eax, y position in ebx
    dec eax   ; row-1
    dec ebx   ; column-1
    shl eax,2 ; (row-1)*4
    add eax,ebx ; (row-1)*4+(column-1)
    shl eax,3 ; ((row-1)*4+(column-1))*2*4
    ; *2 to cover [x,y] pairs, *4 to respect data size (DWORD)
    ; so here eax is byte offset to [x,y] couple in discPositions array

    ; it would make sense to have that offset calculation in another
    ; subroutine, so you can reuse it for SetDiscPosition routine

    ; Now just return the [x,y] stored in the 128B memory array labeled discPositions
    mov ebx,[discPositions+eax+4]  ; fetch y position
    mov eax,[discPositions+eax+0]  ; fetch x position
    ret

    ; ... now somewhere in your code, where you want to get disc's x,y for square(3,4)
    mov eax,3
    mov ebx,4
    call GetDiscPosition
    ; eax now has x position, ebx has y position
    ; ...

编辑: 好吧,既然这个答案得到了两次投票,看起来这些东西可能对其他人有帮助(感谢问题的慷慨措辞?)。

所以我将从第二个共同的角度来解决这个问题。假设您确实有 32 个变量,例如 RPG 中角色的属性,有些只需要 byte (strength),有些需要 qword (experience),并且很快就会想起 health 的索引为 4,而 prestidigitation 的索引为 29。 p>

此外,您通常只需要其中几个用于更新的特定部分,例如计算用剑造成伤害的角色不需要 elocutioncharisma,但你也需要需要几个不同的角色(玩家对敌人)具有相同的统计数据,所以你仍然缺少寄存器。

在这种情况下,我经常只是模仿类似 C 的结构:

; defining "PERSON" structure
PERSON_X        equ     0                   ;2B
PERSON_Y        equ     PERSON_X+2          ;2B
PERSON_HP       equ     PERSON_Y+2          ;4B
PERSON_MANA     equ     PERSON_HP+4         ;4B
PERSON_LEVEL    equ     PERSON_MANA+4       ;2B
;...
PERSON_PRESTIDIGITATION equ PERSON_ELOCUTION+1  ;1B
PERSON_SIZE     equ     PERSON_PRESTIDIGITATION+1

; reserving array for 4 player's characters
playersParty:   resb 4*PERSON_SIZE

    ; ... somewhere in the code:
    ; teleporting whole party at x,y=(32,64)
    MOV     ax,32       ; new x
    MOV     bx,64       ; new y
    MOV     ecx,4
    MOV     edi,playersParty
setAllPartyMembers:
    MOV     [edi+PERSON_X],ax
    MOV     [edi+PERSON_Y],bx
    ADD     edi,PERSON_SIZE
    LOOP    setAllPartyMembers

NASM 实际上有“struc”宏,这样可以省去手动计算正确尺寸的麻烦(就像我在上面所做的那样):

; defining "PERSON" structure with base offset 13 in NASM
; (but you want particular attributes aligned to their size boundary)
STRUC person, 13
            alignb  2
    .x:     resw    1
    .y:     resw    1
            alignb  4
    .hp:    resd    1
    .mana:  resd    1
    .level: resw    1
    ;...
    .prestidigitation:  resb    1
    .size:
ENDSTRUC

; player single person with some basic init (e.g. in .data segment)
SEGMENT .data
playerPerson1: ISTRUC person
    AT person.hp,       dd  100
    AT person.mana,     dd  100
    AT person.level,    dw  1
IEND

    ; .. somewhere in the code:
    ; moving player by ax on x, bx on y
    ; and decreasing hp by 1 (it's a trap!)
    MOV     edi,playerPerson1
    ADD     [edi+person.x],ax
    ADD     [edi+person.y],bx
    DEC     DWORD [edi+person.hp]
    ; ...

(我的代码我没有调试过,所以这里可能有bug,但希望原理能看懂就明白了)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多