TASM assembly array being funky and not working - arrays
Basically....
I'm trying to make a snake game in TASM assembly. currently, main problem is the fact that the array of the snake game (a 400 cell array of bytes) is being completely funky.
example:
when i try to put it later on in the DATASEG (like being one of the last vars defined) and i try to paint the array for the start of the game, it loads up as if some random cells have value different than 0 (they should not). another problem is when i change the value of 1 random cell to generate an apple, it sometimes goes and paints 2 apples, meaning something went awry...
This is how i defined my array: GameArray db 400 dup(0)
This is how i mov array: mov bx, offset GameArray
also, the timer just doesn't seem to work. what i have right now in the code are just the functions and the attempt at seeing if the timer works:
`.286
IDEAL
model small
stack 100h
DATASEG
GameArray db 400 dup(0) ;20x20 array for the snake game. need to be first variable for some reason, or cell values are jumbled up. wierd...
ApplePresent db 0 ;incase 2 or more cells with applevalue, disregard the later cells and make them empty squares
seconds db 99 ;variable for timer to check in how many miliseconds there is change.
One db 1 ;used as number '1' as word so bx which array is moved to will have no problems.
AppleValue db 255 ;used as number '256' as word so bx which array is moved to will have no problems.
Zero db 0 ;used as number '0' as word so bx which array is moved to will have no problems.
PointGained db 0 ;Boolean var to check if point was gained in the movement. if so, snake will be grown.
NumCell dw 0 ;NumCell represents the cell in the array which the snake's head will be going to.
Score db 0 ;keeps score of the game.
xArr dw 10 ;x coordinate of head (value 5 at start) at start of game. (x of array)
yArr dw 9 ;y coordinate of head (value 5 at start) at start of game. (y of array)
SnakeHead db 5 ;SnakeHead value will be copied to element of array snake head will go to.
xDraw dw ? ;x coordinate for drawing screen
yDraw dw ? ;y coordinate for drawing screen
xDrawlim dw ? ;x coordinate for drawing screen limit of box
yDrawlim dw ? ;y coordinate for drawing screen limit of box
Direction db 1 ;1 = right, 2 = up, 3 = left, 4 = down. gets value from last click of WASD keys
Clock equ es:6ch ;looks at clock memory segment.
CODESEG
proc ApplesFix ;FUnction to fix if there are 2 or more cells with value of 255 in them. if so, reset the value of the array cell to 0.
pusha
mov bx, offset GameArray
mov ax, 400
ApplesFixLoop:
mov cl, [AppleValue]
cmp [bx], cl
je IncrementApplePresent
inc bx
dec ax
jnz ApplesFixLoop
jmp EndFix
IncrementApplePresent:
inc [ApplePresent]
cmp [ApplePresent],1
jg FixCell
inc bx
dec ax
jnz ApplesFixLoop
jmp EndFix
FixCell:
mov cl, [Zero]
mov [bx], cl
inc bx
dec ax
jnz ApplesFixLoop
EndFix:
popa
ret
endp ApplesFix
proc RandApple
pusha ;pushes all registers. never knew the command so only using it now.
push [Numcell]
RandGen:
mov [NumCell],0
mov ax, 40h
mov es, ax
mov cx, 10
mov bx, 0
random_loop_apple:
mov ax, [Clock]
mov ah, [byte cs:bx]
xor al, ah
and al, 11111111b
xor ah, ah
mov [NumCell], ax
add [NumCell], 11
loop random_loop_apple
mov bx, offset GameArray
add bx, [NumCell]
mov cl, [Zero]
cmp [bx], cl
je GenerateApple
jmp RandGen
GenerateApple:
mov cl, [AppleValue]
mov [bx], cl
pop [Numcell]
popa
ret
endp RandApple
proc KeyPress ;function which gets key press from WASD and will change var 'Direction' according to it.
push ax
mov ah, 1d
int 21h
Wait_for_Data:
cmp al, 87;'W'
je MovingUp
cmp al, 65;'A'
je MovingLeft
cmp al, 83;'S'
je MovingDown
cmp al, 68;'D'
je MovingRight
jmp Wait_for_Data
MovingUp:
mov [Direction], 2d
jmp EndKeyPress
MovingLeft:
mov [Direction], 3d
jmp EndKeyPress
MovingDown:
mov [Direction], 4d
jmp EndKeyPress
MovingRight:
mov [Direction], 1d
jmp EndKeyPress
EndKeyPress:
pop ax
ret
endp KeyPress
proc MoveHead ;Head value will be copied into the array cell which snake moves to.
pusha
mov bx, offset GameArray
add bx, [NumCell]
mov cl, [SnakeHead]
mov [bx], cl
popa
ret
endp MoveHead
proc DirectionSnake ;proc for changing x,y values of array to know which square head value will be copied to.
cmp [Direction], 1d
je MoveRight
cmp [Direction], 2d
je MoveUp
cmp [Direction], 3d
je MoveLeft
cmp [Direction], 4d
je MoveDown
MoveRight:
add [xArr] ,1d
cmp [xArr], 19d
jg OtherSideRight
jmp EndDirectionSnake
MoveUp:
sub [yArr], 1d
cmp [yArr], 0d
jb OtherSideUp ;function for making snake head appear at the highest layer if snake goes down out of boundaries. (same with labels of same name, just for different function)
jmp EndDirectionSnake
MoveLeft:
sub [xArr], 1d
cmp [xArr], 0d
jb OtherSideLeft
jmp EndDirectionSnake
MoveDown:
add [yArr], 1d
cmp [yArr], 19d
jg OtherSideDown
jmp EndDirectionSnake
OtherSideRight:
mov [xArr], 0d
jmp EndDirectionSnake
OtherSideUp:
mov [yArr], 19d
jmp EndDirectionSnake
OtherSideLeft:
mov [xArr], 19d
jmp EndDirectionSnake
OtherSideDown:
mov [yArr], 0d
EndDirectionSnake:
ret
endp DirectionSnake
proc findHeadXY ;find xy coordinate of the cell in array which head will be going to
push ax ;preserving value of ax by pushing him into stack and popping him at the end of function.
mov ax, [xArr]
mov [NumCell], ax ;NumCell represents the cell in the array which the snake's head will be going to.
mov ax, [yArr]
FindArrayCelly: ;label for loop of finding the array cell's y value that snake head is going to be copied into.
add [NumCell], 20d
sub ax, 1d
jnz FindArrayCelly
pop ax
ret
endp findHeadXY
proc MoveAction ;function will find whats inside the cell snake head will be going to and see if snake eats apple and moves, regular movement or lose.
push bx
push cx
mov bx, offset GameArray
add bx, [NumCell] ;goes to the cell which the snake head will be moving to.
mov cl, [AppleValue]
cmp [bx], cl
je SnakeEatsApple
mov cl, [Zero]
cmp [bx], cl
je SnakeMoves
jmp GameLost
SnakeEatsApple:
add [Score], 1d ;if apple is eaten score is increased by 1.
mov [PointGained], 1d ;sets boolean to 1 meaning 'True', snake will lengthen
cmp [Score], 255d
je GameWon
call MoveHead
SnakeMoves:
call MoveHead
GameLost:
mov ax, 0c00h ;replicating exit interrupt.
int 21h
GameWon:
mov ax, 0c00h ;replicating exit interrupt.
int 21h
EndMoveAction:
pop cx
pop bx
ret
endp MoveAction
proc BlackSquare ;when array element has value which is 0, draw white square
push cx
push dx
mov cx,[xDraw]
mov dx,[yDraw]
mov al, 15d
loopboxB:
mov bh,0h
mov ah,0ch
int 10h
inc cx
cmp cx,[xDrawlim]
jne loopboxB
mov cx,[xDraw]
inc dx
cmp dx,[yDrawlim]
jne loopboxB
pop dx
pop cx
ret
endp BlackSquare
proc SnakeSquare ;when array element has value which is not 0 or 256, draw green square (green color)
push cx
push dx
mov cx,[xDraw]
mov dx,[yDraw]
mov al, 2d ;al assigned different value for different color
loopboxS:
mov bh,0h
mov ah,0ch
int 10h
inc cx
cmp cx,[xDrawlim]
jne loopboxS
mov cx,[xDraw]
inc dx
cmp dx,[yDrawlim]
jne loopboxS
pop dx
pop cx
ret
endp SnakeSquare
proc AppleSquare ;when array element has value which is 256, draw yellow square
push cx
push dx
mov cx,[xDraw]
mov dx,[yDraw]
mov al, 14d ;al assigned different value for different color
loopboxA:
mov bh,0h
mov ah,0ch
int 10h
inc cx
cmp cx,[xDrawlim]
jne loopboxA
mov cx,[xDraw]
inc dx
cmp dx,[yDrawlim]
jne loopboxA
pop dx
pop cx
ret
endp AppleSquare
proc DrawScreen ;draws screen according to value in array elements.
pusha
mov bx, offset GameArray
mov ax, 0d
mov [xDraw], 121d ;starting values for painting screen
mov [ydraw], 101d
mov [xDrawlim], 130d
mov [yDrawlim], 110d
CheckElementValue:
mov cl, [Zero]
cmp [bx], cl
je CallBlackSquare ;goes to label to call function BlackSquare
mov cl, [AppleValue]
cmp [bx], cl ;cx is copying AppleValue since comparing memory (var) to memory (array which is copied in bx) is illegal.
je CallAppleSquare ;goes to label to call function AppleSquare
jmp CallSnakeSquare ;goes to label to call function SnakeSquare
CallBlackSquare:
call BlackSquare
add [xDraw], 10d
add [xDrawlim], 10d
inc ax
cmp ax, 400d
je EndDrawingScreen
add bx,1
cmp [xDrawlim], 330d
je DropLine
jmp CheckElementValue
MidJumP:
jmp CheckElementValue
CallAppleSquare:
call AppleSquare
add [xDraw], 10d
add [xDrawlim], 10d
inc ax
cmp ax, 400d
je EndDrawingScreen
add bx,1
cmp [xDrawlim], 330d
je DropLine
jmp CheckElementValue
CallSnakeSquare:
call SnakeSquare
add [xDraw], 10d
add [xDrawlim], 10d
inc ax
cmp ax, 400d
je EndDrawingScreen
add bx,1
cmp [xDrawlim], 330d
je DropLine
jmp CheckElementValue
DropLine:
add [yDraw], 10d
add [yDrawlim], 10d
mov [xDraw], 121d
mov [xDrawlim], 130d
cmp [yDrawlim], 310d
jne MidJumP
EndDrawingScreen:
popa
ret
endp DrawScreen
proc CycleChange ;the procedure reduces all cells in array which value is greater than 0 by 1, so tail of the snake will get erased after new head is formed.
pusha
mov bx, offset GameArray
mov ax, 400d
CheckArray:
cmp [word ptr bx], 0 ;checks current element of array looked at and checks if equal to 0. need to add that will not reduce value if its 256 as well.
jne DecreaseCellValue
add bx, 1d
dec ax
jz EndCycleChange
DecreaseCellValue:
mov cl, [One]
sub [bx], cl
add bx, 1d
dec ax
jmp CheckArray
EndCycleChange:
popa
ret
endp CycleChange
proc ResetArray ;restore all array values to 0.
pusha
mov bx, offset GameArray
mov ax, 400d
ResetArrayL:
mov cl, [Zero]
mov [byte ptr bx], cl
inc bx
dec ax
jnz ResetArrayL
popa
ret
endp ResetArray
start:
mov ax, #data
mov ds, ax
GameStart:
mov bx, offset GameArray
add bx, 210
push cx
mov cx, [word ptr SnakeHead]
GenerateSnake: ;puts snake of length 5 in the array.
mov [word ptr bx], cx
inc bx
loop GenerateSnake
GenerateStartingApple:
call RandApple ;Puts apple randomly in cell of array before starting the game.
call ApplesFix
mov ax,012h
int 10h ;640 x 480 16 colors. graphic mode interrupt.
secstart:
call DrawScreen
mov ah,02ch ; Get current second
int 021h
mov bh,dh ; Store current second
readloop:
mov ah,02ch ; Get new time. Seconds are stored in dh
int 021h
sub dh,1 ; Subtract 1 from new second. Giving 1 Secs for input.
GoBackCheck: ;if no key has been pressed, until second is over input from keyboard will be checked.
cmp bh,dh
je SecondPassed ; Exit when DH is finally equal to BH.
mov ah,06h ; Function 06h of INT 021 will directly read from the Stdin/Stdout
mov dl,0ffh ; Move 0ff into the DL register to read from the keyboard
int 21h
jz GoBackCheck ; If the zero flag of the FLAGS register is set, no key was pressed.
call KeyPress
jmp GoBackCheck
SecondPassed: ;here snake moves and checks if you lost/won game.
call findHeadXY
call MoveHead
GoBack:
jmp secstart
exit:
mov ax, 0c00h
int 21h
END start`
Related
Sorting an array in assembly 8086 16 bit
I am trying to sort an array by using functions that finds the smallest number in an array, and the other swaps two variables. But for some reason the array doesn't change and stays the same. I thing I have a problem with the stack but I can't find it. This is my code: sorry its long and not organized. I just started assembly. ` org 100h jmp start array db 1,9,3,6,3 **;should get 1,2,3,6,9** min_in_array dw ? start: lea si, array push 5 push si call sortArray pop bx pop bx mov ah, 0 int 16h ret ;doesn't work PROC sortArray push bp mov bp, sp mov dx, 0 ;the index mov cx, [bp+6];size mov di, [bp+4];array loop_arr: add di, dx push di call findMin pop di sub di, dx add di, min_in_array push dx push di call swap pop di pop dx sub di, min_in_array inc dx mov ax, [di] loop loop_arr mov sp, bp pop bp ret ENDP sortArray ;works PROC findMin push bp mov bp, sp sub sp, 4 mov cx, 0 ;init the counter mov di, [bp+4] mov al, [bp-2] ;initialising the min save var mov al, [di] mov bx, [bp-4] ;the index to save mov bx, 0 run: cmp al, [di] ja change_min cmp cx, 4 ;check if cx is lower than the size of the array inc cx ;+1 inc di ;move forward in the array jb run ;check again jmp fin ;finished - cx = size change_min: mov al, [di] ;change the min mov bx, cx ;assign the index inc di cmp cx, 4 je fin inc cx jmp run fin: mov sp, bp pop bp mov cx, 0 mov min_in_array, bx ret ENDP findMin ;function works PROC swap ;creates fram push bp mov bp,sp sub sp,2 ;make space for local temp mov bx, [bp+6] mov cx, [bp+4] ;swaping using the temp varaiable mov [bp-2], bx mov bx, cx mov cx, [bp-2] ;close frame mov sp, bp pop bp ret ENDP swap `
I have a problem with the stack but I can't find it. Your use of the stack is actually fine: prologue, epilogue, cleaning. But there's one additional thing that the stack is good at, and that's preserving register values. Your sortArray procedure depends on the CX register, but you destroy its value in the findMin and swap procedures! You say findMin works, but I assure you it doesn't. Other than not preserving CX and containing a lot of unused code, findMin always processes 5 elements eventhough the supplied address moved up with each invokation, meaning you are processing garbage that follows the original array in memory. Moreover the result that you store in the min_in_array variable is an offset in the unsorted partition of the array, but after returning, sortArray will use this same value as an offset in the original array. Can't work that way... You say swap works, but I assure you it doesn't. What you supply to this procedure is an offset in the original array and an (wrongly calculated) address within the original array. You fetch these arguments from the stack and only swap these in registers, nothing more. You never read/write in the array, so there's no swapping taking place. See if next code points you in the right direction: add di, dx push cx ; Number of elements in the unsorted partition push di ; Address of the start of the unsorted partition call findMin ; -> AX (BL CX SI) pop di pop cx push ax ; Address of the Min from the unsorted partition push di ; Address of the start of the unsorted partition call swap ... ; IN () OUT (ax) MOD (bl,cx,si) PROC findMin push bp mov bp, sp mov cx, [bp + 6] mov si, [bp + 4] min: mov bl, [si] mov ax, si run: dec cx jz done inc si cmp bl, [si] jb run jmp min ; Go change min done: pop bp ret ENDP findMin
Input and print an array of strings in Assembly 8086
I am trying to make a 8086 program in which I input an array of string and then the program prints them. But the program prints only the 1st characters of input strings and jumbled text. This is the code where I attempted to do it. data segment ; Definicija podataka poruka1 DB "Input array length: $" strN DB " " N DW 0 poruka2 DB "Input string: $" strM DB " " niz1 DB 16 dup(?) ends ; Deficija stek segmenta stek segment stack dw 128 dup(0) ends ; Ucitavanje znaka bez prikaza i cuvanja keypress macro push ax mov ah, 08 int 21h pop ax endm ; Isis stringa na ekran writeString macro s push ax push dx mov dx, offset s mov ah, 09 int 21h pop dx pop ax endm ; Kraj programa krajPrograma macro mov ax, 4c02h int 21h endm code segment ; Novi red novired proc push ax push bx push cx push dx mov ah,03 mov bh,0 int 10h inc dh mov dl,0 mov ah,02 int 10h pop dx pop cx pop bx pop ax ret novired endp ; Ucitavanje stringa sa tastature ; Adresa stringa je parametar na steku readString proc push ax push bx push cx push dx push si mov bp, sp mov dx, [bp+12] mov bx, dx mov ax, [bp+14] mov byte [bx] ,al mov ah, 0Ah int 21h mov si, dx mov cl, [si+1] mov ch, 0 kopiraj: mov al, [si+2] mov [si], al inc si loop kopiraj mov [si], '$' pop si pop dx pop cx pop bx pop ax ret 4 readString endp ; Konvertuje string u broj strtoint proc push ax push bx push cx push dx push si mov bp, sp mov bx, [bp+14] mov ax, 0 mov cx, 0 mov si, 10 petlja1: mov cl, [bx] cmp cl, '$' je kraj1 mul si sub cx, 48 add ax, cx inc bx jmp petlja1 kraj1: mov bx, [bp+12] mov [bx], ax pop si pop dx pop cx pop bx pop ax ret 4 strtoint endp ; Konvertuje broj u string inttostr proc push ax push bx push cx push dx push si mov bp, sp mov ax, [bp+14] mov dl, '$' push dx mov si, 10 petlja2: mov dx, 0 div si add dx, 48 push dx cmp ax, 0 jne petlja2 mov bx, [bp+12] petlja2a: pop dx mov [bx], dl inc bx cmp dl, '$' jne petlja2a pop si pop dx pop cx pop bx pop ax ret 4 inttostr endp start: ; postavljanje segmentnih registara ASSUME cs: code, ss:stek mov ax, data mov ds, ax ; Mesto za kod studenata writeString poruka1 ; Unos broja elemenata push 3 push offset strN call readString ; Pretvaranje strN u broj push offset strN push offset N call strtoint call novired writeString strN ; Unos elemenata niza mov cx, N mov di, 0 mov si, 0 unos: call novired writeString poruka2 push 6 push offset strM call readString mov al, strM mov niz1[di], al add di, 2 add si, 1 loop unos call novired mov cx, N mov di, 0 mov si, 0 ispis: writeString niz1[di] add di, 2 add si, 1 loop ispis krajPrograma ends end start
I input an array of string and then the program prints them. But the program prints only the 1st characters of input strings ... What else could the program print if the 1st character is all that you store in memory? mov al, strM mov niz1[di], al add di, 2 ... and jumbled text. With add di, 2 you leave an undetermined byte between any two of these 1st characters. That's not going to look nice. Make that byte the DOS string terminator $. Your writeString macro does not load an address but a word from memory. That's not going to work. The invokation writeString niz1[di] gets expanded into mov dx, offset niz1[di]. What you need here is LEA instead of MOV. Try the following: .... unos: call novired writeString poruka2 push 6 push offset strM call readString mov al, strM MOV AH, "$" mov niz1[di], AX add di, 2 loop unos call novired mov cx, N mov di, 0 ispis: LEA DX, niz1[di] MOV AH, 09h INT 21h add di, 2 loop ispis ...
How to sort an array using stack in assembly
I want to sort an array while using the stack: so first things first I pushed it all into the stack. then I'm locating the minimum element in the stack, swapping it with the top element popping it out and move it back to the array. but something isn't right and about halfway there it got messed up (DI is one index below than what it should really be) data segment a db 5h,12h,6h,4h,9h len equ $-a loop_counter db len min_index dw 0 min db ? ends stack segment dw 128 dup(0) ends code segment ;TODO: Locate min in stack xchg it with top element copy to array and pop it :| start: mov ax, data mov ds, ax mov bx,0 mov cx,0 mov cl,loop_counter push_arr_to_stack: mov al,a[bx] push ax inc bx loop push_arr_to_stack mov bx,len-1 mov ax,0 mov cl,loop_counter mov bp,sp mov ax,[bp] mov bx,[bp] mov di,0 mov dx,0 mov si,2 mov di_check,len-loop_counter find_min_to_arr: cmp bx,ax jb new_min mov bx,[bp+si] add si,2 loop find_min_to_arr mov min,al xchg a[di],al jmp pop_min new_min: mov ax,bx mov bx,[bp+si] mov min_index,si sub min_index,2 add si,2 dec cx jmp find_min_to_arr pop_min: mov dx,[bp] xchg di,min_index mov [bp+di],dx xchg di,min_index pop dx mov dx,0 inc di mov si,0 cmp di,len je b dec loop_counter mov cl,loop_counter jmp find_min_to_arr b: mov ax, 4c00h ; exit to operating system. int 21h ends end start
first I pushed it all into the stack. This part is fine although for speed reasons you should forget about loop .. and replace it with dec cx followed by jnz .. then I'm locating the minimum element in the stack, swapping it with the top element popping it out and move it back to the array. Here your code gets very complicated and it contains many errors. Also the code does not perform true swapping between the located minimum and the element at the top of the stack. I tried amending your code but as is often the case, it is beyond repair. Below is my rewrite that you should study, not just copy! I have defined the loop_counter a word variable because that's easier. Additionally I kept it in the DX register that was sitting there doing nothing... Pushing it all into the stack mov bx, dx push_arr_to_stack: mov al, a[bx-1] push ax dec bx jnz push_arr_to_stack I push the array in reverse so the stack has the elements in the same order as the original array. This is not necessary for the task, but it is simpler and it leaves the BX register at zero for use below. Locating the minimum in the stack Again: mov bp, sp xor si, si mov al, [bp+si] ; Chosen minimum mov di, si ; Remember its position mov cx, dx dec cx ; N elements = N-1 compares jz .c .a: add si, 2 cmp al, [bp+si] jbe .b mov al, [bp+si] ; New minimum mov di, si ; Remember its position .b: dec cx jnz .a Swapping it with the top element .c: xchg al, [bp] mov [bp+di], al Popping it out and moving it back to the array pop ax mov a[bx], al inc bx dec dx jnz Again The important thing here is that the above exactly does what the task description said.
How to preserve an array or string in x86
I'm programming the game "15 puzzle game" in x86 using tasm asm/dosbox. I want to "save" or "preserve" my array called 'a' that is being declared in my data segment, so that after I swap the bytes around using upArrow, downArrow, etc... and then I press 'n' for new game, I can set my array 'a' back to it's original state as it was declared in my data segment. Here is my code: .MODEL TINY .386 .DATA PROMPT DB "Enter q to quit, arrow keys to move, n to restart (new game) HAPPY HOLIDAYS!! :)$" ;this is board preset A a DB 201,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,203,205,205,205,205,187, DB 186,255,48,50,255,186,255,48,49,255,186,255,48,51,255,186,255,48,52,255,186,255,48,53,255,186,255,48,54,255,186, DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185, DB 186,255,48,55,255,186,255,48,56,255,186,255,48,57,255,186,255,49,48,255,186,255,49,49,255,186,255,49,50,255,186, DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185, DB 186,255,49,51,255,186,255,49,52,255,186,255,49,53,255,186,255,49,54,255,186,255,49,55,255,186,255,255,255,255,186, DB 204,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,206,205,205,205,205,185, DB 186,255,49,56,255,186,255,49,57,255,186,255,50,48,255,186,255,50,49,255,186,255,50,50,255,186,255,50,51,255,186, DB 200,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,202,205,205,205,205,188,"$" col DB 0 row DB 0 board DB 0 .CODE org 100h MAIN PROC ;initialize display step 0 MOV AH, 00h MOV AL, 03h INT 10h MOV AX, 0B800h MOV ES, AX XOR di,di ;initialize configuration and dislay prompt step 1 newGame: call initConfig ;display board step 2 ;wait for key step 3 game: ;print board call printBoard1 ;get cursor x y call SetCursor MOV AH, 0 INT 16H MOV BL, AL ;up arrow CMP AH, 48h jz upArrow ;down arrow CMP AH, 50h jz downArrow ;right arrow CMP AH, 4dh jz rightArrow ;left arrow CMP AH, 4bh jz leftArrow ;lowercase q CMP AL, 71h jz EXIT ;uppercase q CMP AL, 51h jz EXIT ;lowercase n CMP AL, 6eh jz newGame ;uppercase n CMP AL, 4eh jz newGame jmp game MAIN ENDP EXIT: MOV AH, 4CH ; return control to DOS INT 21H SetCursor: mov dl, col mov dh, row mov bh, 0 mov ah, 02h int 10h ret getStrlen: lodsb cmp al, 24h je strlen_end inc bx jmp getStrlen strlen_end: ret loadAndDisplayStr: lodsb stosw dec cx jne loadAndDisplayStr ret printBoard1: MOV board, 1 xor dx,dx xor ax,ax mov cx, 9 myloop1: push cx lea si, a add si, dx mov cx, 31 mov di, ax push ax mov ah, 4 call loadAndDisplayStr pop ax add ax, 160 add dx, 32 pop cx dec cx jnz myloop1 ret upArrow: xor si, si xor di, di lea bx, a mov ax, 32 sub row, 2 mul row add al, col mov di, ax mov ax, 32 add row, 2 mul row add al, col mov si, ax mov dx, [bx+si] xchg dx, [bx+di] xchg [bx+si], dx sub row, 2 jmp game downArrow: xor si, si xor di, di lea bx, a mov ax, 32 add row, 2 mul row add al, col mov di, ax mov ax, 32 sub row, 2 mul row add al, col mov si, ax mov dx, [bx+si] xchg dx, [bx+di] xchg [bx+si], dx add row, 2 jmp game leftArrow: xor si, si xor di, di lea bx, a mov ax, 32 sub col, 5 mul row add al, col mov di, ax mov ax, 32 add col, 5 mul row add al, col mov si, ax mov dx, [bx+si] xchg dx, [bx+di] xchg [bx+si], dx sub col, 5 jmp game rightArrow: xor si, si xor di, di lea bx, a mov ax, 32 add col, 5 mul row add al, col mov di, ax mov ax, 32 sub col, 5 mul row add al, col mov si, ax mov dx, [bx+si] xchg dx, [bx+di] xchg [bx+si], dx add col, 5 jmp game initConfig: ;put the cursor at 00 mov col, 27 mov row, 5 ;gets strlen of prompt and stores it in BX lea si, PROMPT xor bx, bx call getStrlen ;display prompt lea si, PROMPT mov cx, bx mov ah, 2 mov di, 5a0h call loadAndDisplayStr ret END MAIN The way I see it is there are 2 ways of doing this. One way would be to create an empty array, and every time the user makes a move (up/down/left/right) I can push this to a stack, and then when the user hits 'n' for new game, I just pop through that stack and reverse all the moves. Another alternative would be to create 2 identical boards (arrays/string) 'a' and 'b', and then the user would manipulate board 'a' till they decide to hit 'n' for a new game, and then I would some how set 'a' = 'b'
There's no magic way, you just have to copy the array like you would in C. I'd suggest having one master copy of the data that you keep clean / untouched, never ever writing into it. Allocate uninitialized space for the working game state somewhere, e.g. on the stack or in the BSS1. At the start of every game (including the first one), copy the preset whole array to the scratch space for the current game. (e.g. with rep movsb or rep movsw after setting CX, SI, and DI. ES and DS segment regs are already equal segment because of .model tiny. i.e. implement a memcpy however you like.) So you don't need to write the initializer data twice or anything like that, and only one copy of it needs to be in the file. And no you don't need any exchanging, just a block copy. Get the assembler to calculate the size of the whole thing by putting a label at the end, or put datasize = $ - a right after the end of a to get the size in bytes. Footnote 1: See #MichaelPetch's comment for details on how to declare a label in the .data? segment so you can use normal label/symbol syntax. Like gamestate datasize dup(?), where datasize is an = or equ constant you got the assembler to calculate earlier from the size of the preset. I think .data? is just space past the end of where DOS loads your .com file, and you can use space from there out to near the end of a 64k segment where the program-loader put your stack. (Unlike the .bss under a modern OS is not zeroed to start with. That's fine for this, you want to write the space you use before you read/modify it anyway.) #DavidWohlferd also suggests you could re-read part of the executable from disk, with DOS file open/read system calls. That could be the start of a save-game mechanism. In its simplest form, if the first n bytes of your program are all read-only (code and constant data) apart from this game-state array, you could read the first n bytes of the raw .com file into memory at ds:100h (or cs or es, it's all the same in a tiny memory model). Overwriting instructions with themselves (like a jmp rel16 over the data) is fine.
How to print an array in DOS x86 assembly?
I have this code to copy the array "NUMBERS" to "DEST" such that no number will repeat (in this case it should be : 1,2,5,4,7) The code works but now I need to print the array "DEST". How can I do that ? data segment NUMBERS db 1,2,1,1,1,5,5,4,7,7 DEST dt ? data ends code segment assume ds:data, cs:code start: mov ax, data mov ds, ax mov ax, 0a0ah mov di, offset NUMBERS mov bx, 0h loop2:mov cl, [di] mov si, offset DEST mov ch, [si] loop1:cmp ch, cl je dontadd inc si mov ch, [si] dec ah jnz loop1 mov si, offset DEST add si, bx inc bx mov [si], cl dontadd:mov ah, 0ah inc di dec al jnz loop2 mov ah, 4ch int 21h code ends end start
You can use INT 21h, AH=02h to print a single character to STDOUT. MOV CX,10 MOV SI,OFFSET DEST print: MOV DL,[si] OR DL,DL JE done ADD DL,'0' ; <-- Convert numeric value in DL into ASCII code MOV AH,02h INT 21h MOV DL,' ' ; Throw in a space to make things pretty INT 21h INC SI LOOP print done: If elements in NUMBERS have values over 9 then you need more elaborate conversion of the numeric values into ASCII.
First convert numbers to string then print them.You can use this two macros for printing numbers: printstr macro str push ax push dx lea dx,str mov ah,9 int 21h pop dx pop cx endm printnum macro n local o,w,s,n5,lb1,lb2,lb3 pusha push si push di jmp w s db 7 dup('$') w: mov si,0 mov cx,7 o:mov s[si],'$' inc si loop o mov si,0 xor ax,ax mov ax,n xor dx,dx cmp ax,0 jge n5 mov bl,'-' mov s[si],bl inc si neg ax n5:mov cx,10 div cx or dl,30h mov s[si],dl xor dx,dx inc si cmp ax,0 jne n5 mov si,0 cmp s[si],'-' jne lb1 inc si lb1:mov di,si lb3:cmp s[si],'$' je lb2 mov al,s[si] push ax inc si jmp lb3 lb2:pop ax mov s[di],al inc di cmp di,si jl lb2 printstr s pop di pop si popa endm