Checking if two tiles are touching and are adjacent in NASM Assembly - algorithm

Suppose that I have a 2D array, and I want to check whether one slot is adjacent and touching with another.
Suppose that the coordinates are in the 4-byte variables: OneX, OneY, TwoX, TwoY.
The solution I had for a while was that if you have the differences OneX - OneY and TwoX - TwoY and add them, if the result is either 1 or -1, then yes, the slots are adjacent and touching.
mov EBX,[oneX]
sub EBX,[oneY]
mov ECX,[twoX]
sub ECX,[twoY]
add EBX,ECX
; Compare EBX with 1 or -1.......
This almost works. But no - given a format (x,y), take: (3,3) and (0,1). They're clearly not adjacent nor touching, but the function will say they are.
The question at Get adjacent elements in a two-dimensional array? is somewhat useful, but it focuses on finding all adjacent matches, whereas I want to check for two specific slots instead.
The structure of my array is like this:
map: dd 'a','b','c','d' ; Double words just to make my life easier
Which is interpreted like
a b
c d
It's a square map.

There is no reason to Add them! And you are also substracting incorrect variables :).
You have to have two conditions OneX - TwoX and OneY - TwoY : both has to be 1, 0 or -1.
For example One is [4,5] and Two is [5,5] >= OneX - TwoX = -1 and OneY - TwoY = 0 => it is adjanced tile.
EDIT : For non-diagonal, there are two approaches :
a)One of condition must be 0 and the other one must be 1 or -1
b)Adding absolute value of OneX - TwoX and absolute value of OneY - TwoY must be 1

Here is some practical code, based on #libik answer:
Optimized for speed:
; eax = OneX-TwoX; ecx = OneY-TwoY
mov eax, [OneX]
mov ecx, [OneY]
sub eax, [TwoX]
sub ecx, [TwoY]
; eax = abs(eax); ecx=abs(ecx)
mov ebx, eax
mov edx, ecx
sar ebx, 31
sar edx, 31
xor eax, ebx
xor ecx, edx
sub eax, ebx
sub ecx, edx
; eax=abs(delta1)+abs(delta2); if eax = 1, jump to where needed
add eax, ecx
dec eax
lz .adjacent
Optimized for size:
; eax = abs(OneX-TwoX); ecx = abs(OneY-TwoY)
mov eax, [OneX]
mov ecx, [OneY]
sub eax, [TwoX]
jns #f
neg eax
##:
sub ecx, [TwoY]
jns #f
neg ecx
##:
; eax=abs(delta1)+abs(delta2); if eax = 1, jump to where needed
add eax, ecx
dec eax
lz .adjacent
Including diagonal cases
Replace add eax, ecx with or eax, ecx

Related

segmentation fault in x86 trying to do bubble sort

I am trying to implement bubble sort in assembly. Here is my code. I keep getting segmentation fault. I have a function down below. I have been trying to figure this out but I couldn't find a compiler for x86 and I have been checking with my code to check what is wrong but to no avail.
here is my function code:
bubble:
push ebp
mov ebp, esp
push ecx
push edx
push edi
push esi
push ebx
push eax
mov eax, 0
mov ecx, [ebp+12] ; number of elements in the array
mov edx, [ebp+8]; address of array
mov edi, 0
mov esi, 0
dec ecx; n - 1
mov esi, 1
sortOuter:
cmp esi, 0
jg sort
sort:
mov esi, 0 ;count
check:
cmp edi, ecx ; i < n - 1
jl sortInner
sortInner:
mov ebx, [edx+edi*4] ; mov array[i+1] to ebx
cmp [edx], ebx ; cmp array[i] to array[i+1]
jle noswap
swap:
mov eax, ebx ; mov array[i+1] to eax
mov ebx, [edx] ; mov array[i] to array[i+1]
mov [edx], eax ; mov array[i+1] to array[i]
inc esi ; count++
noswap:
inc edi ; i++
jmp check
jmp sortOuter
done:
call print_nl
pop ebx
pop esi
pop edi
pop edx
pop ecx
mov esp, ebp
pop ebp
ret
The segmentation error comes from the infinite loop that you have created with
check:
cmp edi, ecx ; i < n - 1
jl sortInner
sortInner:
If EDI is less than ECX you jump to sortInner, but if it isn't you fall-through into sortInner. No matter, you always end up running the code at sortInner and because the memory addresses that the code uses keep growing, at some point you will be trying to read memory that you don't have access to, hence the segmentation error.
Now if you were to correct this, then there's a second infinite loop waiting.
sortOuter:
cmp esi, 0
jg sort
sort:
Other errors include:
Resetting ESI instead of EDI at the start of the inner loop
Not swapping elements at all but always writing the smallest value in the first array element
Forgetting to restore the register EAX
This is a working BubbleSort. Don't just copy it, but find out how it functions!
In an array with N elements we have to do N-1 comparisons at most (to have the greatest value bubble towards the rear).
Because the InnerLoop uses a counter that gets initialized from the ever decreasing OuterLoop counter, with each iteration of the OuterLoop the portion of the array that is processed in the InnerLoop gets smaller. The portion of the array that we then no longer process contains the greatest elements that have bubbled towards the end of the array, hence the name BubbleSort.
Provisions have been made for an empty array or an array that has but 1 element. Always include some code for the special cases!
bubble:
push ebp
mov ebp, esp
push ...
mov ecx, [ebp + 12] ; Number of elements in the array
sub ecx, 1 ; First time we do n = N-1
jbe Done ; Array is empty or has but 1 element
OuterLoop:
mov edx, ecx ; Current value of the OuterLoop counter (n)
mov esi, [ebp + 8] ; Address of array
InnerLoop:
mov eax, [esi]
mov ebx, [esi + 4]
cmp eax, ebx
jng NoSwap
mov [esi], ebx
mov [esi + 4], eax
NoSwap:
add esi, 4
dec edx
jnz InnerLoop
dec ecx ; Next times we do n = n-1
jnz OuterLoop
Done:
pop ...
pop ebp
ret

find all paths from top left corner to right bottom corner assembly

I am new to assembly programming, currently taking online course.
Original problem was to count number of paths from top left corner to bottom right corner. But I found a good solution to that here:
https://www.geeksforgeeks.org/count-possible-paths-top-left-bottom-right-nxm-matrix/
Based on the combinatorics solution I should be able to find all paths in a binary manner.
First question, do you know a faster way to count paths?
Searched for the solution to print all paths in:
https://www.geeksforgeeks.org/print-all-possible-paths-from-top-left-to-bottom-right-of-a-mxn-matrix/
But did not notice any using the binary approach with seemed adequate for assembly.
Searching a bit more online I found:
https://www.baeldung.com/cs/generate-k-combinations
Revolving door algorithm was well detailed, and I calculate it to be O (number of combinations) * O (width or height of matrix (for printing) -1) * O (branching loops) on time complexity and O (width or height + 1) on space. Second question is this a correct assumption? If not, what is the correct complexity? Is it faster than the other solutions posted for finding all paths to this problem? Those are stated to be O(2^(width*height))
Third question: Who wrote this algorithm? Where can I find more like it?
And lastly, I will post my newbie 32-bit assembly pasta code for fasm, should work on matrixes larger than 3 x 3 smaller than 32 x 32(not recommended to go above 16 x 16 that is already a lot of combinations and only omitting the print instructions), any improvements are more than welcome. Thank you.
format PE console
entry start
include 'win32a.inc'
; ===============================================
struct MAT
h db ? ; X coordinate.
w db ? ; Y coordinate.
ends
; ===============================================
section '.bss' readable writeable
; Declare the uninitialized table in memory:
path_matrix MAT ?
count dd ?
indices db path_matrix.w - 1 dup ?
end_indices:
; ===============================================
section '.text' code readable executable
start:
call read_hex
mov [path_matrix.h], al ; down will be 0
call read_hex
mov [path_matrix.w], al ; right will be 1
dec eax
mov ecx, eax
initialize:
mov ebx, ecx
dec ebx
mov byte[indices+ecx], bl
loop initialize
movzx ebx, [path_matrix.h]
dec ebx
add ebx, eax
mov byte[indices+eax+1], bl
mov eax, ebx
print_combination:
inc [count]
movzx ebx, [end_indices - indices]
dec ebx
xor eax, eax
print_loop:
xor esi, esi
inc esi
mov cl, byte[indices + ebx ]
shl esi, cl
xor eax, esi
dec ebx
cmp ebx, 0
jnz print_loop
call print_eax_binary
branch:
lea edi, [indices +1]
movzx eax, [path_matrix.w] ; check if withd is eaven, if true matrix is odd (w -1)
shr eax, 1
jnc odd
eaven:
movzx eax, byte[edi]
cmp eax, 0
jle eaven_indice
dec eax
mov byte[edi], al
jmp print_combination
eaven_indice:
inc edi
try_to_increase:
movzx ebx, byte[edi]
inc ebx
cmp bl, [edi+1]
jl increase
lea ecx, [edi-indices+1]
cmp cl, [path_matrix.w]
jl increase_indice
jmp fin
increase:
mov byte[edi], bl
dec ebx
mov byte[edi-1], bl
jmp print_combination
odd:
movzx eax, byte[edi]
inc eax
cmp al, [edi+1]
jge increase_indice
mov byte[edi], al
jmp print_combination
increase_indice:
inc edi
try_decrease:
lea eax, [edi - indices]
cmp byte[edi], al
jl eaven_indice
decrease:
movzx ebx, byte[edi-1]
mov byte[edi], bl
sub eax, 2
mov byte[edi-1], al
jmp print_combination
fin:
mov eax, [count]
call print_eax
; Exit the process:
push 0
call [ExitProcess]
include 'training.inc'
The solution is not binary because paths from the top or left can overlap - creating duplicates. Working backward the solution is additive - sum of paths from left and paths from top.
Which leads to a simple solution:
_m = 16
_n = 16
ddp rq _m
; initialize first position
mov [ddp + (_n-1)*8], 1
mov ecx, _m
outer:
push rcx
mov ecx, _n
xor eax, eax
inner:
add rax, [ddp + (rcx-1)*8]
mov [ddp + (rcx-1)*8], rax
loop inner
pop rcx
loop outer
There is a closed form solution, but it's a little tricky to reduce the expression in such a way as to cover a large number of inputs:
; number of paths from one corner to opposite diagonal corner of M x N matrix
; RCX : N, RDX : M
numberOfPaths:
mov eax,1
mov r9,1
lea r8,[rcx+rdx-1]
jmp .try
.more:
mul rcx
inc ecx
div r9
inc r9
.try:
cmp rcx,r8
jc .more
retn
It can be reduced further with more code.

How to echo memory location use NASM [duplicate]

I am looking for a way to print an integer in assembler (the compiler I am using is NASM on Linux), however, after doing some research, I have not been able to find a truly viable solution. I was able to find a description for a basic algorithm to serve this purpose, and based on that I developed this code:
global _start
section .bss
digit: resb 16
count: resb 16
i: resb 16
section .data
section .text
_start:
mov dword[i], 108eh ; i = 4238
mov dword[count], 1
L01:
mov eax, dword[i]
cdq
mov ecx, 0Ah
div ecx
mov dword[digit], edx
add dword[digit], 30h ; add 48 to digit to make it an ASCII char
call write_digit
inc dword[count]
mov eax, dword[i]
cdq
mov ecx, 0Ah
div ecx
mov dword[i], eax
cmp dword[i], 0Ah
jg L01
add dword[i], 48 ; add 48 to i to make it an ASCII char
mov eax, 4 ; system call #4 = sys_write
mov ebx, 1 ; file descriptor 1 = stdout
mov ecx, i ; store *address* of i into ecx
mov edx, 16 ; byte size of 16
int 80h
jmp exit
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
write_digit:
mov eax, 4 ; system call #4 = sys_write
mov ebx, 1 ; file descriptor 1 = stdout
mov ecx, digit ; store *address* of digit into ecx
mov edx, 16 ; byte size of 16
int 80h
ret
C# version of what I want to achieve (for clarity):
static string int2string(int i)
{
Stack<char> stack = new Stack<char>();
string s = "";
do
{
stack.Push((char)((i % 10) + 48));
i = i / 10;
} while (i > 10);
stack.Push((char)(i + 48));
foreach (char c in stack)
{
s += c;
}
return s;
}
The issue is that it outputs the characters in reverse, so for 4238, the output is 8324. At first, I thought that I could use the x86 stack to solve this problem, push the digits in, and pop them out and print them at the end, however when I tried implementing that feature, it flopped and I could no longer get an output.
As a result, I am a little bit perplexed about how I can implement a stack in to this algorithm in order to accomplish my goal, aka printing an integer. I would also be interested in a simpler/better solution if one is available (as it's one of my first assembler programs).
One approach is to use recursion. In this case you divide the number by 10 (getting a quotient and a remainder) and then call yourself with the quotient as the number to display; and then display the digit corresponding to the remainder.
An example of this would be:
;Input
; eax = number to display
section .data
const10: dd 10
section .text
printNumber:
push eax
push edx
xor edx,edx ;edx:eax = number
div dword [const10] ;eax = quotient, edx = remainder
test eax,eax ;Is quotient zero?
je .l1 ; yes, don't display it
call printNumber ;Display the quotient
.l1:
lea eax,[edx+'0']
call printCharacter ;Display the remainder
pop edx
pop eax
ret
Another approach is to avoid recursion by changing the divisor. An example of this would be:
;Input
; eax = number to display
section .data
divisorTable:
dd 1000000000
dd 100000000
dd 10000000
dd 1000000
dd 100000
dd 10000
dd 1000
dd 100
dd 10
dd 1
dd 0
section .text
printNumber:
push eax
push ebx
push edx
mov ebx,divisorTable
.nextDigit:
xor edx,edx ;edx:eax = number
div dword [ebx] ;eax = quotient, edx = remainder
add eax,'0'
call printCharacter ;Display the quotient
mov eax,edx ;eax = remainder
add ebx,4 ;ebx = address of next divisor
cmp dword [ebx],0 ;Have all divisors been done?
jne .nextDigit
pop edx
pop ebx
pop eax
ret
This example doesn't suppress leading zeros, but that would be easy to add.
I think that maybe implementing a stack is not the best way to do this (and I really think you could figure out how to do that, saying as how pop is just a mov and a decrement of sp, so you can really set up a stack anywhere you like by just allocating memory for it and setting one of your registers as your new 'stack pointer').
I think this code could be made clearer and more modular if you actually allocated memory for a c-style null delimited string, then create a function to convert the int to string, by the same algorithm you use, then pass the result to another function capable of printing those strings. It will avoid some of the spaghetti code syndrome you are suffering from, and fix your problem to boot. If you want me to demonstrate, just ask, but if you wrote the thing above, I think you can figure out how with the more split up process.
; Input
; EAX = pointer to the int to convert
; EDI = address of the result
; Output:
; None
int_to_string:
xor ebx, ebx ; clear the ebx, I will use as counter for stack pushes
.push_chars:
xor edx, edx ; clear edx
mov ecx, 10 ; ecx is divisor, devide by 10
div ecx ; devide edx by ecx, result in eax remainder in edx
add edx, 0x30 ; add 0x30 to edx convert int => ascii
push edx ; push result to stack
inc ebx ; increment my stack push counter
test eax, eax ; is eax 0?
jnz .push_chars ; if eax not 0 repeat
.pop_chars:
pop eax ; pop result from stack into eax
stosb ; store contents of eax in at the address of num which is in EDI
dec ebx ; decrement my stack push counter
cmp ebx, 0 ; check if stack push counter is 0
jg .pop_chars ; not 0 repeat
mov eax, 0x0a
stosb ; add line feed
ret ; return to main
; eax = number to stringify/output
; edi = location of buffer
intToString:
push edx
push ecx
push edi
push ebp
mov ebp, esp
mov ecx, 10
.pushDigits:
xor edx, edx ; zero-extend eax
div ecx ; divide by 10; now edx = next digit
add edx, 30h ; decimal value + 30h => ascii digit
push edx ; push the whole dword, cause that's how x86 rolls
test eax, eax ; leading zeros suck
jnz .pushDigits
.popDigits:
pop eax
stosb ; don't write the whole dword, just the low byte
cmp esp, ebp ; if esp==ebp, we've popped all the digits
jne .popDigits
xor eax, eax ; add trailing nul
stosb
mov eax, edi
pop ebp
pop edi
pop ecx
pop edx
sub eax, edi ; return number of bytes written
ret

Flipping the first pixel in an image in asm

Hi I am just doing this for practice before I create a loop that can flip an 3x3 image horizontally or vertically. I am using a variable called ap to store the addresses of the first pixel. I would also like to eventually use another variable called amp to store the mirrored pixel address, and also a register to store the calculated offset of the pixels but for now I put it in manually. No matter what I do the program doesn't swap them. Does anyone have an idea of what is the issue? Thank you for reading.
mov ecx, dword ptr[eax + ecx * 4]
mov ap, ecx //temporary pixel address storage
mov ecx, 0
mov ecx, dword ptr[eax + ecx * 4 + 8] //offset by 8 pixels
mov [ap], ecx
I am using a variable called ap to store the addresses of the first pixel
If the ap variable is suppossed to contain an addresss than you need to use the lea instruction (not the mov instruction).
; For the 1st line EAX is address of image = address of 1st pixel
mov ecx, 0 ;Index to 1st pixel
lea ecx, dword ptr[eax + ecx * 4] ;Address of 1st pixel
mov [ap], ecx
mov ecx, 2 ;Index to 3rd pixel
lea ecx, dword ptr[eax + ecx * 4] ;Address of 3rd pixel
mov [amp], ecx
Now to swap these pixels and thus flipping the image you can write:
mov ecx, [ap]
mov edx, [amp]
mov [ap], edx
mov [amp], ecx
To proces the next lines of the image you could each time add the number of bytes per scanline to the EAX register. For an 3x3 image that's probably 12.
I don't get what this suppose to do:
mov ecx, dword ptr[eax + ecx * 4]
whats in ecx? is it a counter for offset? but you are overriding it each time...
If you'r trying to save the original bit i think that you need to make sure you got the right value in ecx. try
mov ecx, 0
first (you can also xor ecx, ecx it gets the job done and its easier to read)

Insertion sort in Assembly

So I'm coding out an insertion sort (in assembly) based on this high level code:
void insertionSort(int data[ ], int arraySize) {
int insert;
int moveItem;
for(int next=1; next<arraySize; next++) {
insert=data[next]; //store the value in the current element
moveItem=next; //initialize location to place element
while((moveItem>0)&&(data[moveItem-1]>insert)) {
//shift element one slot to the right
data[moveItem]=data[moveItem-1];
moveItem--;
} //end while
data[moveItem]=insert;
} //end for
} //end insertionSort
There are exactly 20 random numbers in an array called myArray. I cannot use an of the decision derivatives that come in the library that comes with our book. So basically movs, cmps, loops, and jumps
Here's what I got. I had it sorting the first of 20 random numbers earlier, but I've confused myself to death and have no idea what I'm doing any more. It crashes when it gets to the insertion sort method. Help please.
TITLE Insertion Sort (main.asm)
INCLUDE Irvine32.inc
.data
elems = 20
myArray sdword elems dup(0)
str1 byte "Press enter" ,0
str2 byte "The array now is ",0
next sdword 1
start sdword ?
.code
main PROC
call Clrscr
call CreateRandom
call Display
call InsertionSort
call Display
exit
main ENDP
CreateRandom PROC
;;;;Creates 20 random numbers and populates myArray;;;;;
call Randomize
mov ecx, 20
mov edx, OFFSET myArray
L1:
call Random32 ;create random number
mov [edx], eax ; move random number to the appropriate spot in the array
add edx, 4 ; increase the address of what it is pointing to
loop L1
mov edx, OFFSET str1 ; "press enter to continue"
call WriteString
call ReadInt
call Crlf
ret
CreateRandom ENDP
Display PROC
;;;; Displays current form of the array myArray;;;;;
mov edx, OFFSET str2 ; "The array now is:"
call WriteString ; write string
call Crlf
mov esi, OFFSET myArray ; offset of the array
mov ecx, 20 ; index of the loop
L2:
mov eax, [esi] ; move array at that point to eax
call WriteDec ; print out the array as a decimal
call Crlf ; next line
add esi, 4 ; next element in the array
loop L2
call Crlf
ret
Display ENDP
InsertionSort PROC
mov ecx, 19
mov edx, OFFSET myArray
mov ebx, OFFSET myArray ; eax=next
add ebx, 4 ;moves up the array to second element comparable to next
outterloop:
mov esi, [ebx] ; esi=data[next]
mov eax, ebx ;movelterm=ebx
L1:
mov edx, [eax-4] ;move the number that is greater into edx
mov [eax], edx ;move the number into that 2nd element of the
sub eax, 4
mov esi, [eax]
cmp eax, [edx]
JNG endinner ; if the address is not greater than the first address, skip to the end
mov edx, [eax-4]
cmp edx, esi ; if the address is greater, than it already sorted, skip to end
JG endinner
loop L1
endinner:
mov [eax], esi ; move first to the second to finish the sort
add ebx, 4 ;move to the next element of the array
inc next ;counting outside loop
cmp ecx, next
JNE outterloop ;return to top of for loop
ret
InsertionSort ENDP
END main
I haven't examined your code in detail, but I notice that InsertionSort seems to be using edx for two different purposes at once: as a pointer into the array, and to hold one of the values from the array. This will certainly break even if nothing else is wrong.
So, at the start of InsertionSort you say mov edx, OFFSET myArray -- it's a pointer into the array. Then, a few lines later, mov edx, [eax-4] -- oops, no, it's a value from the array. And a few lines later again, cmp eax, [edx] -- oh, no, now it's a pointer into the array again.
Perhaps that last instruction should be cmp edx, [eax] or something? Because eax does seem to be a pointer into the array here.

Resources