-4

I am making the game "Connect Four". I have a square board which is 4x4. For each tile on the board I have to draw a disc (squre shaped) which has an x value and a y value. The problem is that I have to make 32 variables or a lot of procedures which change the two variables all the time but these options seem very unefficient and the code would be very long. If you have any suggestions of how to it more efficient, please tell.

*Note - I am using x86 Assembly and TASM Here is the code:

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

I have only programmed a bit just to see if the code works.

Thanks for the help.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
KatomPower
  • 119
  • 1
  • 3
  • 14
  • Unlikely anyone could answer this without at least more details on how the code is structured. In any case, a common tip is to avoid global variables and use local ones. – m0skit0 Jun 17 '16 at 08:40
  • Which language do you use? – Richard Jun 17 '16 at 08:44

2 Answers2

3

Use arrays instead of separate variables? Like an array of four arrays of four (x,y) values. All you need then is the base address of the array, and from that you can get all elements of the arrays through offsets.

In C it would be something like

struct Disc
{
    int x;
    int y;
};

struct Disc array[4][4];

C is a very low-level language, close "to the metal", and could in some cases (especially early in its history) be seen as a very advanced macro-assembler.

An array in C is a sequential and contiguous chunk of memory, each element following the other, so it's very easy to calculate the offsets to a specific element in the array. In fact that's what the C compiler does for you, and it's also the reason that array indexes is starting with zero in C and not 1 like in many other high-level languages from the same era.

For a simple array like e.g.

int a[4];

the offset to the each element in the array is the index multiplied by the size of the data. To get element 0 (i.e. a[0]) you do 0 * sizeof(int), to get the second element you do 1 * sizeof(int).

Now to take the array of arrays of structures I showed above you use the same principle to calculate the offsets from the beginning of the memory: Index multiplied by element size.

If we start backwards, the structure is two int members, which on a typical 32-bit machine is 8 bytes in total (each member being a 4 byte (32 bit) integer, two members). That means that the inner array is 8 bytes time 4 elements, or 32 bytes. To get a specific element in the array you multiply the index with 8 (size of structure) and add it as an offset to the start of the array.

For the outer array every element is 32 bytes (each element is an array of 4 structures), which means the total size of array shown above is 128 bytes. To get an element in that array you multiply the zero-based index with 32.

Using the above, the way to get to the structure at array[i][j] (for an arbitrary but in-range value of i and j) you get the base address of array, add i * 32 to get to the inner array, then add j * 4 to get to the actual structure. In pseudo-code (not real C) it would look like

structure = array + i * 32 + j * 4

That give you the address to a specific structure. Now to get the members of the structure is just the same. The member x is at offset 0 and the member y is at offset 4 (the size of the previous member(s)). Again with the pseudo-code:

x = structure
y = structure + 4

So to handle your board you only need three "variables": The base address of the outer array, and the indexes i and j.

My x86 assembly is rusty, it was a long time ago I used it, but calculating the offsets and moving the correct structure variables into a register is easy IIRC.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks for all the help guys. First of all, I am using Assembly x86 and TASM. Second of all, I uploaded my code so you will understand better. Ped7g I didn't really understand your explanation. I also have another problem. I need to enter a number between 1-4. Let's say I want 4. It checks first if I entered 1. If not, it will check if I pressed 2 and so on so what happens is that I have to press 4 times to get to number 4. How do I fix it so it won't do that? – KatomPower Jun 17 '16 at 15:44
  • 1
    @KatomPower: C is a useful way to express data layout in memory, and to describe what your asm does in general. re: input: it sounds like you need to fix your code to input once and check that input multiple ways. If you know any other programming language, "think" in terms of what happens at a higher level before you implement it in asm. – Peter Cordes Jun 17 '16 at 21:42
  • @KatomPower Added a little explanation to my answer – Some programmer dude Jun 17 '16 at 22:09
  • @KatomPower Read it again, let me know which part you don't understand (particular sentence, or word, or idea). Please comment under my answer, so I will be notified of your comment. Sorry, but "Didn't understand" is too broad for me to focus on anything. – Ped7g Jun 18 '16 at 19:24
2

32 variables is usually an equivalent of single variable (an array) of size of 32 items.

And instead of using variable name square_3_1_x you have in mind a "mapping function", for example you address 4x4 squares as 0,1,2.. per row.

so square(row,column) index is ((row-1)*4+(column-1)) for row/column in 1..4 range.

And then either use *2 and +0 for x / +1 for y: 3_1_x is 16, 3_2_y is 19.

Or +0 for x and +16 for y (3_1_x is 8, 3_2_y is 25).

Or whatever your own fancy mapping you can think of.

So let's say you want to get [x,y] position of disc at row 3 (1..4) and column 2 (1..4) in 32b x86 assembler (NASM syntax) (I like how you didn't specify your platform and syntax, so people answering can choose whatever they wish, and you will then have to understand completely alien syntax to you, and convert it to your final source, very generous from you):

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

edit: Well, since this answer got upvoted twice, it looks like this stuff is maybe helpful to others (thanks to the generous wording of question?).

So I will tackle this from second common perspective. Let's say you really have 32 variables, like for example attributes of an character in RPG, some needing just a byte (strength), some a qword (experience), and it would soon become super annoying to remember that health has index 4, and prestidigitation has index 29.

Also you often need just several of them for particular part of update, like calculating the character doing damage by sword doesn't need elocution and charisma, but also you need several different characters (player vs enemy) with same stats, so you have still shortage of registers.

In such scenario I often just mimick C-like structs:

; 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 actually has "struc" macro, which will save you some hassle with calculating the proper size by hand (as I did above):

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

(I didn't debug my code, so there may be a bug here and there, but hopefully the principle is easy to understand just by reading it)

Ped7g
  • 16,236
  • 3
  • 26
  • 63