1

How to write an algorithm to find all diagonal point of a given point?

Such as:

00 01 02 03 04 05
10 11 12 13 14 15
20 21 22 23 24 25
30 31 32 33 34 35
40 41 42 43 44 45
50 51 52 53 54 55

When selected a point 34, how do I find the neighboring diagonal points? (01,12,23,45,25,43,52)

00(01)02 03 04 05
10 11(12)13 14 15
20 21 22(23)24(25)
30 31 32 33  X 35
40 41 42(43)44(45)
50 51(52)53 54 55

Since I'm not stating the programming language I use, I would more prefer pseudocode or instructions.

Ps: I don't want direct code giveaway as I'm trying to learn to code by following pseudocode or instructions.

6 Answers6

4

Let's say your point is on (a, b). A given (c, d) point is on the same diagonal if exists an i integer, so that

a + i = c and b + i = d or a + i = c and b - i = d

since the distance is i, you can do the following:

for i <- 0, n - 1
    if i <> a then
        if (b - i) >= 0 and (b - i) < n then (i, b - i) is on the diagonal
        if (b + i) >= 0 and (b + i) < n then (i, b + i) is on the diagonal
    end if
end for
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • For some reasons more condition checking is "expensive" to use, it would be best if we only have fewer conditions, and have a equation that works on all condition, but also error free. More info about why IF is "expensive", check on the selected answer for this question [link](https://stackoverflow.com/questions/315306/is-if-expensive) – Hashashihn Altheim Aug 26 '17 at 21:51
  • @HashashihnAltheim beware from premature optimizations. First make sure you have an algorithm that works, analyze it and THEN determine whether you need an optimization at all. You will need at least two ifs to work with the two lines going through your point. You can, of course include i <> a into your ifs, but that will be less clear. Not to mention the fact that we speak about algorithms, ways to proceed, we are not speaking against coding details, since you have asked for an algorithm. – Lajos Arpad Aug 27 '17 at 07:26
  • @HashashihnAltheim since you want to learn how to code I will give you two advices. 1. When you ask for help and you get the thing you asked for, do not criticize the help in terms you did not ask for. 2. If you are to become a successful programmer, then there is a high chance that you will work in a team. Clarity of code is at least as important as minuscule performance differences. When there is a performance deficit that matters you will need to optimize. But before coding or even understanding the algorithm you are not yet able to determine its future performance. – Lajos Arpad Aug 27 '17 at 07:28
  • oh I just noticed your answer to be in one cycle rather than two, I'm still learning to code, but more importantly to document how I code it too for my teammates to reference on it. I used to ask for code directly in the past but I figured out learning the flow is more crucial than learning the hard code way. Performance did matter for me as I am coding for an algorithm to deal with long term problem, imagine the N might goes up to 1000+. Your answer did helped me a lot to understand better. THANK! – Hashashihn Altheim Aug 28 '17 at 14:57
  • @HashashihnAltheim you are welcome. 1000 is not a big input yet. If there are 1000+ rows, that means you have 1000 steps. This algorithm should not even be felt with that size of input. In our case, large inputs start with 100 000+ rows, however, in that case the data structure you use becomes a crucial problem. Performance always matter though and it is a good thing to write performant code, but in most cases you will not know in advance what will cause slowness. You can go ahead and do some stress tests to see what is the bottleneck. – Lajos Arpad Aug 29 '17 at 07:08
  • @HashashihnAltheim my algorithm is extremely simple and, as you have mentioned it as well, it has a linear complexity of O(n). The number of ifs is a minuscule question when it comes to performance. The most important question is complexity. I would prefer to keep i <> a separately though, as the code will be understandable then and the minuscule possible performance deficit will not really matter. In the unprobable case that this will be the bottleneck I can go back to the code and optimize it, but then I will have a reproducible case of underperformance. – Lajos Arpad Aug 29 '17 at 07:11
  • 1
    I wrote an implementation for this in C# below https://stackoverflow.com/a/63219124/1566372 – Rady Aug 02 '20 at 17:30
2

Brute force solution

Write some simple for loop over the whole grid. Any points on the diagonal have a slope of one with the starting point

Assuming a zero indexed N x N box and x increases left to right and y increases top to bottom

values = list()
location = (3,4)

for y in 0 ..N-1:
    for x in 0..N-1:
        if (x, y) == location:
            continue 
        slope = abs(y-location(0))/abs(x-location(1))
        if slope == 1:
            list.add( (y, x) ) 

More optimal solution

Start from the location coordinate, then fan outwards, increasing and /or decreasing both of the x, y points at the same time. The tricky part of that method is to not break the loop when one direction hits a boundary

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • I think this if statement might be able to check for boundary if((x>=min_x) && (x<=max_x) && (y>=min_y) && (y<=max_y)) – Hashashihn Altheim Aug 26 '17 at 04:08
  • This solution will result in error if given point is (0,0) and it abs(0-0)/abs(0-0) which will return divide by zero error – Hashashihn Altheim Aug 26 '17 at 04:31
  • 1
    Obviously. You wanted pseudocode, not flawless execution – OneCricketeer Aug 26 '17 at 05:40
  • This approach seems to be unnecessarily complex – Lajos Arpad Aug 26 '17 at 14:44
  • @cricket_007 after some research on IF and branching decision, abs(), max() and min() function seems to be a great way to deal around with the "expensive" issue of IF checking process, which is used by you to have an equation that deal with all possible diagonal points. I'm open for a better answer and if there isn't any then yours will be marked as correct answer, THANKS~ – Hashashihn Altheim Aug 26 '17 at 21:56
  • 1
    You cannot avoid error or boundary checking. You need conditionals – OneCricketeer Aug 27 '17 at 02:24
  • @cricket_007 still a complexity of O(n^2) is unreasonably high. You can achieve the goal using a single cycle. – Lajos Arpad Aug 27 '17 at 08:24
  • @Lajos OP didn't ask for optimal solution – OneCricketeer Aug 27 '17 at 14:26
  • @cricket_007 that's true, but your solution is still unnecessarily overcomplicated. Take a look at mine, which is much simpler and is linear. I did not down-vote your answer, since it is still an answer (if we omit to look at the 0 ..N part, which is problematic in my opinion and should be changed to 0 ..N - 1) – Lajos Arpad Aug 28 '17 at 06:33
  • @LajosArpad I'm not disagreeing with you, nor do I think this should be edited or deleted. So, I don't know what you're suggesting. – OneCricketeer Aug 28 '17 at 06:44
  • 1
    @cricket_007 after the edit your answer seems to be correct. Otherwise I am not suggesting anything. I am just telling you and other readers that this answer is overc-omplicated and should not be recommended due to the fact that there are better alternatives. If we can agree on that, then there is no problem with your answer. – Lajos Arpad Aug 28 '17 at 06:51
2

I wrote an implementation for this accepted answer (https://stackoverflow.com/a/45896595/1566372) in C#

public IEnumerable<(int i, int j)> GetDiagonalPoints(int a, int b, int n)
        {
            /*
             for i <- 0, n - 1
                if i <> a then
                    dist = Abs(i - a)
                    if (b - dist) >= 0 and (b - dist) < n then (i, b - dist) is on the diagonal
                    if (b + dist) >= 0 and (b + dist) < n then (i, b + dist) is on the diagonal
                end if
            end for
             */
            for (int i = 0; i < n; i++)
            {
                if (i != a)
                {
                    var dist = Math.Abs(i - a);
                    if ((b - dist) >= 0 && (b - dist) < n) yield return (i, b - dist);
                    if ((b + dist) < n) yield return (i, b + dist);
                }
            }
        }
Rady
  • 918
  • 1
  • 11
  • 16
0

It's easier to me to write the code itself rather than a pseudocode...

N is the size of the zero-based matrix.

public static void diagonal(int N, int x, int y) {

    int max = Collections.max(Arrays.asList(x, y, N - x, N - y));
    for (int i = 1; i < max; i++) {
        addIfValid(N, x + i, y + i);
        addIfValid(N, x + i, y - i);
        addIfValid(N, x - i, y + i);
        addIfValid(N, x - i, y - i);
    }
}

private static void addIfValid(int N, int i, int j) {
    if (i >= 0 && i < N && j >= 0 && j < N) {
        // collect the results in a list or process them in any way
        System.out.println(i + ":" + j);
    }
}
Selindek
  • 3,269
  • 1
  • 18
  • 25
  • `public static void diagonal(int N, int M, Point location){ for(int i=0; i= 0) System.out.println(i+","+((y-Math.abs(x-i)))); if ((y+Math.abs(x-i)) < m) System.out.println(i+","+((y+Math.abs(x-i)))); } }` You might want to check this solution with bound checking in the loop too~ – Hashashihn Altheim Aug 28 '17 at 16:27
0

As guided by Lajos Arpad answer, I made some changes to suit my needs.

//point_given = (3,3)
//matrix = 5*4
/*
00 01 02 03
10 11 12 13
20 21 22 23
30 31 32 33
40 41 42 43
*/
x = 3 // x of given point
y = 3 // y of given point
N = 5 //row
M = 4 //col

//use row to iterate only
for i = 0 to N, i+1
    //no diagonal point on same row of given point
    if i <> x
        //to check if y in bound of matrix col for the left and right diagonal
        //used abs(x-i) to know how much value to add to y col
        //e.g. 1 row up of x means the diagonal point y is 1 col left and 1 col right to given y
        if((y-abs(x-i))>=0) then (i,y-abs(x-i)) is a diagonal point on left
        endif
        if((y+abs(x-i))<M) then (i,y+abs(x-i)) is a diagonal point on right
        endif
    endif
endfor
0

I wrote a Python solution based @Rady solution: https://stackoverflow.com/a/63219124/14726555

I also added code to draw diagonals of any size so it is easier to see why this solution works and how it is useful for generating diagonals.

def diag_iter(row, col, n):
    for i in range(n):
        if i != row:
            dist = abs(i - row)
            if 0 <= col - dist < n:
                yield (i, col - dist)
            if col + dist < n:
                yield (i, col + dist)

def print_diag(row, col, n):
    board = [['_'] * n for _ in range(n)]
    board[row][col] = 'X'
    for diag_row, diag_col in diag_iter(row, col, n):
        board[diag_row][diag_col] = "X"
    print(f"Board of size {n} with diagional starting at ({row}, {col})")
    for row in board:
        print(row)

print_diag(1, 1, 5)
print_diag(2, 2, 5)
print_diag(3, 4, 5)
print_diag(0, 3, 5)
"""
Board of size 5 with diagional starting at (1, 1)
['X', '_', 'X', '_', '_']
['_', 'X', '_', '_', '_']
['X', '_', 'X', '_', '_']
['_', '_', '_', 'X', '_']
['_', '_', '_', '_', 'X']
Board of size 5 with diagional starting at (2, 2)
['X', '_', '_', '_', 'X']
['_', 'X', '_', 'X', '_']
['_', '_', 'X', '_', '_']
['_', 'X', '_', 'X', '_']
['X', '_', '_', '_', 'X']
Board of size 5 with diagional starting at (3, 4)
['_', 'X', '_', '_', '_']
['_', '_', 'X', '_', '_']
['_', '_', '_', 'X', '_']
['_', '_', '_', '_', 'X']
['_', '_', '_', 'X', '_']
Board of size 5 with diagional starting at (0, 3)
['_', '_', '_', 'X', '_']
['_', '_', 'X', '_', 'X']
['_', 'X', '_', '_', '_']
['X', '_', '_', '_', '_']
['_', '_', '_', '_', '_']
"""
f0lie
  • 46
  • 4