Hagamos esto otra vez pues hubieron cosas que cambiaron
Quiero que actúes como un asistente experto en ingeniería de software y análisis de código Java.
Tengo un proyecto de un juego desarrollado completamente en Java con JavaFX, titulado "Caza del Tesoro en Islas", cuya lógica gira en torno a un grafo de islas conectadas por rutas marítimas. Con clases como Isla, Boat, GameController, etc.
Tu tarea es la siguiente:
Clases involucradas:
ClaseAClaseBMétodos clave:
metodoX() en ClaseA: [Explicación]metodoY() en ClaseB: [Explicación]Descripción detallada:
Explica qué hace esta funcionalidad, qué problema resuelve y cómo se relaciona con otras partes del juego.
Tests sugeridos con JUnit:
@Test
void testNombreMetodo() {
// descripción del caso de prueba
...
}
Basándome en el código del proyecto "Caza del Tesoro en Islas", aquí está la división en funcionalidades lógicas ordenadas cronológicamente:
Clases involucradas:
Vertice<V>Arista<V>Métodos clave:
Vertice(V valor) en Vertice: Constructor que inicializa un vértice con un valor genéricogetValor() en Vertice: Retorna el valor almacenado en el vérticeequals() y hashCode() en Vertice: Implementan comparación e identificación únicaArista(V origen, V destino, double peso) en Arista: Constructor que crea una arista con origen, destino y pesogetOrigen(), getDestino(), getPeso() en Arista: Métodos de acceso a los componentes de la aristaDescripción detallada: Esta funcionalidad establece las estructuras básicas para representar los elementos fundamentales de un grafo: vértices y aristas. Los vértices encapsulan cualquier tipo de dato genérico, mientras que las aristas representan conexiones ponderadas entre dos vértices. Estas clases son inmutables en su estructura principal y proporcionan métodos de comparación necesarios para su uso en colecciones.
Tests sugeridos con JUnit:
@Test
void testVerticeCreacion() {
// Verificar que un vértice se crea correctamente
String valor = "TestValue";
Vertice<String> vertice = new Vertice<>(valor);
assertEquals(valor, vertice.getValor());
}
@Test
void testVerticeEquality() {
// Verificar que dos vértices con el mismo valor son iguales
Vertice<Integer> v1 = new Vertice<>(1);
Vertice<Integer> v2 = new Vertice<>(1);
assertEquals(v1, v2);
assertEquals(v1.hashCode(), v2.hashCode());
}
@Test
void testAristaCreacion() {
// Verificar que una arista se crea correctamente
String origen = "A";
String destino = "B";
double peso = 5.0;
Arista<String> arista = new Arista<>(origen, destino, peso);
assertEquals(origen, arista.getOrigen());
assertEquals(destino, arista.getDestino());
assertEquals(peso, arista.getPeso());
}
@Test
void testAristaEquality() {
// Verificar que dos aristas idénticas son iguales
Arista<String> a1 = new Arista<>("A", "B", 5.0);
Arista<String> a2 = new Arista<>("A", "B", 5.0);
assertEquals(a1, a2);
}Clases involucradas:
Grafo<V> (interfaz)Métodos clave:
agregarVertice(V vertice): Define la operación para añadir un vértice al grafoagregarArista(V origen, V destino, double peso): Define la operación para conectar dos vérticesobtenerVertices(): Define cómo obtener todos los vértices del grafoobtenerVecinos(V vertice): Define cómo obtener los vértices adyacentescaminoMasCorto(V origen, V destino): Define la operación para encontrar el camino más cortogenerarArbolRecubrimientoMinimo(): Define la operación para generar el MSTDescripción detallada: Esta funcionalidad define el contrato que deben cumplir todas las implementaciones de grafo en el sistema. Establece las operaciones fundamentales que cualquier estructura de grafo debe soportar, incluyendo manipulación de vértices y aristas, consultas de conectividad, y algoritmos avanzados como búsqueda de caminos más cortos y generación de árboles de recubrimiento mínimo.
Tests sugeridos con JUnit:
// Nota: Como es una interfaz, los tests se realizarán en las implementaciones concretas
// Aquí se definen los contratos que deben cumplir todas las implementaciones
@Test
void testContratoAgregarVertice() {
// Verificar que después de agregar un vértice, este existe en el grafo
// Este test se implementará en cada clase concreta
}
@Test
void testContratoAgregarArista() {
// Verificar que después de agregar una arista, existe conexión entre vértices
// Este test se implementará en cada clase concreta
}
@Test
void testContratoObtenerVecinos() {
// Verificar que los vecinos retornados son correctos
// Este test se implementará en cada clase concreta
}Clases involucradas:
GrafoListaAdyacencia<V>Métodos clave:
agregarVertice(V vertice) en GrafoListaAdyacencia: Añade un vértice al mapa de listas de adyacenciaagregarArista(V origen, V destino, double peso) en GrafoListaAdyacencia: Crea aristas bidireccionales en las listasobtenerVecinos(V vertice) en GrafoListaAdyacencia: Retorna los destinos de las aristas de un vérticeobtenerPeso(V origen, V destino) en GrafoListaAdyacencia: Busca el peso de una arista específicaexisteArista(V origen, V destino) en GrafoListaAdyacencia: Verifica si existe conexión entre dos vérticesDescripción detallada: Esta funcionalidad implementa un grafo no dirigido usando listas de adyacencia. Cada vértice mantiene una lista de todas sus aristas salientes. Esta implementación es eficiente en memoria para grafos dispersos y permite acceso rápido a los vecinos de cualquier vértice. Las aristas se almacenan en ambas direcciones para mantener la propiedad de grafo no dirigido.
Tests sugeridos con JUnit:
@Test
void testAgregarVerticeListaAdyacencia() {
// Verificar que un vértice se agrega correctamente
GrafoListaAdyacencia<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarVertice("A");
assertTrue(grafo.obtenerVertices().contains("A"));
assertEquals(1, grafo.numeroVertices());
}
@Test
void testAgregarAristaListaAdyacencia() {
// Verificar que una arista se agrega en ambas direcciones
GrafoListaAdyacencia<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 5.0);
assertTrue(grafo.existeArista("A", "B"));
assertTrue(grafo.existeArista("B", "A"));
assertEquals(5.0, grafo.obtenerPeso("A", "B"));
assertEquals(5.0, grafo.obtenerPeso("B", "A"));
}
@Test
void testObtenerVecinosListaAdyacencia() {
// Verificar que se obtienen correctamente los vecinos
GrafoListaAdyacencia<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 1.0);
grafo.agregarArista("A", "C", 2.0);
List<String> vecinos = grafo.obtenerVecinos("A");
assertEquals(2, vecinos.size());
assertTrue(vecinos.contains("B"));
assertTrue(vecinos.contains("C"));
}
@Test
void testObtenerAristasListaAdyacencia() {
// Verificar que no se duplican aristas en grafo no dirigido
GrafoListaAdyacencia<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 1.0);
grafo.agregarArista("B", "C", 2.0);
List<Arista<String>> aristas = grafo.obtenerAristas();
assertEquals(2, aristas.size());
}Clases involucradas:
GrafoMatrizAdyacencia<V>Métodos clave:
agregarVertice(V vertice) en GrafoMatrizAdyacencia: Asigna un índice al vértice y expande la matriz si es necesarioexpandirMatriz() en GrafoMatrizAdyacencia: Duplica el tamaño de la matriz cuando se alcanza la capacidadagregarArista(V origen, V destino, double peso) en GrafoMatrizAdyacencia: Establece el peso en ambas posiciones de la matrizobtenerVecinos(V vertice) en GrafoMatrizAdyacencia: Recorre la fila de la matriz buscando conexionesobtenerPeso(V origen, V destino) en GrafoMatrizAdyacencia: Acceso directo O(1) al peso usando índicesDescripción detallada: Esta funcionalidad implementa un grafo no dirigido usando una matriz de adyacencia. Mantiene mapas bidireccionales entre vértices e índices para acceso eficiente. La matriz se expande dinámicamente cuando se necesita más capacidad. Esta implementación ofrece acceso O(1) a los pesos de las aristas pero consume más memoria, especialmente en grafos dispersos.
Tests sugeridos con JUnit:
@Test
void testAgregarVerticeMatrizAdyacencia() {
// Verificar que un vértice se agrega correctamente
GrafoMatrizAdyacencia<String> grafo = new GrafoMatrizAdyacencia<>(5);
grafo.agregarVertice("A");
assertTrue(grafo.obtenerVertices().contains("A"));
assertEquals(1, grafo.numeroVertices());
}
@Test
void testExpansionMatriz() {
// Verificar que la matriz se expande correctamente
GrafoMatrizAdyacencia<Integer> grafo = new GrafoMatrizAdyacencia<>(2);
// Agregar más vértices que la capacidad inicial
for (int i = 0; i < 5; i++) {
grafo.agregarVertice(i);
}
assertEquals(5, grafo.numeroVertices());
// Verificar que las aristas funcionan después de la expansión
grafo.agregarArista(0, 4, 10.0);
assertTrue(grafo.existeArista(0, 4));
}
@Test
void testAgregarAristaMatrizAdyacencia() {
// Verificar que una arista se agrega en ambas direcciones
GrafoMatrizAdyacencia<String> grafo = new GrafoMatrizAdyacencia<>(5);
grafo.agregarArista("A", "B", 7.0);
assertTrue(grafo.existeArista("A", "B"));
assertTrue(grafo.existeArista("B", "A"));
assertEquals(7.0, grafo.obtenerPeso("A", "B"));
assertEquals(7.0, grafo.obtenerPeso("B", "A"));
}
@Test
void testObtenerVecinosMatrizAdyacencia() {
// Verificar que se obtienen correctamente los vecinos
GrafoMatrizAdyacencia<String> grafo = new GrafoMatrizAdyacencia<>(5);
grafo.agregarArista("A", "B", 1.0);
grafo.agregarArista("A", "C", 2.0);
List<String> vecinos = grafo.obtenerVecinos("A");
assertEquals(2, vecinos.size());
assertTrue(vecinos.contains("B"));
assertTrue(vecinos.contains("C"));
}Clases involucradas:
DijkstraMétodos clave:
encontrarCaminoMasCorto(Grafo<V> grafo, V origen, V destino) en Dijkstra: Implementa el algoritmo de DijkstrareconstruirCamino(Map<V, V> predecesores, V origen, V destino) en Dijkstra: Reconstruye el camino desde los predecesoresDescripción detallada: Esta funcionalidad implementa el algoritmo de Dijkstra para encontrar el camino más corto entre dos vértices en un grafo con pesos positivos. Utiliza una cola de prioridad para seleccionar siempre el vértice con menor distancia acumulada. Mantiene un mapa de predecesores para poder reconstruir el camino completo una vez encontrado el destino.
Tests sugeridos con JUnit:
@Test
void testCaminoMasCortoDirecto() {
// Verificar camino directo entre dos vértices
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 5.0);
List<String> camino = Dijkstra.encontrarCaminoMasCorto(grafo, "A", "B");
assertEquals(2, camino.size());
assertEquals("A", camino.get(0));
assertEquals("B", camino.get(1));
}
@Test
void testCaminoMasCortoIndirecto() {
// Verificar que encuentra el camino más corto cuando hay alternativas
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "C", 100.0); // Camino directo largo
grafo.agregarArista("A", "B", 10.0); // Camino indirecto
grafo.agregarArista("B", "C", 10.0); // más corto
List<String> camino = Dijkstra.encontrarCaminoMasCorto(grafo, "A", "C");
assertEquals(3, camino.size());
assertEquals("A", camino.get(0));
assertEquals("B", camino.get(1));
assertEquals("C", camino.get(2));
}
@Test
void testCaminoInexistente() {
// Verificar comportamiento cuando no hay camino
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarVertice("A");
grafo.agregarVertice("B");
// No agregar arista entre ellos
List<String> camino = Dijkstra.encontrarCaminoMasCorto(grafo, "A", "B");
assertTrue(camino.isEmpty());
}
@Test
void testCaminoComplejo() {
// Verificar en un grafo más complejo
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 4.0);
grafo.agregarArista("A", "C", 2.0);
grafo.agregarArista("B", "D", 3.0);
grafo.agregarArista("C", "D", 1.0);
grafo.agregarArista("C", "E", 6.0);
grafo.agregarArista("D", "E", 2.0);
List<String> camino = Dijkstra.encontrarCaminoMasCorto(grafo, "A", "E");
// El camino más corto debería ser A->C->D->E (peso total: 5)
assertEquals(4, camino.size());
assertEquals("A", camino.get(0));
assertEquals("C", camino.get(1));
assertEquals("D", camino.get(2));
assertEquals("E", camino.get(3));
}Clases involucradas:
PrimMétodos clave:
generarMST(Grafo<V> grafo) en Prim: Implementa el algoritmo de Prim para generar el MSTagregarAristasDelVertice(Grafo<V> grafo, V vertice, Set<V> visitados, PriorityQueue<Arista<V>> aristasDisponibles) en Prim: Añade las aristas de un vértice a la cola de prioridadDescripción detallada: Esta funcionalidad implementa el algoritmo de Prim para encontrar el árbol de recubrimiento mínimo de un grafo conectado. Comienza desde un vértice arbitrario y va agregando iterativamente la arista de menor peso que conecte un vértice visitado con uno no visitado. Utiliza una cola de prioridad para seleccionar eficientemente la siguiente arista mínima.
Tests sugeridos con JUnit:
@Test
void testMSTGrafoCompleto() {
// Verificar MST en un grafo completo pequeño
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 10.0);
grafo.agregarArista("A", "C", 15.0);
grafo.agregarArista("A", "D", 20.0);
grafo.agregarArista("B", "C", 12.0);
grafo.agregarArista("B", "D", 25.0);
grafo.agregarArista("C", "D", 8.0);
List<Arista<String>> mst = Prim.generarMST(grafo);
// Debe tener n-1 aristas
assertEquals(3, mst.size());
// Verificar que todas las aristas están conectadas
Set<String> verticesEnMST = new HashSet<>();
for (Arista<String> arista : mst) {
verticesEnMST.add(arista.getOrigen());
verticesEnMST.add(arista.getDestino());
}
assertEquals(4, verticesEnMST.size());
// Verificar peso total mínimo (8 + 10 + 12 = 30)
double pesoTotal = mst.stream().mapToDouble(Arista::getPeso).sum();
assertEquals(30.0, pesoTotal, 0.001);
}
@Test
void testMSTGrafoLineal() {
// Verificar MST en un grafo lineal
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarArista("A", "B", 5.0);
grafo.agregarArista("B", "C", 3.0);
grafo.agregarArista("C", "D", 7.0);
List<Arista<String>> mst = Prim.generarMST(grafo);
assertEquals(3, mst.size());
double pesoTotal = mst.stream().mapToDouble(Arista::getPeso).sum();
assertEquals(15.0, pesoTotal, 0.001);
}
@Test
void testMSTGrafoVacio() {
// Verificar comportamiento con grafo vacío
Grafo<String> grafo = new GrafoListaAdyacencia<>();
List<Arista<String>> mst = Prim.generarMST(grafo);
assertTrue(mst.isEmpty());
}
@Test
void testMSTUnVertice() {
// Verificar comportamiento con un solo vértice
Grafo<String> grafo = new GrafoListaAdyacencia<>();
grafo.agregarVertice("A");
List<Arista<String>> mst = Prim.generarMST(grafo);
assertTrue(mst.isEmpty());
}Clases involucradas:
IslaMétodos clave:
Isla(int id, double x, double y) en Isla: Constructor básico para crear una islaIsla(int id, double x, double y, boolean tieneTesoro) en Isla: Constructor que incluye información de tesorotieneTesoro() en Isla: Verifica si la isla tiene tesoro disponiblerecolectarTesoro() en Isla: Marca el tesoro como recolectadodistanciaA(Isla otra) en Isla: Calcula la distancia euclidiana a otra islaDescripción detallada: Esta funcionalidad modela una isla en el juego, incluyendo su posición geográfica, identificador único, y estado del tesoro. Las islas pueden contener tesoros que pueden ser recolectados. La clase proporciona métodos para calcular distancias entre islas, lo cual es fundamental para determinar los pesos de las aristas en el grafo del juego.
Tests sugeridos con JUnit:
@Test
void testCreacionIsla() {
// Verificar que una isla se crea correctamente
Isla isla = new Isla(1, 10.0, 20.0);
assertEquals(1, isla.getId());
assertEquals(10.0, isla.getX());
assertEquals(20.0, isla.getY());
assertFalse(isla.tieneTesoro());
}
@Test
void testCreacionIslaConTesoro() {
// Verificar creación de isla con tesoro
Isla isla = new Isla(2, 15.0, 25.0, true);
assertEquals(2, isla.getId());
assertTrue(isla.tieneTesoro());
assertFalse(isla.isTesoroRecolectado());
}
@Test
void testRecolectarTesoro() {
// Verificar recolección de tesoro
Isla isla = new Isla(3, 0.0, 0.0, true);
assertTrue(isla.tieneTesoro());
isla.recolectarTesoro();
assertFalse(isla.tieneTesoro()); // Ya no tiene tesoro disponible
assertTrue(isla.isTesoroRecolectado());
}
@Test
void testRecolectarTesoroSinTener() {
// Verificar que no se puede recolectar tesoro si no hay
Isla isla = new Isla(4, 0.0, 0.0, false);
isla.recolectarTesoro();
assertFalse(isla.isTesoroRecolectado());
}
@Test
void testDistanciaEntreIslas() {
// Verificar cálculo de distancia euclidiana
Isla isla1 = new Isla(1, 0.0, 0.0);
Isla isla2 = new Isla(2, 3.0, 4.0);
double distancia = isla1.distanciaA(isla2);
assertEquals(5.0, distancia, 0.001); // 3-4-5 triángulo
}
@Test
void testIgualdadIslas() {
// Verificar que las islas se comparan por ID
Isla isla1 = new Isla(1, 10.0, 20.0);
Isla isla2 = new Isla(1, 30.0, 40.0); // Mismo ID, diferentes coordenadas
assertEquals(isla1, isla2);
assertEquals(isla1.hashCode(), isla2.hashCode());
}Clases involucradas:
BoatMétodos clave:
Boat(Isla islaInicial) en Boat: Constructor que posiciona el barco en una isla inicialmoverA(Isla nuevaIsla) en Boat: Mueve el barco a una nueva isla y recolecta tesoro si existegetTesorosRecolectados() en Boat: Retorna una copia de la lista de tesoros recolectadosgetNumeroTesorosRecolectados() en Boat: Retorna el contador de tesoros recolectadosDescripción detallada: Esta funcionalidad modela el barco del jugador, incluyendo su posición actual y el inventario de tesoros recolectados. El barco puede moverse entre islas conectadas y automáticamente recolecta tesoros cuando llega a una isla que los contiene. Mantiene un registro de todos los tesoros recolectados para el seguimiento del progreso del juego.
Tests sugeridos con JUnit:
@Test
void testCreacionBarco() {
// Verificar que el barco se crea en la isla inicial
Isla islaInicial = new Isla(1, 10.0, 20.0);
Boat barco = new Boat(islaInicial);
assertEquals(islaInicial, barco.getIslaActual());
assertEquals(10.0, barco.getX());
assertEquals(20.0, barco.getY());
assertEquals(0, barco.getNumeroTesorosRecolectados());
}
@Test
void testMoverSinTesoro() {
// Verificar movimiento a isla sin tesoro
Isla isla1 = new Isla(1, 0.0, 0.0);
Isla isla2 = new Isla(2, 10.0, 10.0);
Boat barco = new Boat(isla1);
barco.moverA(isla2);
assertEquals(isla2, barco.getIslaActual());
assertEquals(10.0, barco.getX());
assertEquals(10.0, barco.getY());
assertEquals(0, barco.getNumeroTesorosRecolectados());
}
@Test
void testMoverConTesoro() {
// Verificar movimiento a isla con tesoro
Isla isla1 = new Isla(1, 0.0, 0.0);
Isla isla2 = new Isla(2, 10.0, 10.0, true);
Boat barco = new Boat(isla1);
assertTrue(isla2.tieneTesoro());
barco.moverA(isla2);
assertEquals(isla2, barco.getIslaActual());
assertEquals(1, barco.getNumeroTesorosRecolectados());
assertFalse(isla2.tieneTesoro()); // Tesoro recolectado
assertTrue(barco.getTesorosRecolectados().contains(isla2));
}
@Test
void testRecoleccionMultiplesTesoros() {
// Verificar recolección de múltiples tesoros
Isla isla1 = new Isla(1, 0.0, 0.0);
Isla isla2 = new Isla(2, 10.0, 10.0, true);
Isla isla3 = new Isla(3, 20.0, 20.0, true);
Boat barco = new Boat(isla1);
barco.moverA(isla2);
barco.moverA(isla3);
assertEquals(2, barco.getNumeroTesorosRecolectados());
List<Isla> tesoros = barco.getTesorosRecolectados();
assertTrue(tesoros.contains(isla2));
assertTrue(tesoros.contains(isla3));
}
@Test
void testInmutabilidadListaTesoros() {
// Verificar que la lista retornada es una copia
Isla isla1 = new Isla(1, 0.0, 0.0);
Isla isla2 = new Isla(2, 10.0, 10.0, true);
Boat barco = new Boat(isla1);
barco.moverA(isla2);
List<Isla> tesoros = barco.getTesorosRecolectados();
tesoros.clear(); // Intentar modificar la lista
// La lista interna no debe haberse modificado
assertEquals(1, barco.getNumeroTesorosRecolectados());
}Clases involucradas:
GameSettingsMétodos clave:
getInstance() en GameSettings: Implementa el patrón singleton para acceso globalisUseMatrixImplementation() en GameSettings: Retorna la implementación de grafo seleccionadasetUseMatrixImplementation(boolean useMatrixImplementation) en GameSettings: Establece la implementación de grafoDescripción detallada: Esta funcionalidad gestiona la configuración global del juego usando el patrón singleton. Permite alternar entre diferentes implementaciones de grafo (matriz vs lista de adyacencia) y mantiene esta configuración accesible desde cualquier parte del sistema. Es fundamental para permitir que el usuario seleccione la implementación de grafo antes de iniciar el juego.
Tests sugeridos con JUnit:
@Test
void testSingleton() {
// Verificar que siempre retorna la misma instancia
GameSettings settings1 = GameSettings.getInstance();
GameSettings settings2 = GameSettings.getInstance();
assertSame(settings1, settings2);
}
@Test
void testConfiguracionPorDefecto() {
// Verificar configuración inicial
GameSettings settings = GameSettings.getInstance();
assertTrue(settings.isUseMatrixImplementation()); // Por defecto usa matriz
}
@Test
void testCambiarImplementacion() {
// Verificar que se puede cambiar la implementación
GameSettings settings = GameSettings.getInstance();
settings.setUseMatrixImplementation(false);
assertFalse(settings.isUseMatrixImplementation());
settings.setUseMatrixImplementation(true);
assertTrue(settings.isUseMatrixImplementation());
}
@Test
void testPersistenciaConfiguracion() {
// Verificar que la configuración persiste entre accesos
GameSettings.getInstance().setUseMatrixImplementation(false);
GameSettings settings = GameSettings.getInstance();
assertFalse(settings.isUseMatrixImplementation());
}Clases involucradas:
GameWorldMétodos clave:
GameWorld() en GameWorld: Constructor que genera un mundo completo del juegogenerarIslas() en GameWorld: Crea islas con posiciones aleatorias válidasconectarIslas() en GameWorld: Establece conexiones entre islas usando MST + conexiones adicionalesgenerarMSTCompleto() en GameWorld: Crea un grafo completo temporal para generar el MSTagregarConexionesAdicionales(int conexionesAdicionales) en GameWorld: Añade más conexiones al MST baseasignarTesoros() en GameWorld: Distribuye tesoros aleatoriamente en las islasDescripción detallada: Esta funcionalidad es responsable de generar proceduralmente el mundo del juego. Crea entre 50-70 islas con posiciones aleatorias, asegurando una distancia mínima entre ellas. Utiliza el algoritmo de Prim para generar un árbol de recubrimiento mínimo que garantiza conectividad, luego añade conexiones adicionales para crear múltiples rutas. Finalmente, distribuye 5-10 tesoros aleatoriamente y posiciona el barco en la primera isla.
Tests sugeridos con JUnit:
@Test
void testGeneracionMundo() {
// Verificar que se genera un mundo válido
GameWorld mundo = new GameWorld();
assertNotNull(mundo.getGrafo());
assertNotNull(mundo.getIslas());
assertNotNull(mundo.getBarco());
assertNotNull(mundo.getIslaInicial());
assertTrue(mundo.getIslas().size() >= 50);
assertTrue(mundo.getIslas().size() <= 70);
assertTrue(mundo.getTotalTesoros() >= 5);
assertTrue(mundo.getTotalTesoros() <= 10);
}
@Test
void testConectividadGrafo() {
// Verificar que el grafo generado está conectado
GameWorld mundo = new GameWorld();
// Verificar que hay suficientes aristas (al menos n-1 para conectividad)
List<Arista<Isla>> aristas = mundo.getGrafo().obtenerAristas();
assertTrue(aristas.size() >= mundo.getIslas().size() - 1);
// Verificar que se puede llegar de la isla inicial a cualquier otra
Isla islaInicial = mundo.getIslaInicial();
for (Isla isla : mundo.getIslas()) {
if (!isla.equals(islaInicial)) {
List<Isla> camino = mundo.getGrafo().caminoMasCorto(islaInicial, isla);
assertFalse(camino.isEmpty(), "No hay camino a la isla " + isla.getId());
}
}
}
@Test
void testDistanciaMinima() {
// Verificar que las islas mantienen distancia mínima
GameWorld mundo = new GameWorld();
double minDistancia = 40.0;
List<Isla> islas = mundo.getIslas();
for (int i = 0; i < islas.size(); i++) {
for (int j = i + 1; j < islas.size(); j++) {
double distancia = islas.get(i).distanciaA(islas.get(j));
assertTrue(distancia >= minDistancia,
"Distancia entre islas " + i + " y " + j + " es menor que " + minDistancia);
}
}
}
@Test
void testBarcoEnIslaInicial() {
// Verificar que el barco inicia en la isla inicial
GameWorld mundo = new GameWorld();
assertEquals(mundo.getIslaInicial(), mundo.getBarco().getIslaActual());
}
@Test
void testImplementacionGrafoSegunConfiguracion() {
// Verificar que usa la implementación correcta según configuración
GameSettings.getInstance().setUseMatrixImplementation(true);
GameWorld mundo1 = new GameWorld();
assertTrue(mundo1.isUseMatrixImplementation());
GameSettings.getInstance().setUseMatrixImplementation(false);
GameWorld mundo2 = new GameWorld();
assertFalse(mundo2.isUseMatrixImplementation());
}
@Test
void testJuegoCompletado() {
// Verificar detección de juego completado
GameWorld mundo = new GameWorld();
assertFalse(mundo.juegoCompletado()); // Al inicio no está completado
// Simular recolección de todos los tesoros
for (Isla isla : mundo.obtenerIslasConTesoro()) {
mundo.getBarco().moverA(isla);
}
// Regresar a isla inicial
mundo.getBarco().moverA(mundo.getIslaInicial());
assertTrue(mundo.juegoCompletado());
}Clases involucradas:
StartControllerMétodos clave:
initialize(URL location, ResourceBundle resources) en StartController: Configura los eventos de los botonesstartGame() en StartController: Inicia el juego cargando la vista principaltoggleImplementation() en StartController: Alterna entre implementaciones de grafoupdateImplementationLabel() en StartController: Actualiza la etiqueta que muestra la implementación actualDescripción detallada: Esta funcionalidad controla la pantalla de inicio del juego, permitiendo al usuario seleccionar la implementación de grafo antes de comenzar. Gestiona la transición entre la pantalla de inicio y la pantalla del juego, asegurando que la configuración seleccionada se aplique correctamente. Proporciona retroalimentación visual sobre la implementación actualmente seleccionada.
Tests sugeridos con JUnit:
@Test
void testInicializacionControlador() {
// Verificar que el controlador se inicializa correctamente
StartController controller = new StartController();
// Simular componentes FXML
controller.startButton = new Button();
controller.implementationButton = new Button();
controller.implementationLabel = new Label();
controller.initialize(null, null);
assertNotNull(controller.startButton.getOnAction());
assertNotNull(controller.implementationButton.getOnAction());
}
@Test
void testCambioImplementacion() {
// Verificar que el cambio de implementación funciona
StartController controller = new StartController();
controller.implementationLabel = new Label();
// Estado inicial
assertTrue(controller.useMatrixImplementation);
// Cambiar implementación
controller.toggleImplementation();
assertFalse(controller.useMatrixImplementation);
// Cambiar de nuevo
controller.toggleImplementation();
assertTrue(controller.useMatrixImplementation);
}
@Test
void testActualizacionEtiqueta() {
// Verificar que la etiqueta se actualiza correctamente
StartController controller = new StartController();
controller.implementationLabel = new Label();
controller.useMatrixImplementation = true;
controller.updateImplementationLabel();
assertTrue(controller.implementationLabel.getText().contains("Matriz"));
controller.useMatrixImplementation = false;
controller.updateImplementationLabel();
assertTrue(controller.implementationLabel.getText().contains("Lista"));
}
@Test
void testConfiguracionGuardada() {
// Verificar que la configuración se guarda antes de iniciar el juego
StartController controller = new StartController();
controller.useMatrixImplementation = false;
// Simular inicio del juego (sin la parte de UI)
GameSettings.getInstance().setUseMatrixImplementation(controller.useMatrixImplementation);
assertFalse(GameSettings.getInstance().isUseMatrixImplementation());
}Clases involucradas:
GameControllerMétodos clave:
initialize(URL location, ResourceBundle resources) en GameController: Inicializa el juego y la interfazdibujarMundo() en GameController: Renderiza visualmente el mundo del juegomanejarClicIsla(Isla islaDestino) en GameController: Procesa los clics del usuario en las islasmoverBarcoA(Isla destino) en GameController: Anima el movimiento del barcomostrarMejorRuta() en GameController: Calcula y muestra la ruta óptima al tesoro más cercanoverificarVictoria() en GameController: Verifica si el jugador ha completado el juegoDescripción detallada: Esta funcionalidad controla toda la lógica de la interfaz del juego principal. Gestiona la renderización visual del mundo, procesa las interacciones del usuario, anima el movimiento del barco, y proporciona ayudas como la visualización de rutas óptimas. También monitorea el progreso del juego y detecta las condiciones de victoria.
Tests sugeridos con JUnit:
@Test
void testInicializacionJuego() {
// Verificar que el juego se inicializa correctamente
GameController controller = new GameController();
// Simular componentes FXML
controller.gamePane = new Pane();
controller.islaActualLabel = new Label();
controller.tesorosRecolectadosLabel = new Label();
controller.totalTesorosLabel = new Label();
controller.mejorRutaButton = new Button();
controller.mostrarMSTButton = new Button();
controller.salirButton = new Button();
controller.initialize(null, null);
assertNotNull(controller.gameWorld);
assertNotNull(controller.islaViews);
assertNotNull(controller.rutasSugeridas);
}
@Test
void testActualizacionInterfaz() {
// Verificar que la interfaz se actualiza correctamente
GameController controller = new GameController();
controller.islaActualLabel = new Label();
controller.tesorosRecolectadosLabel = new Label();
controller.totalTesorosLabel = new Label();
// Crear un mundo de prueba
controller.gameWorld = new GameWorld();
controller.actualizarInterfaz();
assertTrue(controller.islaActualLabel.getText().contains("Isla actual:"));
assertTrue(controller.tesorosRecolectadosLabel.getText().contains("Tesoros recolectados:"));
assertTrue(controller.totalTesorosLabel.getText().contains("Total tesoros:"));
}
@Test
void testValidacionMovimiento() {
// Verificar que solo se permite movimiento a islas conectadas
GameController controller = new GameController();
controller.gameWorld = new GameWorld();
Isla islaActual = controller.gameWorld.getBarco().getIslaActual();
// Encontrar una isla conectada
List<Isla> vecinosValidos = controller.gameWorld.getGrafo().obtenerVecinos(islaActual);
assertFalse(vecinosValidos.isEmpty());
// El movimiento a un vecino debería ser válido
Isla vecinoValido = vecinosValidos.get(0);
assertTrue(controller.gameWorld.getGrafo().existeArista(islaActual, vecinoValido));
}
@Test
void testLimpiezaRutasSugeridas() {
// Verificar que las rutas sugeridas se limpian correctamente
GameController controller = new GameController();
controller.gamePane = new Pane();
controller.rutasSugeridas = new ArrayList<>();
// Simular agregar rutas
Line linea1 = new Line();
Line linea2 = new Line();
controller.rutasSugeridas.add(linea1);
controller.rutasSugeridas.add(linea2);
controller.gamePane.getChildren().addAll(linea1, linea2);
assertEquals(2, controller.gamePane.getChildren().size());
controller.limpiarRutasSugeridas();
assertTrue(controller.rutasSugeridas.isEmpty());
assertFalse(controller.gamePane.getChildren().contains(linea1));
assertFalse(controller.gamePane.getChildren().contains(linea2));
}Clases involucradas:
TreasureHuntApplicationMétodos clave:
start(Stage stage) en TreasureHuntApplication: Configura y muestra la ventana principalmain(String[] args) en TreasureHuntApplication: Punto de entrada de la aplicaciónDescripción detallada: Esta funcionalidad representa el punto de entrada de la aplicación JavaFX. Configura la ventana principal, carga la vista inicial (pantalla de inicio), y establece las propiedades básicas de la ventana como título, tamaño y capacidad de redimensionamiento. Es responsable de inicializar todo el sistema de la aplicación.
Tests sugeridos con JUnit:
// Nota: Los tests de JavaFX Application requieren configuración especial
// Aquí se muestran tests conceptuales que verificarían la lógica
@Test
void testConfiguracionVentana() {
// Verificar que la ventana se configura correctamente
// Este test requeriría TestFX o similar para testing de JavaFX
// Verificaciones esperadas:
// - Título: "Island Treasure Hunt"
// - Tamaño: 1280x720
// - No redimensionable
// - Vista inicial: start.fxml
}
@Test
void testCargaVistaInicial() {
// Verificar que se carga la vista de inicio correctamente
// Este test verificaría que el FXML se carga sin errores
try {
FXMLLoader loader = new FXMLLoader(
TreasureHuntApplication.class.getResource("/views/start.fxml")
);
Parent root = loader.load();
assertNotNull(root);
} catch (IOException e) {
fail("No se pudo cargar la vista de inicio: " + e.getMessage());
}
}
@Test
void testRecursosDisponibles() {
// Verificar que todos los recursos necesarios están disponibles
assertNotNull(TreasureHuntApplication.class.getResource("/views/start.fxml"));
assertNotNull(TreasureHuntApplication.class.getResource("/game-view.fxml"));
// Verificar imágenes (opcionales)
// Estas pueden ser null sin causar errores
URL boatImage = TreasureHuntApplication.class.getResource("/images/boat.png");
URL islandImage = TreasureHuntApplication.class.getResource("/images/island.png");
URL treasureImage = TreasureHuntApplication.class.getResource("/images/island_treasure.png");
// Si existen, deberían ser válidas
if (boatImage != null) assertNotNull(boatImage);
if (islandImage != null) assertNotNull(islandImage);
if (treasureImage != null) assertNotNull(treasureImage);
}Esta división en funcionalidades permite un desarrollo incremental y testing exhaustivo de cada componente del sistema, asegurando que cada parte funcione correctamente antes de integrarla con las demás.
este proyecto cumple con esto?
El programa ofrece una solución a todas las necesidades planteadas en el enunciado. Esto es, mínimo 2 problemas sobre grafos que deben ser resueltos tanto con listas de adyacencia como con matrices de adyacencia. Estas soluciones se encuentran debidamente probadas por casos interesantes en sus pruebas unitarias.
La estructura de datos grafo propia genérica funciona correctamente (con listas de adyacencia y matriz de adyacencia). Se encuentra correctamente documentada. Incluye pruebas unitarias automáticas, con casos interesantes para verificarlas.
Sí, el proyecto "Caza del Tesoro en Islas" cumple completamente con los requisitos que mencionas:
Dijkstra.java, que funciona con cualquier implementación de la interfaz Grafo<V>.Prim.java, que también funciona con cualquier implementación de Grafo<V>.Grafo<V> define el contrato para todas las implementaciones.GrafoListaAdyacencia<V> implementa el grafo usando un Map<V, List<Arista<V>>>.GrafoMatrizAdyacencia<V> implementa el grafo usando una matriz de dobles y mapas para relacionar vértices con índices.GrafoListaAdyacencia: Verifican operaciones básicas como agregar vértices/aristas y obtener vecinos.GrafoMatrizAdyacencia: Incluyen casos específicos como la expansión dinámica de la matriz.Dijkstra: Verifican caminos directos, indirectos, inexistentes y complejos.Prim: Prueban la generación del MST en diferentes tipos de grafos.El proyecto demuestra una implementación robusta de estructuras de datos de grafos y algoritmos, con una aplicación práctica en forma de juego interactivo, cumpliendo todos los requisitos especificados.
debo hacer aproximadamente 8 commits de este proyecto ya que es una tarea que debo enviar pero para hacer los commits debe mostrarse un avance progresivo del proyecto por lo que quiero que de manera literal me digas que deberia enviar para cada commit sea avanzando por funcionalidades o algo asi
ejemplo
para el primer commit envia las clases grafo, arista completas
para el segundo commit envia la clase GameController pero no completa envia los siguientes metodos
metodo(), metodo2(), envia la clase isla, boat
y asi hasta lograr los 8 commits