patternjavaModerate
Retro Rocket ASCII Art
Viewed 0 times
rocketartretroascii
Problem
Inspired by Nested for-loop ASCII art, I looked at building a more complicated ASCII art than just the normal 'diamond' and 'triangle' variations that crop up occasionally here.
The challenge: Produce the following rocket
The question on Stack Overflow has issues, and those issues got answered before I could put a response together, but, the problem intrigued me, and I built the following code to solve it in a more compact way, using loops as much as possible, and parameterizing almost all aspects of the problem.
```
public class Rocket {
private enum Direction {
FORWARD, BACKWARD
}
private static final char NONE = (char) 0;
private static final String buildSymmetrical(
char[] chars, char mid, int from, int len) {
StringBuilder sb = new StringBuilder(len * 2 + 2);
for (int i = 0; i < len; i++) {
sb.append(chars[from + i]);
}
if (mid != NONE) {
sb.append(mid).append(mid);
}
for (int i = 0; i < len; i++) {
sb.append(chars[chars.length - from - len + i]);
}
return sb.toString();
}
private static final String buildLines(
char bracket, char[] source, int len, char midchar, int charfrom,
Direction chardir, int linecount, int duplicates) {
StringBuilder sb = new StringBuilder();
for (int line = 0; line < linecount; line++) {
sb.append(bracket);
int pos = charfrom + line * (chardir == Direction.FORWARD ? 1 : -1);
String block = buildSymmetrical(source, midchar, pos, len);
for (int d = 0; d < dup
The challenge: Produce the following rocket
/**\
//**\\
///**\\\
////**\\\\
/////**\\\\\
+=*=*=*=*=*=*+
|../\..../\..|
|./\/\../\/\.|
|/\/\/\/\/\/\|
|\/\/\/\/\/\/|
|.\/\/..\/\/.|
|..\/....\/..|
+=*=*=*=*=*=*+
|\/\/\/\/\/\/|
|.\/\/..\/\/.|
|..\/....\/..|
|../\..../\..|
|./\/\../\/\.|
|/\/\/\/\/\/\|
+=*=*=*=*=*=*+
/**\
//**\\
///**\\\
////**\\\\
/////**\\\\\The question on Stack Overflow has issues, and those issues got answered before I could put a response together, but, the problem intrigued me, and I built the following code to solve it in a more compact way, using loops as much as possible, and parameterizing almost all aspects of the problem.
```
public class Rocket {
private enum Direction {
FORWARD, BACKWARD
}
private static final char NONE = (char) 0;
private static final String buildSymmetrical(
char[] chars, char mid, int from, int len) {
StringBuilder sb = new StringBuilder(len * 2 + 2);
for (int i = 0; i < len; i++) {
sb.append(chars[from + i]);
}
if (mid != NONE) {
sb.append(mid).append(mid);
}
for (int i = 0; i < len; i++) {
sb.append(chars[chars.length - from - len + i]);
}
return sb.toString();
}
private static final String buildLines(
char bracket, char[] source, int len, char midchar, int charfrom,
Direction chardir, int linecount, int duplicates) {
StringBuilder sb = new StringBuilder();
for (int line = 0; line < linecount; line++) {
sb.append(bracket);
int pos = charfrom + line * (chardir == Direction.FORWARD ? 1 : -1);
String block = buildSymmetrical(source, midchar, pos, len);
for (int d = 0; d < dup
Solution
Wells, for the sake of loop-ifying everything, you may want to consider changing
That will create
The ternary operator below looks like a good candidate for adding a helper method into the
My version is expanded as such:
And calculating
One more minor suggestion: The usage of
Due to the fact that our
boundary as such:final char[] boundary = "=*=*=*".toCharArray();
...
sb.append( buildLines( '+', boundary, 3, NONE, 0, Direction.CENTER, 1, 2 ) );That will create
===*, duplicate it once, and add the + character at both ends.The ternary operator below looks like a good candidate for adding a helper method into the
Direction enum:int pos = charfrom + line * (chardir == Direction.FORWARD ? 1 : -1)My version is expanded as such:
private enum Direction {
CENTER( 0 ), UPWARD( 1 ), DOWNWARD( -1 );
private final int multiplier;
Direction( final int multiplier ) {
this.multiplier = multiplier;
}
int getMultiplier() {
return multiplier;
}
}And calculating
pos is just charfrom + line * chardir.getMultiplier();One more minor suggestion: The usage of
5 and 3 seems to be repeated quite often, maybe refer to them as coneSize and blockSize? The main body will look something like:sb.append( buildLines( ' ', cone, coneSize, '*', 0, Direction.UPWARD, coneSize, 1 ) );
sb.append( buildLines( '+', boundary, blockSize, NONE, 0, Direction.CENTER, 1, 2 ) );
sb.append( buildLines( '|', wider, blockSize, NONE, 0, Direction.UPWARD, blockSize, 2 ) );
sb.append( buildLines( '|', narrower, blockSize, NONE, 2, Direction.DOWNWARD, blockSize, 2 ) );
sb.append( buildLines( '+', boundary, blockSize, NONE, 0, Direction.CENTER, 1, 2 ) );
sb.append( buildLines( '|', narrower, blockSize, NONE, 2, Direction.DOWNWARD, blockSize, 2 ) );
sb.append( buildLines( '|', wider, blockSize, NONE, 0, Direction.UPWARD, blockSize, 2 ) );
sb.append( buildLines( '+', boundary, blockSize, NONE, 0, Direction.CENTER, 1, 2 ) );
sb.append( buildLines( ' ', cone, coneSize, '*', 0, Direction.UPWARD, coneSize, 1 ) );Due to the fact that our
sources are fixed lengths now, I don't see much of an improvement on the method signatures since it's not like the current code can be easily expanded to create rockets of different sizes. Maybe I'll attempt another stab at that when I have some more time...Code Snippets
final char[] boundary = "=*=*=*".toCharArray();
...
sb.append( buildLines( '+', boundary, 3, NONE, 0, Direction.CENTER, 1, 2 ) );int pos = charfrom + line * (chardir == Direction.FORWARD ? 1 : -1)private enum Direction {
CENTER( 0 ), UPWARD( 1 ), DOWNWARD( -1 );
private final int multiplier;
Direction( final int multiplier ) {
this.multiplier = multiplier;
}
int getMultiplier() {
return multiplier;
}
}sb.append( buildLines( ' ', cone, coneSize, '*', 0, Direction.UPWARD, coneSize, 1 ) );
sb.append( buildLines( '+', boundary, blockSize, NONE, 0, Direction.CENTER, 1, 2 ) );
sb.append( buildLines( '|', wider, blockSize, NONE, 0, Direction.UPWARD, blockSize, 2 ) );
sb.append( buildLines( '|', narrower, blockSize, NONE, 2, Direction.DOWNWARD, blockSize, 2 ) );
sb.append( buildLines( '+', boundary, blockSize, NONE, 0, Direction.CENTER, 1, 2 ) );
sb.append( buildLines( '|', narrower, blockSize, NONE, 2, Direction.DOWNWARD, blockSize, 2 ) );
sb.append( buildLines( '|', wider, blockSize, NONE, 0, Direction.UPWARD, blockSize, 2 ) );
sb.append( buildLines( '+', boundary, blockSize, NONE, 0, Direction.CENTER, 1, 2 ) );
sb.append( buildLines( ' ', cone, coneSize, '*', 0, Direction.UPWARD, coneSize, 1 ) );Context
StackExchange Code Review Q#65040, answer score: 10
Revisions (0)
No revisions yet.