Subscribe to MentalFloss - JBlog
1 Votes

## Doing Your Homework - Text Mountain

Considering the fact that I am new to Java (and desperately out of practice with programming in general), I figured I would do what I have done in the past with any language I tried to learn - your homework. See, there is an endless supply of projects available to me through your posts. This provides a means to focused comptency assessment for me.

So, let's look at what I found:

```////////////////\\\\\\\\\\\\\\\\
////////////********\\\\\\\\\\\\
////////****************\\\\\\\\
////************************\\\\
********************************

```

The task is to create a program that will print this output. I did not pay attention to the specific details but the assignment is obvious enough. This is testing the ability to use loops in your program. So, the first thing that must be understood is WHAT exactly is happening here. Let's look:

• There are 5 lines.
• There are 32 characters per line.
• At the half-way point, slashes flip direction.
• To the left and right of half-way point, the number of stars increases by 4 for each line.

This is a rigid comprehension of what is happening. From this, I can program an algorithm that will provide the desired output:

```public class RigidClient {
public static void main(String[] args) {
for (int rows = 0; rows < 5; rows++) {
// Every row grows by 4 stars.
int stars = rows * 4;
// We start printing stars closest to center and work outward.
int startStars = Math.abs(16 - stars);
int stopStars = 16 + stars;

for (int cols = 0; cols <= 32; cols++) {
if (cols < startStars) {
System.out.print('/');
} else if (cols >= startStars && cols < stopStars) {
System.out.print('*');
} else if (cols > stopStars) {
System.out.print('\\');
}
}
System.out.println();
}
}
}

```

```////////////////\\\\\\\\\\\\\\\\
////////////********\\\\\\\\\\\\
////////****************\\\\\\\\
////************************\\\\
********************************

```

OK. So, job's done. We can all go home - it works and we'll pass the assignment.

Except NOW is the time to take that homework you have to do and start to work on making it better. This step is always neglected by students. You think you're done when it "works". You are not done until it is hardened against CHANGE.

The first thing to address is all of those concrete values. We definitely do not want to worry about making a modification in one spot and then having missed it in another spot. So, let's rewrite this so that we have all of our constant values in a simple to see place.

```public class SpongeyClient {

public static void main(String[] args) {
final int MAX_ROWS = 5;
final int MAX_COLS = 32;
final int HALF_COLS = MAX_COLS/2;
final int ADD_STARS = 4;

for (int rows = 0; rows < MAX_ROWS; rows++)
{
int stars = rows * ADD_STARS;
int startStars = Math.abs(HALF_COLS - stars);
int stopStars = HALF_COLS + stars;

for (int cols = 0; cols <= MAX_COLS; cols++)
{
if (cols < startStars) {
System.out.print('/');
}
else if (cols >= startStars && cols < stopStars) {
System.out.print('*');
}
else if (cols > stopStars) {
System.out.print('\\');
}
}
System.out.print('\n');
}
}
}

```

Now we are much more resistant to change. However, I really don't like that I'm so reliant on the System printing. This has confined me to simply being able to print from here. What I really want is to be able to print anywhere so let's change this to use a StringBuilder instead.

```public class Client {

public static void main(String[] args) {
final int MAX_ROWS = 5;
final int MAX_COLS = 32;
final int HALF_COLS = MAX_COLS / 2;
final int ADD_STARS = 4;

StringBuilder output = new StringBuilder();
for (int rows = 0; rows < MAX_ROWS; rows++) {
int stars = rows * ADD_STARS;
int startStars = Math.abs(HALF_COLS - stars);
int stopStars = HALF_COLS + stars;

for (int cols = 0; cols <= MAX_COLS; cols++) {
if (cols < startStars) {
output.append('/');
} else if (cols >= startStars && cols < stopStars) {
output.append('*');
} else if (cols > stopStars) {
output.append('\\');
}
}
output.append('\n');
}
System.out.println(output);
}
}

```

OK cool. I still print here but now I'm certainly not confined to it. It wouldn't take any effort to just return the output and work on it elsewhere. I won't do that though. And so, what can still change? Well, our characters that we print with might change so let's put them somewhere accessible too:

```public class Client {

public static void main(String[] args) {
final int MAX_ROWS = 5;
final int MAX_COLS = 32;
final int HALF_COLS = MAX_COLS / 2;
final int ADD_STARS = 4;

final char center = '*';
final char left = '/';
final char right = '\\';

StringBuilder output = new StringBuilder();
for (int rows = 0; rows < MAX_ROWS; rows++) {
int stars = rows * ADD_STARS;
int startStars = Math.abs(HALF_COLS - stars);
int stopStars = HALF_COLS + stars;

for (int cols = 0; cols <= MAX_COLS; cols++) {
if (cols < startStars) {
output.append(left);
} else if (cols >= startStars && cols < stopStars) {
output.append(center);
} else if (cols > stopStars) {
output.append(right);
}
}
output.append('\n');
}
System.out.println(output);
}
}

```

I kept the newline as its character because that's not going to change. A newline is needed for this algorithm. So, we have made multiple changes and the output looks great but it's still so very rigid. I mean it HAS to print 5 rows and it HAS to print 32 characters. Why should that be a limit?

The first thing we have to understand is why 5 lines and 32 characters was chosen. Well, we know that we increase star count by 8 every time (4 to left and 4 to right of center) and we know that the first line doesn't have any stars. So, realistically it is 32/8 = 4. Then we add that extra line for the line that has no stars and bingo we know the algorithm for any printing we want to do.

```public class Client {

public static void main(String[] args) {
final int MAX_ROWS = 7;
final int ADD_STARS = 3;

final int MAX_COLS = (MAX_ROWS - 1) * (ADD_STARS * 2);
final int HALF_COLS = MAX_COLS / 2;

final char center = '*';
final char left = '/';
final char right = '\\';

StringBuilder output = new StringBuilder();

int stars = 0;
for (int rows = 0; rows < MAX_ROWS; rows++) {
stars = rows * ADD_STARS;
int startStars = Math.abs(HALF_COLS - stars);
int stopStars = HALF_COLS + stars;

for (int cols = 0; cols <= MAX_COLS; cols++) {
if (cols < startStars) {
output.append(left);
} else if (cols >= startStars && cols < stopStars) {
output.append(center);
} else if (cols > stopStars) {
output.append(right);
}
}

output.append('\n');
}
System.out.println(output);
}
}

```

```//////////////////\\\\\\\\\\\\\\\\\\
///////////////******\\\\\\\\\\\\\\\
////////////************\\\\\\\\\\\\
/////////******************\\\\\\\\\
//////************************\\\\\\
///******************************\\\
************************************

```

Now, at this point you're probably top in class because you can have any number of rows you want but hey... we need the user to provide that right? So, let's move all of this to a method and pass in user inputs:

```import java.util.Scanner;

public class Client {

private void printMountain(int rows, int starGrowth) {
final int MAX_ROWS = rows;
final int ADD_STARS = starGrowth;

// The first row doesn't have stars in it. We want the added stars to be
// on the left and right equally.
final int MAX_COLS = (MAX_ROWS - 1) * (ADD_STARS * 2);
final int HALF_COLS = MAX_COLS / 2;

final char center = '*';
final char left = '/';
final char right = '\\';

StringBuilder output = new StringBuilder();

int stars = 0;
for (int row = 0; row < MAX_ROWS; row++) {
stars = row * ADD_STARS;
int startStars = Math.abs(HALF_COLS - stars);
int stopStars = HALF_COLS + stars;

for (int col = 0; col <= MAX_COLS; col++) {
if (col < startStars) {
output.append(left);
} else if (col >= startStars && col < stopStars) {
output.append(center);
} else if (col > stopStars) {
output.append(right);
}
}

output.append('\n');
}
System.out.println(output);
}

private Client() {
Scanner input = new Scanner(System.in);

System.out.print("Number of rows: ");
int rows = input.nextInt();

System.out.print("Star growth: ");
int stars = input.nextInt();

printMountain(rows, stars);

input.close();
}

public static void main(String[] args) {
new Client();
}
}

```

```Number of rows: 10
Star growth: 3
///////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\
////////////////////////******\\\\\\\\\\\\\\\\\\\\\\\\
/////////////////////************\\\\\\\\\\\\\\\\\\\\\
//////////////////******************\\\\\\\\\\\\\\\\\\
///////////////************************\\\\\\\\\\\\\\\
////////////******************************\\\\\\\\\\\\
/////////************************************\\\\\\\\\
//////******************************************\\\\\\
///************************************************\\\
******************************************************

```

Now, obviously we have a huge problem. All of this code is in the main class and well, that's just really a bad idea. So, let's create a new class and put our existing work into it. While we're at it, let's overload the method so that the user can provide the characters to print with.

```import java.util.Scanner;

public class Client {

private Client() {
Scanner input = new Scanner(System.in);

System.out.print("Number of rows: ");
int rows = input.nextInt();

System.out.print("Star growth: ");
int stars = input.nextInt();

new Mountain(rows, stars).printMountain();
new Mountain(rows, stars).printMountain('[', '\$', ']');

input.close();
}

public static void main(String[] args) {
new Client();
}
}

```

```public class Mountain {

private int rows;
private int starGrowth;

public Mountain(int rows, int starGrowth) {
this.rows = rows;
this.starGrowth = starGrowth;
}

public void printMountain() {
printMountain('/', '*', '\\');
}

public void printMountain(char left, char center, char right) {
final int MAX_ROWS = rows;
final int ADD_STARS = starGrowth;

// The first row doesn't have stars in it. We want the added stars to be
// on the left and right equally.
final int MAX_COLS = (MAX_ROWS - 1) * (ADD_STARS * 2);
final int HALF_COLS = MAX_COLS / 2;

StringBuilder output = new StringBuilder();

int stars = 0;
for (int row = 0; row < MAX_ROWS; row++) {
stars = row * ADD_STARS;
int startStars = Math.abs(HALF_COLS - stars);
int stopStars = HALF_COLS + stars;

for (int col = 0; col <= MAX_COLS; col++) {
if (col < startStars) {
output.append(left);
} else if (col >= startStars && col < stopStars) {
output.append(center);
} else if (col > stopStars) {
output.append(right);
}
}
output.append('\n');
}
System.out.println(output);
}
}

```

```Number of rows: 5
Star growth: 3
////////////\\\\\\\\\\\\
/////////******\\\\\\\\\
//////************\\\\\\
///******************\\\
************************

[[[[[[[[[[[[]]]]]]]]]]]]
[[[[[[[[[\$\$\$\$\$\$]]]]]]]]]
[[[[[[\$\$\$\$\$\$\$\$\$\$\$\$]]]]]]
[[[\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$]]]
\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$

```

And that's why I love your homework and you should too! Those assignments are only the start. If you want to advance, bleed them dry.

Have fun!

### Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

S M T W T F S
1234567
891011121314
1516171819 20 21
22232425262728
293031

### 0 user(s) viewing

0 Guests
0 member(s)
0 anonymous member(s)