Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have an assignment to code a method that will print values in a diamond pattern. For example, if the method is called like printNumberDiamond(2), then the results should look like:

"  0  "
" 010 "
"01210"
" 010 "
"  0  "

I have spent a ton of time on writing the code that does this, but I am sure that it's not the most efficient/clean way. I am hoping to learn new strategies for accomplishing this, because this was very difficult for me to complete, and I almost just gave up.. but I got it to work:

public static void printNumberDiamond(int diaCenter)
{   
        printNumberDiamondTop(diaCenter);
        printNumberDiamondBottom(diaCenter);
}


public static void printNumberDiamondTop(int diaCenter)
{
    int maxAscendingRows = diaCenter + 1;                       
    int maxColumnLength = diaCenter * 2 + 1;            
    int highestNbrForRow = 0;

    for(int row = 0, rowCtr=0;row<=diaCenter;row++)
    {   
        int thisColumnLength = 0;
        int thisColumnMaxLeftSpaces = 0;        

        if(row >= maxAscendingRows)
        {           
            thisColumnMaxLeftSpaces = (maxColumnLength - rowCtr) / 2;
            rowCtr--;           
        }
        else
        {
            thisColumnLength = maxColumnLength - row;   
            thisColumnMaxLeftSpaces = (thisColumnLength - row) / 2;
            rowCtr++;
        }

        int nbrWritten = 0;
        int nbrDescendingWritten = 0;           
        for(int col = 0;col < maxColumnLength;col++)            
        {
            if(col < thisColumnMaxLeftSpaces)           
            {
                System.out.print(" ");          
            }
            else if(nbrDescendingWritten == 0 && nbrWritten > row)  
            {
                System.out.print(" ");          
            }
            else if(nbrWritten <= highestNbrForRow)     
            {
                System.out.print(nbrWritten++);     
                nbrDescendingWritten = nbrWritten - 1;                  
            }           
            else if(nbrWritten > highestNbrForRow)
            {
                System.out.print(--nbrDescendingWritten);                   
            }                           
        }           
        ++highestNbrForRow;
        System.out.print("\n");
    }
}

public static void printNumberDiamondBottom(int diaCenter)
{               
    int maxColumnLength = diaCenter * 2 + 1;                        
    int highestNbrForRow = 0;                                       
    for(int row = diaCenter;row>0;row--)
    {               
        highestNbrForRow = row - 1;
        int thisColumnMaxLeftSpaces = (maxColumnLength - highestNbrForRow * 2) / 2;
        int nbrWritten = 0;
        int nbrDescendingWritten = 0;

        for(int col = 0;col < maxColumnLength;col++)            
        {
            if(col < thisColumnMaxLeftSpaces)           
            {
                System.out.print(" ");          
            }
            else if(nbrDescendingWritten == 0 && nbrWritten > highestNbrForRow) 
            {
                System.out.print(" ");          
            }
            else if(nbrWritten <= highestNbrForRow && nbrWritten >= 0)      
            {
                System.out.print(nbrWritten++);     
                nbrDescendingWritten = nbrWritten - 1;                  
            }           
            else if(nbrWritten > highestNbrForRow)
            {
                System.out.print(--nbrDescendingWritten);                   
            }                           
        }           
        ++highestNbrForRow;
        System.out.print("\n");
    }
share|improve this question
1  
Great question! While I'm refactoring it, I will give you a general hint: look at your two methods: printNumberDiamondTop and printNumberDiamondBottom and spot places where you have common code, then extract this common code fragments to a separate methods. This will shorten your code and make it more clear. – RK1 1 hour ago
5  
I've edited out the part where you ask reviewers to post alternative solutions; while reviewers may present better/alternative solutions, they don't have to. You will find that answerers on this site address any & all aspects of the code; sometimes the best answers don't even include a code block. Feel free to hop into The 2nd Monitor if you have any questions. – Mat's Mug 1 hour ago

Determine the number of lines to output (2*n + 1). then for each line:

  • determine how many leading spaces (m) and the highest digit t
  • print m spaces
  • print the integers from 0 through t
  • print the digits from t-1 down to zero
  • print a newline

Here's code that works for n=0..15

public static void printTriangle(int n ) {
  int lines = (2 * n) + 1;
  for (int i = 0; i < lines; i++) {
     int nsp;
     int top;
     if ( i <= n ) {
        nsp = n - i;
        top = i;
     } else {
        nsp = i - n;
        top = n - nsp;
     }
     // print out nsp spaces
     for (int j = 0; j < nsp; j++) {
        System.out.print( ' ' );
     }

     // print integers 0 through top
     for (int j = 0; j <= top; j++) {
        System.out.printf( "%x", j );
     }
     // ptint numbers from top-1 to zero
     for (int j = top - 1; j >= 0; j--) {
        System.out.printf( "%x", j );
     }
     System.out.println( "" );
  }
}
share|improve this answer

I would approach this a two step problem. Build the pattern, then print the pattern. When you try to build it as you print it, you are forced to think left-to-right and then top-to-bottom. Instead of being able to formulate an appropriate mathematical model.

Abhinav Pandey's answer is a good solution for the n <= 9 limit, but there are other models beyond that. You know that the resultant matrix will be 2n-1 by 2n-1, so allocate an array of that size and then fill it in by starting in the center and working your way out.

Printing it out is now a very direct nested loop.

share|improve this answer

The diamond is simmetric, so in pseudocode:

Print_diamond = do {print top; print center; print reverse(top)}

The center is easy to generate:

0.upto(n) + (n - 1).downto(0)

Then reduce it step by step by replacing the center 3 items with the center item minus one until you arrive to a single 0:

Example: 01210 
          010
121 becomes 010
010 becomes 0
Stop

The number of spaces is equal to the max line length - current line length, half before, half after the digits.

Separate this steps into functions and you will have clear code.


When coding create a plan, divide it into steps and then write the actual code. Writing many nested for loops and conditions without an overall view rarely works out for more complex problems (even if it does it is fragile to the addition of functionality and changes).

share|improve this answer

Before going into any coding I would give you a quick hack for the diamond problem . Instead of making so many for looping and columns and keeping track of variables the diamond problem is a variant of a maths problem. HERE

1*1 = 1
11*11 = 121
111*111 = 12321
1111*1111 = 1234321 

and so on. SO if you use this formula you just need one for loop for spaces and one for increasing your num*10 +1 where num is 1 and then squaring it and you will get the diamond pattern. If you want I can code it for you but since you asked for an easier method this is the best you can get.

share|improve this answer
2  
This method will work only till printNumberDiamond(10) after that output will be different. – Kaushal28 1 hour ago
2  
For n>9 it is not clear what the output pattern should look like – FredK 1 hour ago
    
for any n it does not matter because if n is 10 then it will be same just that it will flow out if your integer length. So use long for that. This will never fail as this is a mathematical pattern. What you have pointed out is the limitation of INT so justuse long – Abhinav Pandey 31 mins ago

Solution suggested by FredK is something I would implement, as it breaks down the problem to more smaller problems. However, this only prints the upper part of the diamond, so I would suggest doing the following:

  • don't immidiately print characters out, store them in a String and when a line is ready, store it in an array, or a List, called, for example, lines

  • when you are done with upper half of the diamond, print all the lines, each one in a new line

  • reverse the lines and remove the first element (to avoid duplicating the middle line)

  • print the reversed lines for the last time

share|improve this answer

This method is immediately smelly:

public static void printNumberDiamond(int diaCenter)
{   
        printNumberDiamondTop(diaCenter);
        printNumberDiamondBottom(diaCenter);
}

Which of the called methods will print the center line? It's impossible to tell without looking at the implementation, and you don't want readers to have to ask such questions. You want to make the logic as obvious as possible.

A simple step that will solve this issue is to add a third method to print the center line, and call it between these two methods.

Then, as a next step, realize that since the bottom is a mirror of the top, the logic to print them should have some common element. Looking at this code, or looks like there is no common element, and it will be a good idea to reorganize the code to make that happen.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.