2016-06-17 2 views
-4

Я делаю игру «Connect Four». У меня квадратная доска, которая составляет 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 

Я программируюсь только немного просто, чтобы увидеть, если код работает.

Спасибо за помощь.

+0

Вряд ли кто-нибудь может ответить на этот вопрос, не в наименее подробнее о том, как структурирован код. В любом случае, общий совет - избегать глобальных переменных и использовать локальные. – m0skit0

+0

На каком языке вы владеете? – Richard

ответ

3

Использовать массивы вместо отдельных переменных? Как массив из четырех массивов из четырех (x, y) значений. Все, что вам нужно, это базовый адрес массива, и из этого вы можете получить все элементы массивов с помощью смещений.

В C это будет что-то вроде

struct Disc 
{ 
    int x; 
    int y; 
}; 

struct Disc array[4][4]; 

С очень низкоуровневый язык, близкий «к металлу», и может в некоторых случаях (особенно в начале своей истории) будет рассматривается как очень продвинутый макроассемблер.

Массив в 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] (для произвольной, но в-диапазоне значение i и j) Вы получаете базовый адрес array, добавьте i * 32, чтобы добраться до внутреннего массива, затем добавьте j * 4, чтобы перейти к фактической структуре.В псевдо-коде (не реальный C), это будет выглядеть как

structure = array + i * 32 + j * 4 

Это даст вам адрес для конкретной структуры. Теперь, чтобы получить элементы структуры, все равно. Элемент x находится со смещением 0, а элемент y имеет смещение 4 (размер предыдущего элемента (элементов)). Опять же с псевдо-кодом:

x = structure 
y = structure + 4 

Так обрабатывать ваш совет вам нужно только три «переменные»: базовый адрес внешнего массива, а также индексы i и j.

Моя сборка x86 является ржавой, это было давно, я использовал ее, но вычисление смещений и перемещение правильных структурных переменных в регистр легко IIRC.

+0

Спасибо за помощь. Прежде всего, я использую Assembly x86 и TASM. Во-вторых, я загрузил свой код, чтобы вы поняли лучше. Ped7g Я не очень понял ваше объяснение. У меня также есть другая проблема. Мне нужно ввести число от 1 до 4. Предположим, я хочу 4. Сначала он проверяет, если я ввел 1. Если нет, он будет проверять, нажал ли я 2 и так далее, так что случается, что я должен нажать 4 раза, чтобы добраться до номера 4. Как это исправить? он этого не сделает? – KatomPower

+1

@KatomPower: C - полезный способ выразить расположение данных в памяти и описать, что делает ваш asm в целом. re: input: похоже, что вам нужно исправить свой код для ввода один раз и проверить, что вход несколько. Если вы знаете какой-либо другой язык программирования, подумайте о том, что происходит на более высоком уровне, прежде чем реализовать его в asm. –

+0

@ KatomPower Добавил небольшое объяснение к моему ответу –

2

32 переменных обычно эквивалентно одной переменной (массиву) размером 32 элемента.

И вместо использования имени переменной square_3_1_x вы имеете в виду «функцию сопоставления», например, вы адресуете квадраты 4x4 как 0,1,2 .. на строку.

так square(row,column) указатель есть ((row -1) * 4 + (column -1)) для строки/столбца в диапазоне 1..4.

А затем либо использовать * 2 и +0 для x/+1 для y: 3_1_x является 16, 3_2_y является 19.

Или +0 для x и +16 для y (3_1_x является 8, 3_2_y является 25).

Или что бы вы ни думали о своем собственном воображаемом картотеке.

Предположим, вы хотите получить позицию [x, y] диска в строке 3 (1..4) и столбце 2 (1..4) в ассемблере 32b x86 (синтаксис NASM) (мне нравится, как вы не указывали вашу платформу и синтаксис, поэтому люди, отвечающие, могут выбирать все, что пожелают, и тогда вам нужно будет понять полностью чуждый синтаксис для вас и преобразовать его в ваш окончательный источник, очень щедро от вас):

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 
    ; ... 

редактировать: Ну, так как этот ответ был upvoted дважды, похоже, этот материал может быть полезным для других (благодаря щедрой формулировке вопроса?).

Так что я займусь этим из второй общей перспективы. Допустим, вы действительно есть 32 переменных, как, например, атрибуты персонажа в RPG, некоторые нуждаются только byte (силы), некоторые в qword (опыт), и это скоро станет супер раздражает помнить, что здоровье имеет индекс 4 и престиж имеет индекс 29.

Также часто требуется только несколько из них для определенной части обновления, как вычисления символа делает урон от меча не нуждается в ораторском искусстве и харизме, но и вам нужен несколько различных персонажей (игрок против врага) с одинаковой статистикой, поэтому у вас все еще есть нехватка регистров.

В таком случае я часто просто подражать 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] 
    ; ... 

(я не отлаживать код, так что может быть ошибка здесь и там, но, надеюсь, этот принцип легко понять, просто прочитав его)

Смежные вопросы