El siguiente programa fue el resultado de un proceso de análisis (comprensión del problema), diseño (de un algoritmo en pseudocódigo), implementación (traducción del algoritmo a Java) y pruebas (de cada uno de los anteriores). El rastro del diseño se puede ver en los comentarios en el código.
1000 o masa <= 0 o altura <= 0 o altura > 300cm
if ( mass > 1000.0 || mass <= 0.0 || heightCm <= 0.0 || heightCm > 300.0 )
{
// Informar datos invalidos
System.out.println("invalid data");
}
else
{
// Los datos son validos
// Convertir la altura a metros
double heightMeters = heightCm / 100.0;
// Calcular el indice de masa corporal (bmi)
double bodyMassIndex = mass / (heightMeters * heightMeters);
// Informar la masa, la altura en centrimetros, y el bmi
System.out.printf("%5.2f ", bodyMassIndex);
// Imprimir el estado nutricional de acuerdo a los rangos de la OMC
if ( bodyMassIndex < 18.5 )
{
// Informar infrapeso
System.out.println("underweight");
}
if ( bodyMassIndex >= 18.5 && bodyMassIndex < 25.0 )
{
// Informar normal
System.out.println("normal");
}
if ( bodyMassIndex >= 25.0 && bodyMassIndex < 30.0 )
{
// Informar sobrepeso
System.out.println("overweight");
}
if ( bodyMassIndex >= 30.0 )
{
// Informar obesidad
System.out.println("obese");
}
}
}
// Close the standard input
input.close();
}
}
]]>
Produce números aleatorios enteros en un rango dado, por ejemplo, si el rango es 00 a 75 (inclusive), producirá números válidos para un bingo.
Los operadores ariméticos (+, -, *, /, %) funcionan únicamente con tipos de datos primitivos (enteros y flotantes). Sólo existe una única excepción: el operador + puede concatenar textos (String). Los demás operadores de Java sólo trabajan con tipos de datos primitivos: operadores relacionales (==, >, >=, <, <=), operadores lógicos (!, &&, ||). Sin embargo hay que tener algunos cuidados. Por ejemplo, el operador de igualdad == sólo funciona con enteros, y en caso de flotantes sólo funciona cuando se compara contra 0.0.
1000.0 ? 1000.0 : mass;
/*
mass > 1000.0
? System.out.println("invalid data")
: System.out.println("valid data"); // bmi = mass / h*h*
*/
int a = 5;
int x = ++a - a--;
System.out.printf("a=%d x=%d\n", a, x);
// Close the standard input
input.close();
}
}
]]>
Los operadores de asignación (=) tienen variantes cortas para cada operador aritmético (+=, -=, *=, /=, %=), y operadores de pre/post-incremento (++) y pre/post-decremento (--). Estos últimos deben evitarse combinar en una misma expresión.
Se mostró cómo crear un ejercicio desde cero. Las instrucciones se encuentran en la sección Ejercicios inventados del curso. El ejercicio completo puede obtenerse en:
Se crearon 11 casos de prueba, varios con datos inválidos. El siguiente programa usa excepciones de Java para reaccionar a esas condiciones anormales.
try
{
// Read the width of the rectangle, stop if it is negative
int width = input.nextInt();
if ( width < 0 )
throw new RuntimeException("invalid data");
// If there is another number
int height = width;
if ( input.hasNextInt() )
{
// Read the height, stop if it is negative
height = input.nextInt();
if ( height < 0 )
throw new RuntimeException("invalid data");
}
// Read the fill character
char fillChar = input.next().charAt(0);
// Read the boolean that indicates if the rectangle is filled
// We read the boolean as 0 or 1, and stop if something else is given
int filled = input.nextInt();
if ( filled != 0 && filled != 1 )
throw new RuntimeException("invalid data");
boolean isFilled = filled == 1;
// Print each of the height rows
for ( int row = 1; row <= height; ++row )
{
// Print each of the width columns in the row
for ( int column = 1; column <= width; ++column )
{
// If rectangle is filled, or row is first or last one, or column is first or last one
if ( isFilled || row == 1 || row == height || column == 1 || column == width )
{
// Print the fill character
System.out.print(fillChar);
}
else
{
// Print a space
System.out.print(' ');
}
}
// Print a new line
System.out.println();
}
}
catch ( java.util.InputMismatchException exception )
{
System.out.println("invalid data");
}
catch ( java.util.NoSuchElementException exception )
{
System.out.println("missing data");
}
catch ( RuntimeException exception )
{
System.out.println( exception.getMessage() );
}
//
// Close the standard input
input.close();
}
}
]]>
El siguiente ejemplo muestra el resultado de cómo un problema se dividió en varios subproblemas recursivamente. Un subproblema que requiere su propio proceso de análisis, diseño e implementación, es buen canditato para implementarse como una subrutina. Cada subrutina debe tener su propia documentación. Aquí se usa notación JavaDoc.
/**
* Run the solution. This method is called from main()
*/
public void run()
{
// Create object to read data from standard input
input = new Scanner(System.in);
// Read the n, r
long n = input.nextLong();
long r = input.nextLong();
// Print the table header
System.out.printf("%33s%21s%n", "No repetitions", "With repetitions");
// Print permutations
printPermutations(n, r);
// Print combinations
printCombinations(n, r);
// Close the standard input
input.close();
}
/**
* Print the table row for the permutations with and without repetition
*
* @param n The number of elements to choose from. n must be positive
* otherwise, it will print invalid data.
*
* @param r The number of chosen elements from n. r must be positive
*/
public void printPermutations(long n, long r)
{
System.out.print("Permutations");
// Calculate and print permutations without repetition
printPermutationsNoRepetition(n, r);
// Calculate and print permutations with repetition
printPermutationsWithRepetition(n, r);
}
/**
* Calculate and print permutations without repetition
*
* @param n The number of elements to choose from. n must be positive
* otherwise, it will print invalid data.
*
* @param r The number of chosen elements from n. r must be positive
*/
public void printPermutationsNoRepetition(long n, long r)
{
long permutations = factorialDivision(n, n - r);
System.out.printf("%21d", permutations);
}
/**
* Calculate and print permutations with repetition
*
* @param n The number of elements to choose from. n must be positive
* otherwise, it will print invalid data.
*
* @param r The number of chosen elements from n. r must be positive
*/
public void printPermutationsWithRepetition(long n, long r)
{
long permutations = calculatePermutationsWithRepetition(n, r);
System.out.printf("%21d%n", permutations);
}
/**
* Calculate the number of permutations with repetition of r in n as n^r
*
* @see printPermutations() for details about the parameters
*
* @return The amount of permutations
*/
public long calculatePermutationsWithRepetition(long n, long r)
{
long power = 1;
for ( long counter = 1; counter <= r; ++counter )
power = power * n;
return power;
}
/**
* Returns the factorial of an integer number. The factorial of n is
* the multiplication of all integers less or equals to n
*
* @param n The number to get the factorial from. n must be positive,
* otherwise an RuntimeException is thrown. If n is greater than 20
* it will overflow and an invalid result is produced
*
* @return The factorial of n
*/
public long factorial(long n)
{
long factorial = 1;
for ( long counter = 1; counter <= n; ++counter )
{
factorial *= counter;
}
return factorial;
}
/**
* Optimizes the calculus of the division of two factorial parts in the form:
* (numerator)! / (denominator)!
*
* @see factorialDivision(long, long, long)
*/
public long factorialDivision(long numerator, long denominator)
{
/* long factorial = 1;
if ( numerator >= denominator && denominator > 0 )
{
for ( long counter = numerator; counter > 1 && counter > denominator; --counter )
{
factorial *= counter;
}
}
else
{
factorial = 0;
}
return factorial;
*/
return factorialDivision(numerator, denominator, 1);
}
/**
* Optimizes the calculus of the division with three factorial parts in the form:
* (numerator)! / ( (denominator1)! (denominator2)! )
*
* This function cancels the common numerators and denominators before multiply
* them for getting the resulting factorial. Therefore it avoids overfloating
* long values.
*
* @param numerator The numerator before calculating its factorial
* @param denominator1 The first denominator part before calculating its factorial
* @param denominator2 The second denominator part before calculating its factorial
* @return The result of the division n! / (d1! d2!)
*/
public long factorialDivision(long numerator, long denominator1, long denominator2)
{
long factorial = 1;
long minimum = Math.min(denominator1, denominator2);
long maximum = Math.max(denominator1, denominator2);
if ( numerator >= maximum && maximum > 0 )
{
for ( long counter = numerator; counter > maximum; --counter )
{
factorial *= counter;
}
factorial /= factorial(minimum);
}
else
{
factorial = 0;
}
return factorial;
}
/**
* Print the table row for the combinations with and without repetition
*
* @param n The number of elements to choose from. n must be positive
* otherwise, it will print invalid data.
*
* @param r The number of chosen elements from n. r must be positive
*/
public void printCombinations(long n, long r)
{
System.out.print("Combinations");
// Calculate and print combinations without repetition
printCombinationsNoRepetition(n, r);
// Calculate and print combinations with repetition
printCombinationsWithRepetition(n, r);
}
/**
* Calculate and print combinations without repetition
*
* @param n The number of elements to choose from. n must be positive
* otherwise, it will print invalid data.
*
* @param r The number of chosen elements from n. r must be positive
*/
void printCombinationsNoRepetition(long n, long r)
{
long combinations = factorialDivision(n, r, n - r);
System.out.printf("%21d", combinations);
}
/**
* Calculate and print combinations with repetition
*
* @param n The number of elements to choose from. n must be positive
* otherwise, it will print invalid data.
*
* @param r The number of chosen elements from n. r must be positive
*/
void printCombinationsWithRepetition(long n, long r)
{
long combinations = factorialDivision(n + r - 1, r, n - 1);
System.out.printf("%21d", combinations);
}
//
}
]]>
/**
* Run the solution. This method is called from main()
*/
public void run()
{
// Create object to read data from standard input
this.input = new Scanner(System.in);
// This code replicates the input to the standard output
// Modify this code to solve the problem
while ( this.input.hasNextLong() )
{
long number = this.input.nextLong();
testIterativeFactorial(number);
testTailRecursiveFactorial(number);
testRecursiveFactorial(number);
}
// Close the standard input
this.input.close();
}
public void testIterativeFactorial(long number)
{
long start = System.currentTimeMillis();
BigInteger factorial = iterativeFactorial( number );
double duration = (System.currentTimeMillis() - start) / 1000.0;
System.out.printf( "Iterative factorial:%n%,d: %.3fs%n%n", factorial, duration );
}
public void testTailRecursiveFactorial(long number)
{
long start = System.currentTimeMillis();
BigInteger factorial = tailRecursiveFactorial( number );
double duration = (System.currentTimeMillis() - start) / 1000.0;
System.out.printf( "%n%nTail Recursive factorial:%n%,d: %.3fs%n%n", factorial, duration );
}
public void testRecursiveFactorial(long number)
{
long start = System.currentTimeMillis();
BigInteger factorial = recursiveFactorial( number );
double duration = (System.currentTimeMillis() - start) / 1000.0;
System.out.printf( "%n%nRecursive factorial:%n%,d: %.3fs%n%n", factorial, duration );
}
public static BigInteger iterativeFactorial(long number)
{
BigInteger result = BigInteger.valueOf(1);
for ( long current = 1; current <= number; ++current )
result = result.multiply( BigInteger.valueOf(current) );
return result;
}
public static BigInteger recursiveFactorial(long number)
{
if ( number <= 0 )
return BigInteger.valueOf(1);
else
return BigInteger.valueOf(number).multiply( recursiveFactorial(number - 1) );
}
public static BigInteger tailRecursiveFactorial(long number)
{
return tailRecursiveFactorial(number, BigInteger.valueOf(1));
}
public static BigInteger tailRecursiveFactorial(long number, BigInteger accumulator)
{
if ( number <= 0 )
return accumulator;
else
return tailRecursiveFactorial( number - 1, accumulator.multiply( BigInteger.valueOf(number) ) );
}
//
}
]]>
Nota: El compilador de Java no soporta recursión de cola al momento de escribir (nov-2017).
/**
* Run the solution. This method is called from main()
*/
public void run()
{
// Create object to read data from standard input
this.input = new Scanner(System.in);
// This code replicates the input to the standard output
// Modify this code to solve the problem
while ( this.input.hasNextLong() )
{
long number = this.input.nextLong();
System.out.printf("%,d: %,d%n", number, recursiveFibonacci(number));
System.out.printf("%,d: %,d%n%n", number, tailRecursiveFibonacci(number));
}
// Close the standard input
this.input.close();
}
public static BigInteger iterativeFactorial(long number)
{
BigInteger result = BigInteger.valueOf(1);
for ( long current = 1; current <= number; ++current )
result = result.multiply( BigInteger.valueOf(current) );
return result;
}
public static BigInteger recursiveFibonacci(long number)
{
if ( number <= 1 )
return BigInteger.valueOf(number);
else
return recursiveFibonacci(number - 1).add( recursiveFibonacci(number - 2) );
}
public static BigInteger tailRecursiveFibonacci(long number)
{
return tailRecursiveFibonacci(number, BigInteger.valueOf(0), BigInteger.valueOf(1));
}
public static BigInteger tailRecursiveFibonacci(long number, BigInteger previous, BigInteger result)
{
if ( number <= 0 )
return previous;
else if ( number == 1 )
return result;
else
return tailRecursiveFibonacci(number - 1, result, previous.add(result) );
}
//
}
]]>
/**
* Run the solution. This method is called from main()
*/
public void run()
{
// Create object to read data from standard input
this.input = new Scanner(System.in);
// This code replicates the input to the standard output
// Modify this code to solve the problem
while ( this.input.hasNextLong() )
{
BigInteger base = this.input.nextBigInteger();
long exponent = this.input.nextLong();
System.out.printf("%,d^%,d: %,d%n", base, exponent, recursivePower(base, exponent));
System.out.printf("%,d^%,d: %,d%n", base, exponent, efficientTailRecursivePower(base, exponent));
}
// Close the standard input
this.input.close();
}
public static BigInteger iterativeFactorial(long number)
{
BigInteger result = BigInteger.valueOf(1);
for ( long current = 1; current <= number; ++current )
result = result.multiply( BigInteger.valueOf(current) );
return result;
}
public static BigInteger recursivePower(BigInteger base, long exponent)
{
if ( exponent <= 0 )
return BigInteger.valueOf(1);
else
return base.multiply( recursivePower(base, exponent - 1) );
}
public static BigInteger efficientRecursivePower(BigInteger base, long exponent)
{
if ( exponent <= 0 )
return BigInteger.valueOf(1);
else if ( exponent == 1 )
return base;
else if ( exponent % 2 == 0 )
return efficientRecursivePower(base.multiply(base), exponent / 2);
else
return base.multiply( efficientRecursivePower(base, exponent - 1) );
}
public static BigInteger efficientTailRecursivePower(BigInteger base, long exponent)
{
return efficientTailRecursivePower(base, exponent, BigInteger.valueOf(1));
}
public static BigInteger efficientTailRecursivePower(BigInteger base, long exponent, BigInteger result)
{
if ( exponent <= 0 )
return result;
else if ( exponent % 2 == 0 )
return efficientTailRecursivePower(base.multiply(base), exponent / 2, result);
else
return efficientTailRecursivePower(base, exponent - 1, base.multiply(result) );
}
//
}
]]>
1000 o masa <= 0 o altura <= 0 o altura > 300cm
if ( this.person.isValid() )
{
// Los datos son validos
this.person.calculateBodyMassIndex();
this.person.calculateNutritionalState();
// Informar la masa, la altura en centrimetros, y el bmi
System.out.printf("%5.2f %s%n", this.person.getBodyMassIndex(), this.person.getNutritionalState() );
}
else
{
// Informar datos invalidos
System.out.println("invalid data");
}
}
// Close the standard input
input.close();
}
/**
* Read data from standard input and create a Person
*
* @return true if a Person was read from standard input, false if there are no
* more persons in standard input
*/
public boolean readPerson()
{
if ( this.input.hasNextDouble() )
{
// Obtener la masa en kilogramos
double mass = input.nextDouble();
// Obtener la altura en centimetros
double heightCm = input.nextDouble();
// Toma el plano/clase Persona y crea un objeto/instancia
this.person = new Person(mass, heightCm);
// Done
return true;
}
else
{
// No more data to create a person in standard input
return false;
}
}
}
]]>
0.0 && height > 0.0 && height <= 300.0;
}
/**
* Updates the body mass index data member for this person
*/
public void calculateBodyMassIndex()
{
// Convertir la altura a metros
double heightMeters = this.height / 100.0;
// Calcular el indice de masa corporal (bmi)
bodyMassIndex = this.mass / (heightMeters * heightMeters);
}
/**
* Updates the nutritional state data member for this person
*/
public void calculateNutritionalState()
{
// Actualizar el estado nutricional de acuerdo a los rangos de la OMC
if ( bodyMassIndex < 18.5 )
{
// Informar infrapeso
this.nutritionalState = "underweight";
}
if ( bodyMassIndex >= 18.5 && bodyMassIndex < 25.0 )
{
// Informar normal
this.nutritionalState = "normal";
}
if ( bodyMassIndex >= 25.0 && bodyMassIndex < 30.0 )
{
// Informar sobrepeso
this.nutritionalState = "overweight";
}
if ( bodyMassIndex >= 30.0 )
{
// Informar obesidad
this.nutritionalState = "obese";
}
}
}
]]>
Diseño de la solución:
Estructura del proyecto, sus carpetas y archivos:
Las clases deben estar en control de versiones en la carpeta src/ de su proyecto. Se presentan a continuación la clase controladora y la clase modelo.
0 )
{
// Read a triangle from arguments and run in batch, that is,
// do not ask user to type the arguments in standard input
this.runInBatch(args);
}
else
{
// Read triangles from standard input
this.runInteractively();
}
}
/**
* Run interactively, that is, reads triangles from standard
* input until the EOF is reached
*/
public void runInteractively()
{
// Create object to read data from standard input
input = new Scanner(System.in);
// Echoes the standard input
while ( readTriangle() )
{
this.triangle.print();
}
// Close the standard input
input.close();
}
/**
* Creates a Triangle object and read it from standard input
* @return true if the Triangle was read, false otherwise
*/
public boolean readTriangle()
{
// True if a triangle was read, false otherwise
boolean wasRead = false;
// We assume if there is a real, there are also three edges
if ( input.hasNextDouble() )
{
// Create the triangle object and read its edges
this.triangle = new Triangle();
wasRead = this.triangle.read(input);
}
else
{
// There is not more edges in standard input, return false
wasRead = false;
}
return wasRead;
}
/**
* Runs the program in batch mode, that is, read a triangle
* from command line arguments instead of standard input
*
* @param args The command line arguments
*/
public void runInBatch(String args[])
{
// Analyze the given arguments
ArgumentAnalyzer argumentAnalyzer = new ArgumentAnalyzer();
argumentAnalyzer.analyze(args);
// If help was asked, just print it and exit
if ( argumentAnalyzer.wasHelpAsked() )
{
this.printHelp();
}
else
{
// Otherwise, if a valid triangle was given
if ( argumentAnalyzer.hasThreeEdges() )
{
// Create a triangle with the three edges
double edge1 = argumentAnalyzer.getEdge1();
double edge2 = argumentAnalyzer.getEdge2();
double edge3 = argumentAnalyzer.getEdge3();
this.triangle = new Triangle( edge1, edge2, edge3 );
// Print the triangle properties
this.triangle.print();
}
else
{
// Otherwise. Print an error message
System.err.println("Error: insufficient arguments");
}
// If there was other error, report it
if ( argumentAnalyzer.getErrorMessage().length() > 0 )
{
System.err.print( argumentAnalyzer.getErrorMessage() );
}
}
}
/**
* Print usage of this program in standard output
*/
public void printHelp()
{
System.out.println("TriangleInequality v1.1 [2017-Oct-02] Jeisson Hidalgo-Cespedes");
System.out.println("Usage: java TriangleInequality [a b c]");
System.out.println();
System.out.println("Arguments:");
System.out.println(" a b c Edges of the triangle");
System.out.println();
System.out.println("Si no arguments are provided, program will run in interactive mode");
System.out.println("reading triangles from standard input until EOF is provided.");
}
}
]]>
= 3;
}
/**
* Get a copy of the first triangle edge found
* @return Length of first edge
*/
public double getEdge1()
{
return this.edge1;
}
/**
* Get a copy of the second triangle edge found
* @return Length of second edge
*/
public double getEdge2()
{
return this.edge2;
}
/**
* Get a copy of the third triangle edge found
* @return Length of third edge
*/
public double getEdge3()
{
return this.edge3;
}
/**
* Get a reference to the collected error messages found
* while the analysis process is done
*
* @return All error messages concatenated, or empty if no errors
* were collected
*/
public String getErrorMessage()
{
return this.errorMessage;
}
/**
* Start the command line analysis process
* @param arguments The arguments received by main() function
*/
public void analyze(String arguments[])
{
// Traverse all command line arguments
for ( int index = 0; index < arguments.length; ++index )
{
// If help was asked
if ( arguments[index].equals("--help") || arguments[index].equals("-help") )
{
this.helpAsked = true;
}
else if ( analyzeEdge( arguments[index] ) )
{
// Do nothing, the method analyzeEdge updated what is required
}
else
{
// The argument is unknown, report it later
this.errorMessage += "Error: invalid argument: " + arguments[index] + "\n";
}
}
}
/**
* Checks if the given argument text is a triangle's edge value
* If so, the value will be stored in the next free edge attribute
*
* @param argument The text of the argument to be analyzed
* @return true If the argument is an edge, false otherwise
*/
private boolean analyzeEdge(String argument)
{
try
{
// Try to convert the string to double
double edge = Double.parseDouble(argument);
// If reached this line, the string has a valid double value
++this.edgeCount;
// Store the double value as the following edge's length
switch ( this.edgeCount )
{
case 1: this.edge1 = edge; break;
case 2: this.edge2 = edge; break;
case 3: this.edge3 = edge; break;
default:
// We ignore more edges, only first three are parsed
System.err.println("Warning: ignoring argument " + argument);
}
return true;
}
catch ( NumberFormatException exception )
{
// If entered here, the text is not a valid real value, report it
return false;
}
}
}
]]>
0.0 && this.edge2 > 0.0 && this.edge3 > 0.0 )
{
valid = true;
}
return valid;
*/
// The following expression is equivalent to the previous code
// But it is not debugger-friendly
return this.edge1 > 0.0 && this.edge2 > 0.0 && this.edge3 > 0.0;
}
/**
* Indicates if this triangle is actually a triangle if it fulfills the
* triangle inequality principle, that is, each edge is less than the
* sum the other edges.
*
* @return true if this triangle fulfills the triangle inequality principle,
* false otherwise.
*/
public boolean isTriangle()
{
// We assume the triangle does not fulfill the principle
boolean valid = false;
// If any edge is less than the sum of the others
if ( this.edge1 < this.edge2 + this.edge3 )
{
if ( this.edge1 > Math.abs(this.edge2 - this.edge3) )
{
// The triangle fulfills the inequality principle
valid = true;
}
}
return valid;
}
/**
* Prints the perimeter of this triangle, for example:
* P=15
*/
public void printPerimeter()
{
System.out.printf("P=%s", format(this.calculatePerimeter()) );
}
/**
* Calculates the perimeter of this triangle. The perimeter is the
* sum of the three edges of the triangle.
*
* @return The perimeter of this triangle as a real value
*/
public double calculatePerimeter()
{
return this.edge1 + this.edge2 + this.edge3;
}
/**
* Calculates and prints the area of this triangle. For example:
* A=14.28
*/
public void printArea()
{
System.out.printf("A=%s", format(this.calculateArea()) );
}
/**
* Calculates the area of this triangle using its edges through the
* Heron's formula
*
* @return The area of the triangle as a real value
*/
public double calculateArea()
{
// The Heron's formula uses the semiperimeter `s` of the triangle
double semiperimeter = this.calculateSemiperimeter();
// Area is calculated as:
// A = \sqrt{s(s-a)(s-b)(s-c)}
// where `s` is semiperimeter and `a, b, c` are the triangle's edges
double subradical = semiperimeter
* (semiperimeter - this.edge1)
* (semiperimeter - this.edge2)
* (semiperimeter - this.edge3);
return Math.sqrt(subradical);
}
/**
* Calculates the semiperimeter of this triangle. The semiperimeter
* is half of perimeter
*
* @return The semiperimeter of this triangle as a real value
*/
public double calculateSemiperimeter()
{
return this.calculatePerimeter() / 2.0;
}
/**
* Prints the classification of this triangle according to its edges
* @see getCategoryByEdge()
*/
public void printCategoryByEdge()
{
System.out.print( this.getCategoryByEdge() );
}
/**
* Returns a String indicating the classification of this triangle according
* to its edges. The returned text is in Spanish. Possible values are:
* "equilatero", "isosceles", or "escaleno".
*/
public String getCategoryByEdge()
{
String category = "";
// Compare the lengths of the sides
if ( this.edge1 == this.edge2 && this.edge2 == this.edge3 )
{
// All edges are equal, we have an equilateral triangle
category = "equilatero";
}
else if ( this.edge1 == this.edge2 || this.edge1 == this.edge3 || this.edge2 == this.edge3 )
{
// Only two edges are equal, we have an isosceles triangle
category = "isosceles";
}
else
{
// Otherwise, we assume a scalene triangle
category = "escaleno";
}
return category;
}
/**
* Prints the classification of this triangle according to its angles
* @see getCategoryByAngle()
*/
public void printCategoryByAngle()
{
System.out.print( this.getCategoryByAngle() );
}
/**
* Returns a String indicating the classification of this triangle according
* to its angles. The returned text is in Spanish. Possible values are:
* "obtusangulo", "rectangulo", or "acutangulo".
*/
public String getCategoryByAngle()
{
// We need to find the hypotenuse and the two cathetus
MutableDouble hypotenuse = new MutableDouble(0.0);
MutableDouble cathetus1 = new MutableDouble(0.0);
MutableDouble cathetus2 = new MutableDouble(0.0);
// Find the hypotenuse and the two cathetus objects
// This method will modify the objects referred by parameter
findHypotenuseAndCathetuses(hypotenuse, cathetus1, cathetus2);
// Text indicating the classification of this triangle according to angles
String category = "";
// We use the Pythagorean theorem to check the type of triangle
// We square each edge for convenience
double squaredHypotenuse = hypotenuse.getValue() * hypotenuse.getValue();
double squaredCathetus1 = cathetus1.getValue() * cathetus1.getValue();
double squaredCathetus2 = cathetus2.getValue() * cathetus2.getValue();
// We compare the squares of the hypotenuse and sum of squared cathetus
if ( squaredHypotenuse == squaredCathetus1 + squaredCathetus2 )
{
// Edges fulfill the Pythagorean theorem, it is a rectangled triangle
category = "rectangulo";
}
else if ( squaredHypotenuse > squaredCathetus1 + squaredCathetus2 )
{
// Hypotenuse area is larger than cathetus area, is an obtuse triangle
category = "obtusangulo";
}
else
{
// Otherwise, we assume it is an acute triangle
category = "acutangulo";
}
return category;
}
/**
* Finds the largest edge of the triangle (hypotenuse) and the two smaller edges
* and set the given objects to these results.
*
* @param hypotenuse This object will be modified to have the hypotenuse's length
* @param cathetus1 This object will be modified to have a cathetus's length
* @param cathetus2 This object will be modified to have a cathetus's length
*/
public void findHypotenuseAndCathetuses(MutableDouble hypotenuse, MutableDouble cathetus1, MutableDouble cathetus2)
{
// Test each edge against the remaining two looking for the largest
if ( this.edge1 > this.edge2 && this.edge1 > this.edge3 )
{
// The edge1 is larger than edge2 and edge3, it is the hypotenuse
hypotenuse.setValue(this.edge1);
cathetus1.setValue(this.edge2);
cathetus2.setValue(this.edge3);
}
else if ( this.edge2 > this.edge1 && this.edge2 > this.edge3 )
{
// The edge2 is larger than edge1 and edge3, it is the hypotenuse
hypotenuse.setValue(this.edge2);
cathetus1.setValue(this.edge1);
cathetus2.setValue(this.edge3);
}
else
{
// The edge3 must be larger than edge1 and edge2, it is the hypotenuse
hypotenuse.setValue(this.edge3);
cathetus1.setValue(this.edge1);
cathetus2.setValue(this.edge2);
}
}
}
]]>
Solution.java. Obtener código fuente.Persona. Obtener código fuente.Estudiante. Obtener código fuente.Funcionario. Obtener código fuente.Profesor. Obtener código fuente.Administrativo. Obtener código fuente.Una clase arreglo dinámico puede crecer. En Java la clase de biblioteca ArrayList realiza esta funcionalidad.
En el siguiente ejemplo, la clase controladora Solution usa el arreglo dinámico para calcular la mediana sin saber la cantidad de datos que vienen en la entrada estándar.
Solution. Obtener código fuente. index; --current )
{
this.elements[current] = this.elements[current - 1];
}
this.elements[index] = element;
++this.count;
}
public int getCount()
{
return this.count;
}
public int getCapacity()
{
return this.elements.length;
}
public double getAt(int index)
{
return this.elements[index];
}
private void increaseCapacity()
{
double[] newElements = new double[ INCREASE_FACTOR * this.getCapacity() ];
for ( int index = 0; index < this.count; ++index )
{
newElements[index] = this.elements[index];
}
this.elements = newElements;
}
public void sort()
{
Arrays.sort( this.elements, 0, this.getCount() );
}
public void bubbleSort()
{
int changes = -1;
int pass = 0;
//for ( int pass = 0; pass < this.getCount(); ++pass )
while ( changes != 0 )
{
changes = 0;
for ( int index = 1; index < this.getCount() - pass; ++index )
{
if ( this.elements[index - 1] > this.elements[index] )
{
this.swap(index - 1, index);
++changes;
}
}
++pass;
}
}
private void swap(int index1, int index2)
{
double copy1 = this.elements[index1];
this.elements[index1] = this.elements[index2];
this.elements[index2] = copy1;
}
/**
* Sequential search in O(n)
* @param element
* @return
*/
public int searchFirst(double element)
{
int position = -1;
for ( int index = 0; index < this.getCount() && position == -1; ++index )
{
if ( this.elements[index] == element )
{
position = index;
}
}
return position;
}
public int binarySearch(double element)
{
int low = 0;
int high = this.getCount();
while ( low < high )
{
int middle = (low + high) / 2;
if ( element == this.elements[middle] )
return middle;
else if ( element < this.elements[middle] )
high = middle;
else
low = middle + 1;
}
return -1;
}
}
]]>
Una clase que administra una matriz, de dimensiones arbitrarias, y realiza operaciones matemáticas comunes de las matrices.
0 && columns > 0 )
{
// Dimensions are valid, create the actual matrix
this.matrix = new double[rows][columns];
}
}
/**
* Read the dimensions and values from the given input
* @param matrix
*/
public void read(Scanner input)
{
// Read the dimensions of the matrix
int rows = input.nextInt();
int cols = input.nextInt();
// Create the matrix in heap, and keep a reference
this.matrix = new double[rows][cols];
// Read all values for the matrix
for ( int row = 0; row < this.matrix.length; ++row )
{
// Read all values for current row
for ( int col = 0; col < this.matrix[row].length; ++col )
{
this.matrix[row][col] = input.nextDouble();
}
}
}
/**
* Print this matrix in the given output
* @param output The file where print this matrix
*/
public void print(PrintStream output)
{
// Print each row
for ( int row = 0; row < matrix.length; ++row )
{
// Print each column in the current row
for ( int col = 0; col < matrix[row].length; ++col )
{
// Print the cell value
output.printf("%.2f ", matrix[row][col]);
}
// Separate this row from next by a new line character
output.println();
}
}
/**
* Adds this matrix with another
*
* @param other Other matrix to be added with this
* @return A reference to the resulting matrix object containing
* the sum of this and the other matrix. If matrixes have different
* dimensions, a null reference will be retorned
*/
public Matrix add(Matrix other)
{
// The resulting matrix of adding this one with other
Matrix result = null;
// Only matrixes of same size can be added
if ( this.matchesSize(other) )
{
// Create the matrix object to store the resulting sum
result = new Matrix( this.getRowCount(), this.getColumnCount() );
// Add the rows of both matrixes. Because the three matrixes
// (this, other, and result) have the same dimensions, we can use
// the dimensions of anyone to control the loops
for ( int row = 0; row < this.matrix.length; ++row )
{
// Add all columns in this row
for ( int col = 0; col < this.matrix[row].length; ++col )
{
// The result cell is the sum of respectives cells in
// this and other matrixes
result.matrix[row][col] = this.matrix[row][col] + other.matrix[row][col];
}
}
}
// Notice that we return null if matrixes do not match their size
return result;
}
/**
* Returns true if this matrix and other have the same amount of
* rows and columns
*
* @param other Other matrix to be checked against this for size
* @return true if this matrix and other have the same dimensions
*/
public boolean matchesSize(Matrix other)
{
return this.getRowCount() == other.getRowCount()
&& this.getColumnCount() == other.getColumnCount();
}
/**
* Return the number of rows that this matrix has
* @return The number of rows, 0 if this is an invalid matrix
*/
public int getRowCount()
{
return this.matrix != null ? this.matrix.length : 0;
}
/**
* Return the number of columns that this matrix has
* @return The number of rows, 0 if this is an invalid matrix
*/
public int getColumnCount()
{
// Avoid to check lengths for null matrix references
// We assume all rows have the same amount of columns,
// therefore, we use the first row length
return this.matrix != null && this.matrix.length > 0 ? this.matrix[0].length : 0;
}
}
]]>
0 )
{
students.append( name );
}
}
students.print( System.out );
// Close the standard input
this.input.close();
}
}
]]>
0 )
{
// The key to be inserted must go in the right subtree
// Check if we alread have a right subtree
if ( this.right == null )
{
// We do not have a right subtree, create the node there
this.right = new Node(key, value);
}
else
{
// We already have a right subtree, insert the node there
this.right.insert(key, value);
}
}
// else: notice we insert repeated keys in the tree, so it can
// have multiple values for a same key. If we forbid this
// behavior, we will have a set (in mathematical sense).
}
/**
* Print this tree in in-order, which gives alphabetical order
* @param out
*/
public void print(PrintStream out)
{
// First, print the entire left subtree recursively
// because all its keys are less than mine
if ( this.left != null ) { this.left.print(out); }
// Second, print myself because I am the next
out.printf("%s\t%s%n", this.key, this.value);
// Third, print the entire right subtree recursively
// because all its keys are greater than mine
if ( this.right != null ) { this.right.print(out); }
}
/**
* Finds the value for the given key. This method
* will do log_2(n) comparisons if the tree is balanced
*
* @param key The key to be searched
* @return The corresponding value for the key, null if
* the key is not found in the tree
*/
public String findValue(String key)
{
// Compare the searched key with my key. E.g: if searching
// for "board" and I have "body", it will produce:
// "board".compareTo("body") == -3
int comparison = key.compareTo(this.key);
// If both keys are identical
if ( comparison == 0 )
{
// I have the value for that key, return it
return this.value;
}
else if ( comparison < 0 )
{
// The searched key must be in the left subtree
if ( this.left == null )
{
// But I do not have a left subtree, stop here
return null;
}
else
{
// I have a left subtree, search there
return this.left.findValue(key);
}
}
else
{
// The searched key must be in the right subtree
if ( this.right == null )
{
// But I do not have a right subtree, stop here
return null;
}
else
{
// I have a right subtree, search there
return this.right.findValue(key);
}
}
} // findValue()
} // class Node
/**
* A tree simply has a reference to the root node.
* If this reference is null, the tree is empty
*/
private Node root = null;
/**
* The number of elements stored in the tree
*/
private long count = 0;
/**
* Return true if this tree is empty
* @return true if the tree is empty, false otherwise
*/
public boolean isEmpty()
{
return root == null;
}
/**
* Return the count of elements currently stored in the tree
* @return The count of elements
*/
public long getCount()
{
return this.count;
}
/**
* Insert the given pair (key,value) in the tree
* @param key The key to be stored
* @param value The value to be stored
*/
public void insert(String key, String value)
{
// The insertion depends on if the tree is empty
if ( this.isEmpty() )
{
// The tree is empty, make the new pair the root
this.root = new Node(key, value);
}
else
{
// The tree has elements, ask the root to insert
// the pair (key,value) in its place
this.root.insert(key, value);
}
// We have one more element stored in the tree
++this.count;
}
/**
* Prints this tree to the given output in alphabetical order
* @param out The file were the tree will be printed
*/
public void print(PrintStream out)
{
// We can only print a tree if it has values
if ( ! this.isEmpty() )
{
// Print the nodes recursively
this.root.print(out);
}
}
/**
* Finds the value for the given key. This method
* will do log_2(n) comparisons if the tree is balanced
*
* @param key The key to be searched
* @return The corresponding value for the key, null if
* the key is not found in the tree
*/
public String findValue(String key)
{
// The search depends on if the tree is empty
if ( this.isEmpty() )
{
// The tree is empty, we do not have a value for the key
return null;
}
else
{
// We have elements in the tree, search for the value
// recursively
return this.root.findValue(key);
}
}
}
]]>
El archivo TrainLaneGame.zip contiene el proyecto completo, que incluye el código fuente, imágenes, archivos de configuración de Eclipse.
cellWidth )
{
this.timerCarAnimation.stop();
this.movingCarX = 0;
this.movingCarRow = this.movingCarColumn = -1;
}
}
else
{
g.drawImage(this.obstacle
, x + paddingHorizontal, y + paddingVertical
, cellWidth - 2 * paddingHorizontal, cellHeight - 2 * paddingVertical, null);
}
}
}
}
}
/**
* Invoked when an action occurs.
*/
@Override
public void actionPerformed(ActionEvent event)
{
if ( event.getSource() == this.timerCarAnimation )
{
this.repaint();
}
}
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
*/
@Override
public void mouseClicked(MouseEvent event)
{
int cellWidth = this.getWidth() / obstacleMatrix.getColumnCount();
int cellHeight = this.getHeight() / obstacleMatrix.getRowCount();
int row = event.getY() / cellHeight;
int column = event.getX() / cellWidth;
System.out.printf("mouseClicked(%d,%d)%n", event.getX(), event.getY());
System.out.printf("Obstacle(%d,%d)%n", row + 1, column + 1);
this.movingCarRow = row;
this.movingCarColumn = column;
this.movingCarX = -5;
this.timerCarAnimation.start();
}
@Override
public void mousePressed(MouseEvent event)
{
// TODO Auto-generated method stub
// System.out.printf("mousePressed(%d,%d)%n", event.getX(), event.getY());
}
@Override
public void mouseReleased(MouseEvent event)
{
// TODO Auto-generated method stub
// System.out.printf("mouseReleased(%d,%d)%n", event.getX(), event.getY());
}
@Override
public void mouseEntered(MouseEvent event)
{
// TODO Auto-generated method stub
// System.out.printf("mouseEntered(%d,%d)%n", event.getX(), event.getY());
}
@Override
public void mouseExited(MouseEvent event)
{
// TODO Auto-generated method stub
// System.out.printf("mouseExited(%d,%d)%n", event.getX(), event.getY());
}
}
]]>