assemblyx86-16tasmdosbox

replacing values in an array and incrementing


I'm making the snake game and I ran into 2 problems.

  1. I can't understand how to do the replacement. When you move, in the DS you have the coordinates of the stars and each of them moves one spot to the right. (The first number is the coordinates of the first star)Say in the DS there is: dw 452, 743, 534 and when I run the replacement proc it'll look like: "new number", 452, 743 I tried the following (it didn't work. no matter what direction I move, the stars don't delete themselves):
proc replace_stars
    mov cx, [st_am]   ;the amount of stars, how many loops
    mov bx, [st_am]
    dec bx
    shl bx, 1
    
replace:
    mov di, [stars+bx-2]    ;the one before last stars
    mov bx, [stars+bx]      ;the last stars
    mov [bx], di            ;in the last one, now the one before it
    sub di, 2
    sub bx, 2
    loop replace     ;loop the amount of stars
  ret
endp replace_stars

2)I don't know how to do that when I move in any direction and eat an apple, another star and its coordinates will add to the array. (The first number is the coordinates of the first star)When I move (let's say right), say I have in the DS: dw 2342, 4532, 4653 and after I move it'll look like: (moved right, so +2)2344, 2342, 4532, 4653

MY whole code is:

MODEL small
STACK 100h
DATASEG
; --------------------------
; Your variables here
; --------------------------
saveal db ' '  ;used in line 223-233
dir db 0

app dw 0       ;place of the apple
st_am dw 3
stars dw 0, 0, 0  ;places of the *

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
    
    cmp si, [app]
    jnz move_up
    call apple
    
move_up:
    call delete
    call replace_stars
    ;mov di, [stars+2]    failed attempt
    ;mov [stars+4], di
    ;mov di, [stars]
    ;mov [stars+2], di
    ;sub di, 80*2
    ;mov ah, 156
    ;mov al, '*'
    mov [es:di], 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
    
    cmp si, [app]
    jnz move_down
    call apple
    
move_down:
    call delete
    call replace_stars
    ;mov di, [stars+2]     failed attempt
    ;mov [stars+4], di
    ;mov di, [stars]
    ;mov [stars+2], di
    ;add di, 80*2
    ;mov ah, 156
    ;mov al, '*'
    mov [es:di], 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
    
    cmp si, [app]
    jnz move_left
    call apple
    
move_left:
    call delete
    call replace_stars
    
    ;mov di, [stars+2]    failed attempt
    ;mov [stars+4], di
    ;mov di, [stars]
    ;mov [stars+2], di
    ;mov ah, 156
    ;mov al, '*'
    ;mov [es:di], ax
    mov [stars], si
    
    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
    
    cmp si, [app]
    jnz move_right
    call apple
    
move_right:
    call delete
    call replace_stars
    
    ;mov di, [stars+2]    failed attempt
    ;mov [stars+4], di
    ;mov di, [stars]
    ;mov [stars+2], di
    ;mov ah, 156
    ;mov al, '*'
    ;mov [es:di], ax
    mov [stars], si
    
    add si, 2
    mov ah, 156
    mov al, '*'
    mov [es:si], ax
    
not_move_right:
  ret
endp right

proc apple
    mov ax, 40h
    mov es, ax
    mov ax, [es:6ch]
    and ax, 0000001111111110b
    mov di,ax
    mov [app], di
    mov ax, 0b800h
    mov es, ax
    
    mov al, '@'
    mov ah, 154
    mov [es:di], ax
  ret 
endp apple
    
proc delete
    mov bx, offset stars
    mov di, [st_am]
    dec di
    shl di, 1
    mov di, [bx+di]
    mov ax, 0b800h
    mov es, ax
    
    mov al, ' '
    mov ah, 0
    
    mov [es:di], ax
    
    ;mov di, [stars+2]
    ;mov [stars+4], di
    ;mov di, [stars]
    ;mov [stars+2], di
    
    mov [stars], si
  ret
endp delete

proc replace_stars
    mov cx, [st_am]   ;the amount of stars, how many loops
    mov bx, [st_am]
    dec bx
    shl bx, 1
    
replace:
    mov di, [stars+bx-2]    ;the one before last stars
    mov bx, [stars+bx]      ;the last stars
    mov [bx], di            ;in the last one, now the one before it
    sub di, 2
    sub bx, 2
    loop replace     ;loop the amount of stars
  ret
endp replace_stars

proc first_3_dots
    mov bx, offset stars
    mov si, ((12*80+40)*2)-2
    mov al, '*'
    mov ah, 156
    mov [es:si], ax
    mov [bx], si
    mov si, (12*80+40)*2
    mov al, '*'
    mov ah, 156
    mov [es:si], ax
    mov [bx+2], si
    mov si, ((12*80+40)*2)+2
    mov al, '*'
    mov ah, 156
    mov [es:si], ax
    mov [bx+4], si
  ret
endp first_3_dots

proc delay
    mov cx, 0FFFFh
delay1:
    mov ax, 300
delay2:
    dec ax
    jnz delay2
    loop delay1
  ret
endp delay


proc move_stars_right
    mov cx, [st_am]
    
    mov di, offset stars
    mov bx, di
    
move_loop:
    mov ax, [di]
    
    add ax, 2
    mov [bx], ax
    
    mov ah, 156
    mov al, '*'
    mov [es:di], ax
    
    add di, 2
    add bx, 2
    
    loop move_loop
    
  ret
endp move_stars_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
    
    call first_3_dots
    mov si, ((12*80+40)*2)-2    

    call apple
    
wasd:
    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 wasd
s:
    call down
    jmp wasd    
a:
    call left
    jmp wasd
d:
    call right
    jmp wasd
    
exit:
    mov ax, 4c00h
    int 21h
END start

Solution

  • dw 452, 743, 534
    dw 2342, 4532, 4653
    

    I find it worrying to see these examples of what you think could be in the stars array. The values stored in the stars array represent offset addresses in the video memory at linear address 000B8000h for the 80x25 text screen. Then what is wrong?

    (The first number is the coordinates of the first star)

    Not really! The first number on the array is the offset address on the screen of the first star. Coordinates would be the mention of column and row, or X and Y.

    after I move it'll look like: (moved right, so -2) 2340, 2342, 4532, 4653

    Just another example of not truly understanding what moving the snake entails. When you move to the right on the screen, the address (that you keep in SI) gets increased by +2, therefore the expected numbers would start with 2344, 2342, ...


    The replace_stars proc is disastrously mixing addresses that refer to the screen with addresses that refer to the stars array that resides in DATASEG!
    And it is doing one iteration too many, because in an array with 3 elements you can do just 2 of those movements.
    This is the revised code:

      mov  cx, [st_am]   ; The amount of stars (3 or more)
      dec  cx            ; How many loops
      mov  bx, cx
      shl  bx, 1         ; Offset to the last star
    replace:
      mov  ax, [stars+bx-2]
      mov  [stars+bx], ax
      sub  bx, 2
      loop replace
      ret
    

    The better version of this loop does not use the loop instruction (and so does not clobber the CX register):

      mov  bx, [st_am]   ; The amount of stars (3 or more)
      dec  bx
      shl  bx, 1         ; Offset to the last star
    replace:
      mov  ax, [stars+bx-2]
      mov  [stars+bx], ax
      sub  bx, 2
      jnz  replace
      ret
    

    I take it that your move_stars_right proc is an attempt to make the snake grow? Forget about it, it's too early! You need to fix the errors first. You didn't even apply corrections about which I spoke in previous answers...

    And similar to what I told about the replace_stars proc, this one is also disastrously mixing addresses that refer to the screen with addresses that refer to the stars array that resides in DATASEG!

    Have you ever played the snake game?

    https://www.google.be/url?esrc=s&q=&rct=j&sa=U&url=https://www.quora.com/Why-cant-snakes-crawl-backwards&ved=2ahUKEwjr8-6n_oWEAxXe2gIHHTuzAsgQFnoECAIQAw&usg=AOvVaw2fkOBLUqGbzjfOYcYSdgdt

    When the snake is currently moving to the left, you cannot allow a request to move to the right.
    When the snake is currently moving to the right, you cannot allow a request to move to the left.
    When the snake is currently moving to the top, you cannot allow a request to move to the bottom.
    When the snake is currently moving to the bottom, you cannot allow a request to move to the top.

    I had solved this in my previous answer.

    [EDIT]

    From a comment:

    it worked except for something strange. When I go up or down, it leaves behind random characters.

    At some point you have decided about a 'failed attempt' and you have turned a number of lines into comments. Sadly, for the up and down procs you forgot to put the instruction mov [es:di], ax behind such a semicolon. Those are the two lines that produce random characters.

    For the up and down procs you further forgot to update the first value in the stars array:

    sub si, 80*2
    mov [stars], si
    

    and

    add si, 80*2
    mov [stars], si
    

    And for the left and right procs you did not forget to update the first value in the stars array but it comes too soon (so the value stays the same):

    sub si, 2
    mov [stars], si
    

    and

    add si, 2
    mov [stars], si