By this method I am able to solve my problem, but is there any other way that I can make this type of triangle? Please correct my code if I am doing this the long way.
public class Pyramid{
public static void main(String [] args){
for (int i=0;i<= 6 ;i++) {
for (int x=0;x < 6-i;x++) {
System.out.print(" ");
}
for (int k=1;k<=i;k++) {
if (k <= 1) {
System.out.print(" *");
}
else if(k <= 2) {
System.out.print(" ");
}
else if(k <= 3) {
System.out.print(" ");
}
else if(k <= 4) {
System.out.print(" ");
}
else if(k <= 5) {
System.out.print(" ");
}
else if(k <= 6) {
System.out.print(" ");
}
}
for (int l=0;l<=i;l++) {
if (l <= 0) {
System.out.print(" *");
}
}
System.out.println();
}
System.out.print("* * * * * * * *");
}
}
-
1\$\begingroup\$ (Welcome to CR!) (I find the indentation misleading.) Is there anything specific you are not quite satisfied with? What if the number of layers was 42 instead of 6? \$\endgroup\$greybeard– greybeard2018年03月18日 15:55:16 +00:00Commented Mar 18, 2018 at 15:55
-
\$\begingroup\$ I am not satisfied because i think i hard-code this problem instead of dynamic that why i am seeking help so i can find my mistake and learn from that mistake in future @greybeard \$\endgroup\$Raza Khan– Raza Khan2018年03月18日 16:11:47 +00:00Commented Mar 18, 2018 at 16:11
-
\$\begingroup\$ if the number of layers was 42 then i have to put 42 layers and its so wrong i need solution i am working on it for 5 hours and i am new in java \$\endgroup\$Raza Khan– Raza Khan2018年03月18日 16:14:42 +00:00Commented Mar 18, 2018 at 16:14
-
\$\begingroup\$ Can you provide the result of what this outputs? \$\endgroup\$Simon Forsberg– Simon Forsberg2018年03月18日 17:59:06 +00:00Commented Mar 18, 2018 at 17:59
2 Answers 2
Your logic is completely static and will be impossible to maintain for bigger shape, but that kind of shape have a specific pattern.
The pattern
For a height (4), the output should be : (space replace by a dot for readability).
...*
..*.*
.*...*
* * * *
We can see that the left spaces start at 3 (height - 1) and decreased by one each time.
When we have two stars, the spaces between those is odd, incremented by two each row. If we use a bigger triangle, we see the following pattern :
- 1 space //Row 1 (using an 0-index based, first row don't have that spaces)
- 3 spaces //Row 2
- 5 spaces //Row 3
- 7 spaces //Row 4
This can be calculated with (#row * 2 - 1)
The last row is a bit different, we need to print 4 stars (height) separated by a space
Let's code
First, we need a way to easily print a number of spaces (the only variable in that pattern).
public static String blankString(int length);
The method can be quite verbose using a loop but I like to use String.format
here. This formatting allow use to add space padding to a String
easily. More information can be found at How can I pad a String in Java?
public static String blankString(int length){
if(length == 0)
return ""; //%0s is not supported
else
return String.format("%" + length + "s", "");
}
A one-line method using a ternary operator, because it is nice to use
return (length == 0) ? "" : String.format("%" + length + "s", "");
The triangle
*
* *
* *
* * * *
Let's use the previous method to print the triangle like explained before
System.out.println(blankString(3) + "*"); // ...*
System.out.println(blankString(2) + "*" + blankString(1) + "*"); // ..*.*
System.out.println(blankString(1) + "*" + blankString(3) + "*"); // .*...*
for(int i = 0; i < 4; ++i){
System.out.print("* "); //*.*.*.*.
}
Great, this works, know let's update the code with a variable height
.
int height = 4;
System.out.println(blankString(height - 1) + "*"); //Row 0
System.out.println(blankString(height - 1 - 1) + "*" + blankString((1 * 2) - 1) + "*"); //Row 1
System.out.println(blankString(height - 1 - 2) + "*" + blankString((2 * 2) - 1) + "*"); //Row 2
for(int i = 0; i < height; ++i){
System.out.print("* ");
}
Note that we find the row#
in the parameter send to blankString
int height = 4;
//Row 0
System.out.println(blankString(height - 1) + "*");
// Following rows
for(int row = 1; row < height -1 ; ++row){
System.out.println(blankString(height - 1 - row) + "*" + blankString((row * 2) - 1) + "*"); //Row 1
}
//Last row
for(int i = 0; i < height; ++i){
System.out.print("* ");
}
Of course, we end up with a method two allow us to change height
public static void buildTriangle(int height){
//Row 0
System.out.println(blankString(height - 1) + "*");
// Following rows
for(int row = 1; row < height -1 ; ++row){
System.out.println(blankString(height - 1 - row) + "*" + blankString((row * 2) - 1) + "*"); //Row 1
}
//Last row
for(int i = 0; i < height; ++i){
System.out.print("* ");
}
}
And with buildTriangle(8)
:
*
* *
* *
* *
* *
* *
* *
* * * * * * * *
Note, most of the code need to be protected against negative parameters, but since this pattern was not easy to explain, I preferred to focus the scope on the logic, not the parameter safety.
-
\$\begingroup\$ It's been a while since my last review, so if I messed something in my post, let me know! \$\endgroup\$AxelH– AxelH2018年03月19日 13:32:18 +00:00Commented Mar 19, 2018 at 13:32
-
\$\begingroup\$ yeah its working and its understandable i am confused about is there any way that i can make it dynamic i think that's not possible but your method is also simple for beginners @AxelH \$\endgroup\$Raza Khan– Raza Khan2018年03月20日 06:32:41 +00:00Commented Mar 20, 2018 at 6:32
-
\$\begingroup\$ @RazaKhan What do you want to be dynamic ? Here I have only thought about the height (layers as you called it) of the shape to be a parameter... \$\endgroup\$AxelH– AxelH2018年03月20日 07:04:42 +00:00Commented Mar 20, 2018 at 7:04
Your method certainly works, but I agree that using nested/multiple loops and inner if/else blocks is inelegant, if only because it makes following the code somewhat harder. Also, as you point out in a comment, hard-coding the structure is a nightmare if you suddenly want a pyramid which is 46 stars high.
As an alternative, I've rewritten the code to break it out into separate methods which hopefully make the code easier to understand, and also to allow a variable pyramid height (any value from zero or above).
public static void main(String[] args) {
drawStarPyramid2(8);
}
private static void drawStarPyramid2(int height) {
if (height < 0) {
throw new IllegalArgumentException("Height cannot be negative.");
}
StringBuilder sb = new StringBuilder(height * height);
appendSides(sb, height);
appendBaseline(sb, height);
System.out.println(sb.toString());
}
private static void appendSides(StringBuilder sb, int height) {
int baselineWidth = height * 2 - 1;
int midLine = baselineWidth / 2;
for (int rowIndex = 0; rowIndex < height - 1; ++rowIndex) {
int leftStarOffset = midLine - rowIndex;
appendSpacesThenStar(sb, leftStarOffset);
if (rowIndex > 0) {
int rightStarOffset = midLine + rowIndex - 1;
appendSpacesThenStar(sb, rightStarOffset - leftStarOffset);
}
sb.append("\n");
}
}
private static void appendSpacesThenStar(StringBuilder sb, int spaces) {
for (int spaceIndex = 0; spaceIndex < spaces; ++spaceIndex) {
sb.append(' ');
}
sb.append('*');
}
private static void appendBaseline(StringBuilder sb, int stars) {
boolean first = true;
for (int starIndex = 0; starIndex < stars; ++starIndex) {
if (!first) {
sb.append(' ');
}
sb.append('*');
first = false;
}
}
Because the sides need to be rendered differently to the baseline, each chunk of code goes into its own method, with a name which clearly describes the different purpose of each.
The appendSides
method is responsible only for drawing the left and right sides of the triangle. This calculates the baseline width (the number of characters on the console counting stars and spaces) and this will be equal to height
stars (because the number of stars on the baseline must equal the number of stars along the height of each side) plus height - 1
spaces, which gives 2 * height - 1
. Then it calculates the mid-way point (in terms of characters on the console line) and then places the first star at this point.
For all subsequent lines, the "left" side star is simply placed at the position which is one additional character further left of the previous position (starting at the mid-way position), and the "right" side star at the position which is one additional character further right of the previous position. The rowIndex
is a convenient way to calculate how many places to move away from the mid-way point on each line. The mathematics being used to calculate all of these offsets is fairly simple, but I recommend you sketch it out on a bit of paper, one line at a time, to get a feel for how the numbers work together.
The appendSpacesThenStar
method simply appends the specified number of space characters to the StringBuilder
and then a star. This method does not append a newline, because this method is often called twice for the same line, to write the "left" and then the "right" stars.
The appendBaseline
method just appends (to the StringBuilder
) the required number of stars, separated by spaces.
A StringBuilder
is being used to make assembly of the final string sequence more efficient, allowing the building of each line to be split across multiple method calls, rather than trying to finish each line in a single statement.
(Also note that the initial capacity passed to the StringBuilder
constructor can be improved by giving exactly the number of characters that will be needed, once spaces, stars, and newlines have been taken into consideration, but I'll leave this as an exercise for you.)
-
\$\begingroup\$ Sir i am new in java and in the learning process i am understanding your code little bit but its hard for me to understand clearly and i cant explain it to my Professor because there are many thing i am not understanding \$\endgroup\$Raza Khan– Raza Khan2018年03月18日 16:20:42 +00:00Commented Mar 18, 2018 at 16:20
-
\$\begingroup\$ I think
appendBaseline()
could be as straightforward asappendSpacesThenStar()
usingsb.append('*'); for (int done = 1; done < stars; ++done ) sb.append(' ').append('*');
\$\endgroup\$greybeard– greybeard2018年03月18日 16:30:54 +00:00Commented Mar 18, 2018 at 16:30 -
\$\begingroup\$ @RazaKhan I've added some narrative about how the primary three methods work, so it's hopefully easier to understand what they're doing. \$\endgroup\$Bobulous– Bobulous2018年03月18日 16:37:45 +00:00Commented Mar 18, 2018 at 16:37
-
\$\begingroup\$ @greybeard the
appendBaseline
method could be written a few ways, but don't forget that this code currently permits aheight
of zero, so a zero-check would be needed before switching to your approach. If performance was critical then your approach is probably more efficient, though. \$\endgroup\$Bobulous– Bobulous2018年03月18日 16:39:41 +00:00Commented Mar 18, 2018 at 16:39 -
\$\begingroup\$ Things I liked: readability over brevity; sizing the
StringBuilder
. \$\endgroup\$greybeard– greybeard2018年03月18日 16:50:10 +00:00Commented Mar 18, 2018 at 16:50