I've tried running this, but printing out circleCounter only prints 0. If I were to put the counter code under the tester function in the bottom part, then it would work. What am I doing wrong? Am I missing out on something?
public class Project1 {
public int circleCounter; // Number of non-singular circles in the file.
public int posFirstLast; // Indicates whether the first and last circles overlap or not.
public double maxArea; // Area of the largest circle (by area).
public double minArea; // Area of the smallest circle (by area).
public double averageArea; // Average area of the circles.
public double stdArea; // Standard deviation of area of the circles.
public double medArea; // Median of the area.
public int stamp = 189375;
public Project1() {
// This method is complete.
}
public void results(String fileName) {
MaInput F1 = new MaInput("DataFile.data");
double x, y, rad;
int circleCounter = 0;
double sumArea = 0;
Circle A = new Circle();
while (!F1.atEOF()) {
x = F1.readDouble();
y = F1.readDouble();
rad = F1.readDouble();
circleCounter++;
if (A.area() > maxArea) {
maxArea = A.area();
}
if (A.area() < minArea) {
minArea = A.area();
}
sumArea += A.area();
averageArea = sumArea / circleCounter;
stdArea = Math.sqrt((Math.pow(A.area() - averageArea, 2) / circleCounter));
//Array for points
Circle[] points = new Circle[circleCounter];
for (int j = 0; j < points.length; j++) {
if (rad > Point.GEOMTOL) {
points[j] = A;
}
}
posFirstLast = points[1].overlap(points[points.length]);
//Array of areas
double[] areas = new double[circleCounter];
for (int i = 0; i < areas.length; i++) {
if (rad > Point.GEOMTOL) {
areas[i] = A.area();
}
}
//Bubble Sort
for (int i = 0; i < areas.length; i++) {
if (areas[i + 1] < areas[i]) {
double temp = areas[i + 1];
areas[i + 1] = areas[i];
areas[i] = temp;
}
}
//Median
if (areas.length % 2 == 0) {
medArea = (0 / 5) * (areas[(areas.length / 2) - 1] + areas[areas.length / 2]);
} else {
medArea = (0.5) * (areas[((areas.length) - 1) / 2]);
}
}
}
public static void main(String args[]) {
Project1 pleasework = new Project1();
System.out.println("Number of (non-singular) circles: " + pleasework.circleCounter);
System.out.println("Whether the first and last circles overlap: " + pleasework.posFirstLast);
System.out.println("Maximum Area: " + pleasework.maxArea);
System.out.println("Minimum Area: " + pleasework.minArea);
System.out.println("Average Area: " + pleasework.averageArea);
System.out.println("Standard deviation of the areas: " + pleasework.stdArea);
System.out.println("Median of the areas: " + pleasework.medArea);
}
}
So, if it's only your circleCounter that's still giving you 0, then you should be aware of shadowing your variables.
private int circleCounter = 0; is applicable to the global scope.
int circleCounter = 0; is applicable to the scope local to your method results. The most local scope takes precedence with variables, so you've thus shadowed your global variable by redeclaring it here.
Simply take out that declaration and your variable won't be shadowed.
Edit: This also presumes that you actually call the method, too.
The main in your code does not invoke the results() method and hence all the default values of the fields are printed on your console i.e either 0 or 0.0(for double)
as main is the only entry point for java in your program.
Related
I am adapting a program which compiles OK; but when I try to run it I get an error window that says "no main classes found". I searched on your site for that type of problem (for NetBeans)and then tried a R click on my project in the Project window. Lagrange/properties/run and the class shown was the one in my program. I clicked run in that window and got the same error message.
The program is pasted below:
package lagrange;
class MyMath {
double xi[] = { 0, 0.5, 1, 1.5, 2 };
double fi[] = { 1, 0.938470, 0.765198, 0.511828, 0.223891 };
double x = 0.9;
double f = aitken(x, xi, fi);
// Method to carry out the Aitken recursions.
public double aitken(double x, double xi[], double fi[]) {
int n = xi.length - 1;
double ft[] = (double[]) fi.clone();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n - i; ++j) {
ft[j] = (x - xi[j]) / (xi[i + j + 1] - xi[j]) * ft[j + 1]
+ (x - xi[i + j + 1]) / (xi[j] - xi[i + j + 1]) * ft[j];
}
}
return ft[0];
}
}
public class Lagrange {
public void main(String[] args) {
// TODO code application logic here
System.out.println("Interpolated value: " + f);
}
}
It is public static void main - main method has to be static. And in your current code, you are declaring the main method in an inner class which is not static. This is not allowed and it will fail as
static methods can only be declared in a static or top level type.
One solution that can work for you is provided below with these changes -
main method shifted to MyMath class.
main method being static does not have access to non-static members and hence an instance of MyMath is created and used to print the result.
package lagrange;
class MyMath {
double xi[] = { 0, 0.5, 1, 1.5, 2 };
double fi[] = { 1, 0.938470, 0.765198, 0.511828, 0.223891 };
double x = 0.9;
double f = aitken(x, xi, fi);
// Method to carry out the Aitken recursions.
public double aitken(double x, double xi[], double fi[]) {
int n = xi.length - 1;
double ft[] = (double[]) fi.clone();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n - i; ++j) {
ft[j] = (x - xi[j]) / (xi[i + j + 1] - xi[j]) * ft[j + 1]
+ (x - xi[i + j + 1]) / (xi[j] - xi[i + j + 1]) * ft[j];
}
}
return ft[0];
}
public static void main(String[] args) {
System.out.println("Interpolated value: " + new MyMath().f);
}
}
I'm trying to create an algorithm that returns the closest pair from randomly generated points. I have finished the algorithm, however the divide and conquer method of the algorithm is not much faster than the brute-force method. What can I do to optimize the code so that it returns at (n log n) time?
import java.util.*;
import java.lang.*;
import static java.lang.Math.min;
import static java.lang.StrictMath.abs;
public class closestPair {
private static Random randomGenerator; // for random numbers
public static class Point implements Comparable<Point> {
public long x, y;
// Constructor
public Point(long x, long y) {
this.x = x;
this.y = y;
}
public int compareTo(Point p) {
// compare this and p and there are three results: >0, ==0, or <0
if (this.x == p.x) {
if (this.y == p.y)
return 0;
else
return (this.y > p.y)? 1 : -1;
}
else
return (this.x > p.x)? 1 : -1;
}
public String toString() {
return " ("+Long.toString(this.x)+","+Long.toString(this.y)+")";
}
public double distance(Point p) {
long dx = (this.x - p.x);
long dy = (this.y - p.y);
return Math.sqrt(dx*dx + dy*dy);
}
}
public static Point[] plane;
public static Point[] T;
public static Point[] Y;
public static int N; // number of points in the plane
public static void main(String[] args) {
// Read in the Size of a maze
Scanner scan = new Scanner(System.in);
try {
System.out.println("How many points in your plane? ");
N = scan.nextInt();
}
catch(Exception ex){
ex.printStackTrace();
}
scan.close();
// Create plane of N points.
plane = new Point[N];
Y = new Point[N];
T = new Point[N];
randomGenerator = new Random();
for (int i = 0; i < N; ++i) {
long x = randomGenerator.nextInt(N<<6);
long y = randomGenerator.nextInt(N<<6);
plane[i] = new Point(x, y);
}
Arrays.sort(plane); // sort points according to compareTo.
for (int i = 1; i < N; ++i) // make all x's distinct.
if (plane[i-1].x >= plane[i].x) plane[i].x = plane[i-1].x + 1;
//for (int i = 1; i < N; i++)
// if (plane[i-1].y >= plane[i].y) plane[i].y = plane[i-1].y + 1;
//
//
System.out.println(N + " points are randomly created.");
System.out.println("The first two points are"+plane[0]+" and"+plane[1]);
System.out.println("The distance of the first two points is "+plane[0].distance(plane[1]));
long start = System.currentTimeMillis();
// Compute the minimal distance of any pair of points by exhaustive search.
double min1 = minDisSimple();
long end = System.currentTimeMillis();
System.out.println("The distance of the two closest points by minDisSimple is "+min1);
System.out.println("The running time for minDisSimple is "+(end-start)+" mms");
// Compute the minimal distance of any pair of points by divide-and-conquer
long start1 = System.currentTimeMillis();
double min2 = minDisDivideConquer(0, N-1);
long end1 = System.currentTimeMillis();
System.out.println("The distance of the two closest points by misDisDivideConquer is "+min2);
System.out.println("The running time for misDisDivideConquer is "+(end1-start1)+" mms");
}
static double minDisSimple() {
// A straightforward method for computing the distance
// of the two closest points in plane[0..N-1].
// to be completed
double midDis = Double.POSITIVE_INFINITY;
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
if (plane[i].distance(plane[j]) < midDis){
midDis = plane[i].distance(plane[j]);
}
}
}
return midDis;
}
static void exchange(int i, int j) {
Point x = plane[i];
plane[i] = plane[j];
plane[j] = x;
}
static double minDisDivideConquer(int low, int high) {
// Initialize necessary values
double minIntermediate;
double minmin;
double minDis;
if (high == low+1) { // two points
if (plane[low].y > plane[high].y) exchange(low, high);
return plane[low].distance(plane[high]);
}
else if (high == low+2) { // three points
// sort these points by y-coordinate
if (plane[low].y > plane[high].y) exchange(low, high);
if (plane[low].y > plane[low+1].y) exchange(low, low+1);
else if (plane[low+1].y > plane[high].y) exchange(low+1, high);
// compute pairwise distances
double d1 = plane[low].distance(plane[high]);
double d2 = plane[low].distance(plane[low+1]);
double d3 = plane[low+1].distance(plane[high]);
return ((d1 < d2)? ((d1 < d3)? d1 : d3) : (d2 < d3)? d2 : d3); // return min(d1, d2, d3)
} else { // 4 or more points: Divide and conquer
int mid = (high + low)/2;
double lowerPartMin = minDisDivideConquer(low,mid);
double upperPartMin = minDisDivideConquer(mid+1,high);
minIntermediate = min(lowerPartMin, upperPartMin);
int k = 0;
double x0 = plane[mid].x;
for(int i = 1; i < N; i++){
if(abs(plane[i].x-x0) <= minIntermediate){
k++;
T[k] = plane[i];
}
}
minmin = 2 * minIntermediate;
for (int i = 1; i < k-1; i++){
for(int j = i + 1; j < min(i+7,k);j++){
double distance0 = abs(T[i].distance(T[j]));
if(distance0 < minmin){
minmin = distance0;
}
}
}
minDis = min(minmin, minIntermediate);
}
return minDis;
}
}
Use the following method with the change for minDisSimple. You can get more performance.
static double minDisSimple() {
// A straightforward method for computing the distance
// of the two closest points in plane[0..N-1].
// to be completed
double midDis = Double.POSITIVE_INFINITY;
double temp;
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
temp = plane[i].distance(plane[j]);
if (temp < midDis) {
midDis = temp;
}
}
}
return midDis;
}
Performance wise for small amount of points simple method is good but larger amount of points Divide and Conquer is good. Try number of points with 10, 100, 1000, 10000, 100000, 1000000.
One critical aspect in the minDisDivideConquer() is that the loop that constructs the auxiliary array T iterates through all the N points. Since there are O(N) recursive calls in total, making this pass through all the N points every time leads to a complexity of O(N^2), equivalent to that of the simple algorithm.
The loop should actually only consider the points with indices between low and high. Furthermore, it could be split into two separate loops that start from mid (forward and backward), and break when the checked distance is already too large.
Another possible improvement for the minDisDivideConquer() method, in the "4 or more points" situation is to prevent looking into pairs that were already considered in the recursive calls.
If my understanding is correct, the array T contains those points that are close enough on x axis to the mid point, so that there is a chance that a pair of points in T generates a distance smaller than those from the individual half sets.
However, it is not necessary to look into points that are both before mid, or both after mid (since these pairs were already considered in the recursive calls).
Thus, a possible optimization is to construct two lists T_left and T_right (instead of T) and check distances between pairs of points such that one is on the left of mid, and the other to the right.
This way, instead of computing |T| * (|T| - 1) / 2 distances, we would only look into |T_left| * |T_right| pairs, with |T_left| + |T_right| = |T|. This value is at most (|T| / 2) * (|T| / 2) = |T| ^ 2 / 4, i.e. around 2 times fewer distances than before (this is in the worst case, but the actual number of pairs can also be much smaller, inclusively zero).
I have a big problem. I try to create a neural network and want to train it with a backpropagation algorithm. I found this tutorial here http://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/ and tried to recreate it in Java. And when I use the training data he uses, I get the same results as him.
Without backpropagation my TotalError is nearly the same as his. And when I use the back backpropagation 10 000 time like him, than I get the nearly the same error. But he uses 2 Input Neurons, 2 Hidden Neurons and 2 Outputs but I'd like to use this neural network for OCR, so I need definitely more Neurons. But if I use for example 49 Input Neurons, 49 Hidden Neurons and 2 Output Neurons, It takes very long to change the weights to get a small error. (I believe it takes forever.....). I have a learningRate of 0.5. In the constructor of my network, I generate the neurons and give them the same training data like the one in the tutorial and for testing it with more neurons, I gave them random weights, inputs and targets. So can't I use this for many Neurons, does it takes just very long or is something wrong with my code ? Shall I increase the learning rate, the bias or the start weight?
Hopefully you can help me.
package de.Marcel.NeuralNetwork;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Random;
public class Network {
private ArrayList<Neuron> inputUnit, hiddenUnit, outputUnit;
private double[] inHiWeigth, hiOutWeigth;
private double hiddenBias, outputBias;
private double learningRate;
public Network(double learningRate) {
this.inputUnit = new ArrayList<Neuron>();
this.hiddenUnit = new ArrayList<Neuron>();
this.outputUnit = new ArrayList<Neuron>();
this.learningRate = learningRate;
generateNeurons(2,2,2);
calculateTotalNetInputForHiddenUnit();
calculateTotalNetInputForOutputUnit();
}
public double calcuteLateTotalError () {
double e = 0;
for(Neuron n : outputUnit) {
e += 0.5 * Math.pow(Math.max(n.getTarget(), n.getOutput()) - Math.min(n.getTarget(), n.getOutput()), 2.0);
}
return e;
}
private void generateNeurons(int input, int hidden, int output) {
// generate inputNeurons
for (int i = 0; i < input; i++) {
Neuron neuron = new Neuron();
// for testing give each neuron an input
if(i == 0) {
neuron.setInput(0.05d);
} else if(i == 1) {
neuron.setOutput(0.10d);
}
inputUnit.add(neuron);
}
// generate hiddenNeurons
for (int i = 0; i < hidden; i++) {
Neuron neuron = new Neuron();
hiddenUnit.add(neuron);
}
// generate outputNeurons
for (int i = 0; i < output; i++) {
Neuron neuron = new Neuron();
if(i == 0) {
neuron.setTarget(0.01d);
} else if(i == 1) {
neuron.setTarget(0.99d);
}
outputUnit.add(neuron);
}
// generate Bias
hiddenBias = 0.35;
outputBias = 0.6;
// generate connections
double startWeigth = 0.15;
// generate inHiWeigths
inHiWeigth = new double[inputUnit.size() * hiddenUnit.size()];
for (int i = 0; i < inputUnit.size() * hiddenUnit.size(); i += hiddenUnit.size()) {
for (int x = 0; x < hiddenUnit.size(); x++) {
int z = i + x;
inHiWeigth[z] = round(startWeigth, 2, BigDecimal.ROUND_HALF_UP);
startWeigth += 0.05;
}
}
// generate hiOutWeigths
hiOutWeigth = new double[hiddenUnit.size() * outputUnit.size()];
startWeigth += 0.05;
for (int i = 0; i < hiddenUnit.size() * outputUnit.size(); i += outputUnit.size()) {
for (int x = 0; x < outputUnit.size(); x++) {
int z = i + x;
hiOutWeigth[z] = round(startWeigth, 2, BigDecimal.ROUND_HALF_UP);
startWeigth += 0.05;
}
}
}
private double round(double unrounded, int precision, int roundingMode)
{
BigDecimal bd = new BigDecimal(unrounded);
BigDecimal rounded = bd.setScale(precision, roundingMode);
return rounded.doubleValue();
}
private void calculateTotalNetInputForHiddenUnit() {
// calculate totalnetinput for each hidden neuron
for (int s = 0; s < hiddenUnit.size(); s++) {
double net = 0;
int x = (inHiWeigth.length / inputUnit.size());
// calculate toAdd
for (int i = 0; i < x; i++) {
int v = i + s * x;
double weigth = inHiWeigth[v];
double toAdd = weigth * inputUnit.get(i).getInput();
net += toAdd;
}
// add bias
net += hiddenBias * 1;
net = net *-1;
double output = (1.0 / (1.0 + (double)Math.exp(net)));
hiddenUnit.get(s).setOutput(output);
}
}
private void calculateTotalNetInputForOutputUnit() {
// calculate totalnetinput for each hidden neuron
for (int s = 0; s < outputUnit.size(); s++) {
double net = 0;
int x = (hiOutWeigth.length / hiddenUnit.size());
// calculate toAdd
for (int i = 0; i < x; i++) {
int v = i + s * x;
double weigth = hiOutWeigth[v];
double outputOfH = hiddenUnit.get(s).getOutput();
double toAdd = weigth * outputOfH;
net += toAdd;
}
// add bias
net += outputBias * 1;
net = net *-1;
double output = (double) (1.0 / (1.0 + Math.exp(net)));
outputUnit.get(s).setOutput(output);
}
}
private void backPropagate() {
// calculate ouputNeuron weigthChanges
double[] oldWeigthsHiOut = hiOutWeigth;
double[] newWeights = new double[hiOutWeigth.length];
for (int i = 0; i < hiddenUnit.size(); i += 1) {
double together = 0;
double[] newOuts = new double[hiddenUnit.size()];
for (int x = 0; x < outputUnit.size(); x++) {
int z = x * hiddenUnit.size() + i;
double weigth = oldWeigthsHiOut[z];
double target = outputUnit.get(x).getTarget();
double output = outputUnit.get(x).getOutput();
double totalErrorChangeRespectOutput = -(target - output);
double partialDerivativeLogisticFunction = output * (1 - output);
double totalNetInputChangeWithRespect = hiddenUnit.get(x).getOutput();
double puttedAllTogether = totalErrorChangeRespectOutput * partialDerivativeLogisticFunction
* totalNetInputChangeWithRespect;
double weigthChange = weigth - learningRate * puttedAllTogether;
// set new weigth
newWeights[z] = weigthChange;
together += (totalErrorChangeRespectOutput * partialDerivativeLogisticFunction * weigth);
double out = hiddenUnit.get(x).getOutput();
newOuts[x] = out * (1.0 - out);
}
for (int t = 0; t < newOuts.length; t++) {
inHiWeigth[t + i] = (double) (inHiWeigth[t + i] - learningRate * (newOuts[t] * together * inputUnit.get(t).getInput()));
}
hiOutWeigth = newWeights;
}
}
}
And my Neuron Class:
package de.Marcel.NeuralNetwork;
public class Neuron {
private double input, output;
private double target;
public Neuron () {
}
public void setTarget(double target) {
this.target = target;
}
public void setInput (double input) {
this.input = input;
}
public void setOutput(double output) {
this.output = output;
}
public double getInput() {
return input;
}
public double getOutput() {
return output;
}
public double getTarget() {
return target;
}
}
Think about it: you have 10,000 propagations through 49->49->2 neurons. Between the input layer and the hidden layer, you have 49 * 49 links to propagate through, so parts of your code are being executed about 24 million times (10,000 * 49 * 49). That is going to take time. You could try 100 propogations, and see how long it takes, just to give you an idea.
There are a few things that can be done to increase performance, like using a plain array instead of an ArrayList, but this is a better topic for the Code Review site. Also, don't expect this to give drastic improvements.
Your back propagation code has complexity of O(h*o + h^2) * 10000, where h is the number of hidden neurons and o is the number of output neurons. Here's why.
You have a loop that executes for all of your hidden neurons...
for (int i = 0; i < hiddenUnit.size(); i += 1) {
... containing another loop that executes for all the output neurons...
for (int x = 0; x < outputUnit.size(); x++) {
... and an additional inner loop that executes again for all the hidden neurons...
double[] newOuts = new double[hiddenUnit.size()];
for (int t = 0; t < newOuts.length; t++) {
... and you execute all of that ten thousand times. Add on top of this O(i + h + o) [initial object creation] + O(i*h + o*h) [initial weights] + O(h*i) [calculate net inputs] + O(h*o) [calculate net outputs].
No wonder it's taking forever; your code is littered with nested loops. If you want it to go faster, factor these out - for example, combine object creation and initialization - or reduce the number of neurons. But significantly cutting the number of back propagation calls is the best way to make this run faster.
I want to invoke this method to get the median from an array. The method is declared as public double getMedian(double[]list){//code}.
I tried calling the method as getMedian(double,list) but I got an error. What would be the right way to call the method?
Here is the complete method:
public double getMedian(double[] list) {
// calculate the length of the entries
// create an iterator
int factor = list.length - 1;
double[] first = new double[(int) ((double) factor / 2)];
double[] last = new double[first.length];
double[] middleNumbers = new double[1];
for (int i = 0; i < first.length; i++) {
first[i] = list[i];
}
for (int i = list.length; i > last.length; i--) {
last[i] = list[i];
}
for (int i = 0; i <= list.length; i++) {
if (list[i] != first[i] || list[i] != last[i])
middleNumbers[i] = list[i];
}
if (list.length % 2 == 0) {
double total = middleNumbers[0] + middleNumbers[1];
return total / 2;
} else {
System.out.println(middleNumbers);
return middleNumbers[0];
}
}
The method takes an array of double values as a parameter. You would want to make an array of double and pass that:
double[] values = {0.1d, 0.3d, 0.5d, 1.0d, 1200.0d};
double median = this.getMedian(values); // should return 0.5d
But the getMedian method has some logic errors that prevent it from working correctly. In particular, the second loop starts beyond the bounds of the array:
for (int i = list.length; i > last.length; i--) {
last[i] = list[i];
}
Using my test data, i starts at 5 and counts down until i is greater than 5, but the array only has elements indexed from 0 to 4.
Its only asking for a double, list is what you just made the name of the array. You would need to do
getMedian(double[] doubleArray, List list)
To use 2 different types when its called.
Like this (which includes arguably a more elegant, and working, version of getMedian):
public class Test
{
public double getMedian(double[] list)
{
double median = 0;
if (list != null && (list.length > 0))
{
// Sort ascending
Arrays.sort(list);
int numItems = list.length;
if ((numItems % 2) == 0)
{
// We have an even number of items - average the middle two
int middleIndex = numItems / 2;
double firstMiddleValue = list[middleIndex - 1];
double secondMiddleValue = list[middleIndex];
median = (firstMiddleValue + secondMiddleValue) / 2;
}
else
{
// Odd number of items - pick the middle one
median = list[(numItems / 2)];
}
}
return median;
}
public static void main(String[] args)
{
Test t = new Test();
double[] testValuesOfLengthOne = { 3.1415 };
double[] testValuesEvenLength = {22.5, 14.33, 100.849, 44.259, 0.0, 145000.0};
double[] testValuesOddLength = {22.5, 14.33, 100.849, 44.259, 0.0, 145000.0, -4.9};
System.out.println("Median of " + Arrays.toString(testValuesOfLengthOne) + " is " + t.getMedian(testValuesOfLengthOne));
System.out.println("Median of " + Arrays.toString(testValuesEvenLength) + " is " + t.getMedian(testValuesEvenLength));
System.out.println("Median of " + Arrays.toString(testValuesOddLength) + " is " + t.getMedian(testValuesOddLength));
}
}
This gives you the following output:
Median of [3.1415] is 3.1415
Median of [22.5, 14.33, 100.849, 44.259, 0.0, 145000.0] is 33.3795
Median of [22.5, 14.33, 100.849, 44.259, 0.0, 145000.0, -4.9] is 22.5
So in my CS class, we have a little hw question and it isn't due for a week or so and it almost works except one little piece. Here is the assignment:
Write a program named ChrisTree that produces images of Christmas trees as output. It should have a method with two parameters: one for the number of segments in the tree and one for the height of each segment. For example, the tree shown here on the left has three segments of height 4 and the one on the right has two segments of height 5.
So my code works except on some trees where the last line of the tree is and the trunk are both off by a space. I can't seem to plug up that hole without making a new one. Any one see a possible "root" of the issue? PS the tree segments and heights are variable by changing class constants (I know, its a terrible method of changing them, but thats what this guy wants)(I know its probably horribly redundant as well)
public class ChrisTree {
public static final int SEGMENTS = 4;
public static final int HEIGHT = 4;
public static void main(String[] args){
makeTree();
}
// makeTree: code that prints the tree; params: num. of segments of tree, height of tree segments
public static void makeTree(){
// maxStars: calculation the length of each line which is the sum of spaces and stars for any line
int maxStars = 2*HEIGHT+2*SEGMENTS-3;
// maxStr: master variable string that will be changed and printed for each line
String maxStr = "";
// populates maxStr will spaces; will be used with substring to generate needed spaces
for (int len=0; len < maxStars; len++){
maxStr+=" ";
}
// loops once per segment
for (int i=1; i <= SEGMENTS; i++){
// starStr: variable string that changes perline that holds the stars
// populates starStr with stars
// loops through each line
for (int line=1; line <= HEIGHT; line++){
String starStr = "";
for (int j=1; j <= 2*line+2*i-3; j++){
starStr+="*";
}
for (int space=0; space <= maxStars-(HEIGHT+line+i); space++){
starStr = " " + starStr;
}
System.out.println(starStr);
}
}
for (int i=0; i <= maxStars/2;i++){
System.out.print(" ");
}
System.out.print("*\n");
for (int i=0; i <= maxStars/2;i++){
System.out.print(" ");
}
System.out.print("*\n");
for (int i=0; i <= maxStars/2-3;i++){
System.out.print(" ");
}
System.out.print("*******\n");
}
}
In my defense of doing obvious homework problems, the solutions here just hurt my eyes too much. (And I know these are standard homework problems, I did them back in the 80's, in Pascal).
package com.edwinbuck.christmas;
/**
* Draws a ChristmasTree.
* #author Edwin Buck
*/
public class ChristmasTree {
public static final int SEGMENTS = 4;
public static final int HEIGHT = 4;
public static void main(String[] args) {
int maxSize = 1 + 2 * (SEGMENTS - 1) + 2 * (HEIGHT - 1);
// for each segment beyond zero, we need 2 more asterisks.
for (int segmentContrib = 0; segmentContrib < 2 * SEGMENTS; segmentContrib += 2) {
// for each segment slice beyond zero, we need 2 more asterisks.
for (int sliceContrib = 0; sliceContrib < 2 * HEIGHT; sliceContrib += 2) {
drawCentered(maxSize, 1 + segmentContrib + sliceContrib);
}
}
// draw the trunk
drawCentered(maxSize, 1);
drawCentered(maxSize, 1);
// draw the base
drawCentered(maxSize, 7);
}
/**
* Draws a line of asterisks, centered within size spaces.
*
* #param size The size to center on.
* #param asterisks The number of asterisks to draw.
*/
private static void drawCentered(int size, int asterisks) {
int before = (size - asterisks) / 2;
int after = size - before - asterisks;
print(before, " ");
print(asterisks, "*");
print(after, " ");
System.out.println();
}
/**
* Draws a character a number of times.
*
* #param count The number of time to draw the character.
* #param character The character to draw.
*/
private static void print(int count, final String character) {
for (int i = 0; i < count; i++) {
System.out.print(character);
}
}
}
The key is to realize that all of the lines are centered asterisks of variable size. Once you do that, then you only need to figure out the loop to draw the sections (and the maximum line size).
The maximum line size is controlled by the bottom most section. Each input (SEGMENTS and HEIGHT) needs to be converted from "count from 1" to "count from 0". Each additional segment adds two to the asterisk size, as does each additional slice. The tree must have at least one asterisk, the one (trunk) running down the center. This leads to the formula
1 + 2*(SEGMENTS-1) + 2(HEIGHT-1)
which many have simplified to
2*SEGMENTS + 2*HEIGHT - 3
I didn't simplify it because it hides intent, something that's hard to recover in code once lost.
Then while walking through the loops, I decided to have the contributors to the size increment by two. It makes the rest of the math easier as we don't have to put "magic" formulas and math in odd places. This means that we can reuse our drawCentered(...) with the parameter 1 + segmentContrib + sliceContrib where the two other variables are the segment and slice "asterisk" contributions.
Finally, we draw a trunk of two vertical asterisks and the base.
I know this is extremely late, but I just wrote this and it worked.
public class ChrisTree {
public static final int SEGMENTS = 4;
public static final int HEIGHT = 4;
public static void main(String[] args) {
makeTree();
}
public static void makeTree() {
int maxStars = 2 * HEIGHT + 2 * SEGMENTS - 3;
String maxStr = "";
for (int l = 0; l < maxStars; l++) {
maxStr += " ";
}
for (int i = 1; i <= SEGMENTS; i++) {
for (int line = 1; line <= HEIGHT; line++) {
String starStr = "";
for (int j = 1; j <= 2 * line + 2 * i - 3; j++) {
starStr += "*";
}
for (int space = 0; space <= maxStars - (HEIGHT + line + i); space++) {
starStr = " " + starStr;
}
System.out.println(starStr);
}
}
for (int i = 0; i <= maxStars / 2; i++) {
System.out.print(" ");
}
System.out.println(" " + "*" + " ");
for (int i = 0; i <= maxStars / 2; i++) {
System.out.print(" ");
}
System.out.println(" " + "*" + " ");
for (int i = 0; i <= maxStars / 2 - 3; i++) {
System.out.print(" ");
}
System.out.println(" " + "*******");
}
}