vaska11
vaska11

Reputation: 380

Drawing a diamond of numbers in a 2d array Java

I've been solving some coding questions to get myself prepared for a coding interview, and found out a question that seemed kind of puzzling. I solved the question after spending some time on it; however, the code looks hardcoded and has no style. So, I was wondering if I could get some feedbacks on styling the code, or perhaps getting an better idea of approaching the problem.

The question basically asks you to draw a diamond of numbers with a pattern in 2d array. It gives a coordinate of 'x' and range of x. From the x, the numbers spread one by one until the range. So, there are 4 different inputs, N (the size of an array), X, Y (the coordinate of 'x' as (rows, cols)), and R (range).

If they were given a size of 8, coordinate of (4,5) with a range of 3, the result would be like,

0 0 0 0 3 0 0 0
0 0 0 3 2 3 0 0
0 0 3 2 1 2 3 0
0 3 2 1 x 1 2 3
0 0 3 2 1 2 3 0
0 0 0 3 2 3 0 0
0 0 0 0 3 0 0 0
0 0 0 0 0 0 0 0

And the below is what I have,

    int n = sc.nextInt();
    char[][] arr = new char[n][n];
    int r = sc.nextInt() - 1;
    int c = sc.nextInt() - 1;
    int range = sc.nextInt();

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            arr[i][j] = '0';
        }
    }

    arr[r][c] = 'x';


    int num = 1;
    for (int i = 0; i < range; i++) {
        //Cross
        if (c-num > -1) {
            arr[r][c - num] = (char) (num + '0');
        }
        if (c+num < n) {
            arr[r][c + num] = (char) (num + '0');
        }
        if (r-num > -1) {
            arr[r - num][c] = (char) (num + '0');
        }
        if (r+num < n) {
            arr[r + num][c] = (char) (num + '0');
        }
        //Diagonal
        if (i > 0) {
            int sum = num - 1, delta = 1;

            while (sum != 0) {
                if (r-sum > -1 && c+delta < n) {
                    arr[r - sum][c + delta] = (char) (num + '0');
                }
                sum--;
                delta++;
            }
            sum = num - 1; delta = 1;
            while (sum != 0) {
                if (r+sum < n && c-delta > -1) {
                    arr[r + sum][c - delta] = (char) (num + '0');
                }
                sum--;
                delta++;
            }
            sum = num - 1; delta = 1;
            while (sum != 0) {
                if (r-sum > -1 && c-delta > -1) {
                    arr[r - sum][c - delta] = (char) (num + '0');
                }
                sum--;
                delta++;
            }
            sum = num - 1; delta = 1;
            while (sum != 0) {
                if (r+sum < n && c+delta > -1) {
                    arr[r + sum][c + delta] = (char) (num + '0');
                }
                sum--;
                delta++;
            }
        }
        num++;
    }

I could not figure out any other way to take care of the diagonal numbers other than using four different while-loops. I would appreciate any kind of feedback. Thanks in advance!

Upvotes: 3

Views: 2552

Answers (3)

RaffleBuffle
RaffleBuffle

Reputation: 5455

Here's a fairly compact method. On each iteration i we fill a single-character wide i+1 by i+1 diamond-shaped ring, centered on (row, col), with value i. To avoid filling the interior of the diamond we check that the manhattan distance to (row, col) is equal to i - this is only true for cells on the boundary of the diamond.

static char[][] buildDiamond(int n, int row, int col, int range)
{
  char[][] arr = new char[n][n];
  for(char[] a : arr) Arrays.fill(a, '0');
  arr[row][col] = 'x';

  for(int i=1; i<=range; i++)
    for(int j=0; j<=i; j++)
      for(int k=0; k<=i; k++)
        if(Math.abs(k-j) + Math.abs(k+j-i) == i)
          arr[row+k-j][col+k+j-i] += i;

  return arr;
}

Test:

public static void main(String[] args)
{
  for(char[] a : buildDiamond(7, 3, 3, 3)) 
    System.out.println(new String(a).replaceAll(".", "$0 "));
}

Output:

0 0 0 3 0 0 0 
0 0 3 2 3 0 0 
0 3 2 1 2 3 0 
3 2 1 x 1 2 3 
0 3 2 1 2 3 0 
0 0 3 2 3 0 0 
0 0 0 3 0 0 0 

Upvotes: 1

Robby Cornelissen
Robby Cornelissen

Reputation: 97130

You can just loop over the array once, and set the values based on the relative distance of the current location (i, j) to the fixed coordinate (x, j).

Your code could look like this:

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        // variables
        int n = 8;
        int x = 4 - 1; // coordinates are one-based
        int y = 5 - 1; // coordinates are one-based
        int r = 3;
        char[][] array = new char[n][n];

        // logic
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int dist = Math.abs(x - i) + Math.abs(y - j); // calculate distance

                if(dist == 0) {         // at x,y
                    array[i][j] = 'x';
                } else if (dist <= r) { // distance to x,y is within range
                    array[i][j] = (char) (dist + '0');
                } else {                // distance to x,y is outside of range
                    array[i][j] = '0';
                }
            }
        }

        // dump output
        System.out.println(Arrays.deepToString(array)
                           .replace("], ", "]\n")
                           .replace("[", "")
                           .replace("]", "")
                           .replace(", ", " "));
    }
}

Which yields the following output:

0 0 0 0 3 0 0 0
0 0 0 3 2 3 0 0
0 0 3 2 1 2 3 0
0 3 2 1 x 1 2 3
0 0 3 2 1 2 3 0
0 0 0 3 2 3 0 0
0 0 0 0 3 0 0 0
0 0 0 0 0 0 0 0

If you want to be even more concise, you can replace the branched if… else if… else statement with ternary operators:

array[i][j] = dist == 0 ? 'x' : dist <= r ? (char) (dist + '0') : '0';

Upvotes: 1

akmin04
akmin04

Reputation: 697

You can try using floodfill, although depending on your level it might be a bit far.

https://en.wikipedia.org/wiki/Flood_fill

EDIT: Robby Cornelissen's code looks much cleaner and simpler than mine so you should probably check out his. However, floodfill is a pretty important concept for later on so might as well check it out.

The article is pretty long, but the GIF in the article is the most important part.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class test {

    public static void main(String[] args) throws IOException {
        //Get inputs (I used BufferedReader, Scanner works fine as well)
        //My inputs are formatted as 'N X Y R' (ex. '8 4 5 3')
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        int N = Integer.parseInt(st.nextToken());
        int R = Integer.parseInt(st.nextToken()) - 1;
        int C = Integer.parseInt(st.nextToken()) - 1;
        int range = Integer.parseInt(st.nextToken());
        char[][] arr = new char[N][N];

        //Make everything in array '0'
        for (int i = 0; i < N; i++) {
            Arrays.fill(arr[i], '0');
        }

        //Floodfill using BFS
        //FYI: this BFS is iterative, not recursive
        Queue<int[]> q = new LinkedList<>();
        q.add(new int[]{0, R, C});
        while (!q.isEmpty()) {
            int[] current = q.remove();
            if (arr[current[1]][current[2]] == '0' && current[0] <= range) {
                arr[current[1]][current[2]] = (current[0]+"").charAt(0);
                if(current[1]+1 < N) q.add(new int[]{current[0]+1, current[1]+1, current[2]});
                if(current[1]-1>= 0) q.add(new int[]{current[0]+1, current[1]-1, current[2]});
                if(current[2]+1 < N) q.add(new int[]{current[0]+1, current[1], current[2]+1});
                if(current[2]-1>= 0) q.add(new int[]{current[0]+1, current[1], current[2]-1});
            }
        }
        arr[R][C] = 'x';

        //Print out the final grid
        for (int i = 0; i < N; i++) {
            for (int j = 0; j< N; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}

Upvotes: 0

Related Questions