La siguiente opción del menú habla de registrar las tres vueltas de la competencia en la que participan cada uno de los deportistas.
No se nos indica de que manera debemos registrar y relacionar las vueltas con los deportistas, así que lo decidimos nosotros.
Hay múltiples formas: una matriz paralela al ArrayList de deportistas, agregar nuevos atributos a los deportistas,...
Tampoco nos dicen cómo hemos de recoger los tiempos de las vueltas: ¿en minutos, en segundos, en minutos y segundos....?
Creo que por equilibrio entre sencillez y lógica, podemos pedir al usuario minutos y segundos por separado.
De hecho, podemos crear una clase llamada
Vuelta con esos dos atributos, minutos y segundos.
Luego se nos va a pedir comparar los tiempos de unas vueltas con otras, en este caso si puede resultarnos más cómodo tratar el tiempo total en solo segundos para que sea más fácil comparar. Así que podemos darle a esta clase
Vuelta un método que haga este cálculo.
También podemos sobreescribirle el método toString() para que así una Vuelta sepa darnos un String que representa sus tiempos con un formato adecuado
public class Vuelta {
private int minutos;
private int segundos;
public Vuelta() {
minutos = 0;
segundos = 0;
}
public Vuelta(int minutos, int segundos) {
this.minutos = minutos;
this.segundos = segundos;
}
public int getMinutos() {
return minutos;
}
public void setMinutos(int minutos) {
this.minutos = minutos;
}
public int getSegundos() {
return segundos;
}
public void setSegundos(int segundos) {
this.segundos = segundos;
}
/*
* Para comparar tiempos de distintas vueltas,
* puede ser más cómodo convertir el tiempo
* en segundos totales.
*/
public int totalSegundos() {
return (minutos * 60) + segundos;
}
@Override
public String toString() {
return String.format("[%02d:%02d]", minutos, segundos);
}
}
Vale, ahora ya tenemos una clase donde recoger tiempos de vueltas. ¿Cómo las relacionamos con los deportistas?
Cada deportista realizará tres vueltas, y solo tres, así que por ahora (quizás luego cambie de opinión) creo que lo más cómodo es modificar la clase
Deportista para que tenga un nuevo atributo, que será un array de tres objetos
Vuelta.
En su constructor inicializaremos el array con tres Vueltas con tiempo 0, aunque solo será por no dejar el array con valores null en ningún momento.
Luego los valores de las vueltas, se los haremos llegar (por comodidad) por un setter que machacará el array anterior. Así que en realidad no sería necesario inicializarlo al crear un
Deportista, pero no me gusta dejar atributos con valores null si no hay un motivo lógico.
La clase Deportista queda así cambiada:
public class Deportista {
private String codigo;
private String nombre;
private int edad;
private String nivel;
private String sexo;
//Las vueltas que realiza el deportista
private Vuelta[] vueltas;
public Deportista(String codigo, String nombre, int edad, String nivel, String sexo) {
this.codigo = codigo;
this.nombre = nombre;
this.edad = edad;
this.nivel = nivel;
this.sexo = sexo;
//Un competidor realiza 3 vueltas
vueltas = new Vuelta[3];
for (int i = 0; i < 3; i++)
vueltas = new Vuelta();//Inicialmente las vueltas tienen los tiempos en 0
}
public String getCodigo() {
return codigo;
}
public void setCodigo(String codigo) {
this.codigo = codigo;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
public String getNivel() {
return nivel;
}
public void setNivel(String nivel) {
this.nivel = nivel;
}
public String getSexo() {
return sexo;
}
public void setSexo(String sexo) {
this.sexo = sexo;
}
/*
* Los tiempos de vueltas llegarán ya coleccionadas
* en un array que machará el actual.
*/
public void setVueltas(Vuelta[] vueltas) {
this.vueltas = vueltas;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Deportista) {
//Dos deportistas son equivalentes si tienen el mismo codigo
Deportista otroDepor = (Deportista) obj;
return otroDepor.codigo.equals(codigo);
}
else
return false;
}
}
Con esto, ya podemos hacer el punto 4 del menú.
Para ello a la clase principal le añadimos una nueva función que, tras comprobar si hay deportistas registrados, pida los tiempos de tres vueltas y luego pida el código del deportista al que quiere asignarle esos tiempos.
private static void registrarVueltas() {
if (deportistas.isEmpty())
System.out.println("No hay deportistas registrados."
+ "\nNo se pueden registar tiempos de vueltas.");
else {
Vuelta[] vueltas = new Vuelta[3];
System.out.println("\n\tREGISTRAR COMPETENCIA");
System.out.println("Introduzca los tiempos de tres vueltas");
for (int i = 0; i < 3; i++) {
System.out.println("Vuelta #" + (i+1));
System.out.print("Minutos: ");
int minutos = Integer.parseInt(teclado.nextLine());
System.out.print("Segundos: ");
int segundos = Integer.parseInt(teclado.nextLine());
vueltas[i] = new Vuelta(minutos, segundos);
}
//Ahora preguntamos a que Deportista se las asignamos
System.out.print("\nIndique el codigo del Deportista: ");
String codigo = teclado.nextLine();
Deportista buscado = null;
for (int i = 0; i < deportistas.size(); i++)
if (deportistas.get(i).getCodigo().equals(codigo))
buscado = deportistas.get(i);
if (buscado == null)
System.out.println("\nNo existe deportista con el codigo: " + codigo);
else {
buscado.setVueltas(vueltas);
System.out.println("\nTiempos de vueltas se han asignado al deportista.");
}
}
}
Añadimos nueva opción al menú y por supuesto al switch del main() para poder llevarla a cabo:
do {
mostrarMenu();
opcion = Integer.parseInt(teclado.nextLine());
switch(opcion) {
case 0:
System.out.println("\nFIN DE PROGRAMA");
break;
case 1:
registrarDeportista();
break;
case 2:
eliminarDeportista();
break;
case 3:
modificarDeportista();
break;
case 4:
registrarVueltas();
break;
default:
System.out.println("\nOpcion equivocada");
}
}while (opcion != 0);
Si continuamos con la siguiente opción del menú, la 5, nos pide obtener el tiempo promedio de cada deportista en realizar las tres vueltas.
Para esto, primero le vamos a enseñar a la clase
Deportista a retornar el tiempo promedio.
Para esto nos será útil el poder convertir los tiempos a segundos, calcular el promedio, y dicho promedio reconvertirlo a minutos y segundos para poder presentarlo en pantalla debidamente formateado.
Así que a la clase
Deportista le añadimos los siguientes métodos:
Uno se encargará de calcular el promedio, en segundos. Hay más opciones del menú que dependen de este cálculo, así que va bien tener un método específico para esta tarea y que otros métodos puedan recurrir a él.
/*
* El tiempo promedio se retorna calculado
* en segundos
*/
public int tiempoPromedio() {
int segundosTotales = 0;
for (Vuelta v: vueltas)
segundosTotales += v.totalSegundos();
return segundosTotales / 3;
}
Otro método será el que se encargue de retornar un String para mostrar en pantalla el tiempo promedio.
Para esto, se ha de transformar el promedio en minutos y segundos. Con estos dos elemenos, podemos construir un objeto Vuelta e invocar a su método toString(), al que anteriormente ya le enseñamos a como ha de formatear un tiempo de vuelta para mostrarlo en pantalla.
Pero, ¡¡atención!!...
Pueden haber deportistas que aún no hayan competido, es decir, que no tengan tiempos de vueltas registrados.
En ese caso, convendría mostrar un mensaje en pantalla y no un tiempo.
Hay que distinguir entre los que han competido y los que no, para tratarlos de distinta manera.
Una forma de saberlo, es aprovechar el método calcularPromedio(). Si retorna un valor de 0, que es el tiempo de las vueltas al inicializarse, es que no se le han registrado nuevas Vueltas todavía y por tanto no ha competido el deportista en cuestión.
Podemos hacer otro método boolean que basándose en el promedio, retorne verdadero o falso para indicar si ha competido o no este deportista.
/*
* Para saber si un Deportista ha competido podemos comprobar
* si su tiempo promedio es distinto de 0
*/
public boolean haCompetido() {
return tiempoPromedio() != 0;
}
Y ahora sí, podemos hacer el método que mostrará el tiempo promedio en pantalla si el deportista ha competido, y si no, mostrará un mensaje
/*
* Para mostrar en pantalla el tiempo promedio
* bien formateado, hay que convertir a minutos y segundos
* para poder construir un objeto Vuelta
*/
public String mostrarPromedio() {
if (haCompetido()) {
int promedio = tiempoPromedio();
int minutos = promedio / 60;
int segundos = promedio % 60;
//El objeto Vuelta ya sabe como mostrarse en pantalla formateado
return new Vuelta(minutos, segundos).toString();
}
else
return "No ha competido.";
}
Con esto, ya podemos volver a la clase principal y añadir nueva función que se encargue de recorrer los deportistas registrados y mostrar sus tiempos promedios:
private static void mostrarPromedios() {
System.out.println("\n\tTIEMPOS PROMEDIOS");
System.out.println("\t------- ---------");
if (deportistas.isEmpty())
System.out.println("No hay deportistas registrados todavía");
else {
for (Deportista dpt: deportistas) {
System.out.println("\n\t---------------------------");
System.out.println("Codigo: " + dpt.getCodigo());
System.out.println("Nombre: " + dpt.getNombre());
System.out.println("Tiempo promedio: " + dpt.mostrarPromedio());
System.out.println("\t---------------------------");
}
}
}
Tras esto, actualizamos el menú y el switch para disponer de esta nueva opción.
Y si la ejecutamos, veremos en pantalla que se muestran los tiempos promedios de aquellos que han competido y los que no, se muestra un mensaje.
TIEMPOS PROMEDIOS
------- ---------
---------------------------
Codigo: DEP001
Nombre: Lucas
Tiempo promedio: [01:03]
---------------------------
---------------------------
Codigo: DEP002
Nombre: Sara
Tiempo promedio: [00:59]
---------------------------
---------------------------
Codigo: DEP003
Nombre: Ramon
Tiempo promedio: No ha competido.
---------------------------
---------------------------
Codigo: DEP004
Nombre: Laura
Tiempo promedio: [01:05]
---------------------------
Continuaremos en un próximo mensaje.