R7 [Solución] – Guerra por el Sistema Solar: Tierra, Marte y el Cinturón” (The Expanse)

1) Nave.java





/**
 * Representa una nave espacial dentro del universo de The Expanse.
 * 
 * Conceptos que se trabajan aquí:
 * - Encapsulamiento (atributos privados + getters/setters)
 * - Constructor completo
 * - toString() para imprimir bonito el objeto
 */
public class Nave {

    // -------------------------
    // Atributos (siempre privados)
    // -------------------------
    private String nombre;
    private String faccion; // "Tierra", "Marte", "Cinturon"
    private int misiles;
    private boolean necesitaReparacion;

    // -------------------------
    // Constructores
    // -------------------------

    /**
     * Constructor completo exigido por el enunciado.
     */
    public Nave(String nombre, String faccion, int misiles, boolean necesitaReparacion) {
        this.nombre = nombre;
        this.faccion = faccion;
        this.misiles = misiles;
        this.necesitaReparacion = necesitaReparacion;
    }

    /**
     * Constructor opcional de conveniencia (por si quieres crear naves “rápido”).
     * Por ejemplo: misiles = 0 y no necesita reparación por defecto.
     */
    public Nave(String nombre, String faccion) {
        this(nombre, faccion, 0, false);
    }

    // -------------------------
    // Getters y Setters
    // -------------------------
    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getFaccion() {
        return faccion;
    }

    public void setFaccion(String faccion) {
        this.faccion = faccion;
    }

    public int getMisiles() {
        return misiles;
    }

    public void setMisiles(int misiles) {
        this.misiles = misiles;
    }

    public boolean isNecesitaReparacion() {
        return necesitaReparacion;
    }

    public void setNecesitaReparacion(boolean necesitaReparacion) {
        this.necesitaReparacion = necesitaReparacion;
    }

    // -------------------------
    // toString() (muy útil para listar)
    // -------------------------
    @Override
    public String toString() {
        return "Nave{" +
                "nombre='" + nombre + '\'' +
                ", faccion='" + faccion + '\'' +
                ", misiles=" + misiles +
                ", necesitaReparacion=" + (necesitaReparacion ? "Sí" : "No") +
                '}';
    }
}

2) Flota.java





import java.util.ArrayList;
import java.util.Scanner;

/**
 * Flota = conjunto de naves.
 *
 * Conceptos que se trabajan:
 * - ArrayList con objetos (ArrayList<Nave>)
 * - Métodos para recorrer y filtrar
 * - Métodos con Scanner para crear objetos desde teclado
 */
public class Flota {

    // Lista privada: nadie fuera debería tocarla directamente
    private ArrayList<Nave> naves;

    // -------------------------
    // Constructor
    // -------------------------
    public Flota() {
        // Inicializamos la lista vacía (obligatorio)
        this.naves = new ArrayList<>();
    }

    // -------------------------
    // Agregar nave ya creada
    // -------------------------
    public void agregarNave(Nave nave) {
        if (nave == null) {
            System.out.println("No se puede añadir una nave nula.");
            return;
        }
        naves.add(nave);
        System.out.println("✅ Nave añadida a la flota: " + nave.getNombre());
    }

    // -------------------------
    // Crear nave por teclado
    // -------------------------
    public void crearNaveDesdeTeclado(Scanner sc) {
        System.out.println("=== CREAR NUEVA NAVE ===");

        // Nombre
        System.out.print("Nombre de la nave: ");
        String nombre = sc.nextLine().trim();

        // Facción (validada)
        String faccion = leerFaccionValida(sc);

        // Misiles (entero >= 0)
        int misiles = leerEnteroNoNegativo(sc, "Número de misiles: ");

        // Reparación (S/N)
        boolean necesitaReparacion = leerBooleanSN(sc, "¿Necesita reparación? (S/N): ");

        // Creamos el objeto Nave con los datos recogidos
        Nave nave = new Nave(nombre, faccion, misiles, necesitaReparacion);

        // La añadimos al ArrayList
        naves.add(nave);

        System.out.println("✅ Nave creada y añadida: " + nave);
    }

    // -------------------------
    // Número de naves
    // -------------------------
    public int getNumeroNaves() {
        return naves.size();
    }

    // -------------------------
    // Listar todas
    // -------------------------
    public void listarTodas() {
        System.out.println("=== LISTADO COMPLETO DE NAVES ===");

        if (naves.isEmpty()) {
            System.out.println("La flota está vacía.");
            return;
        }

        for (Nave n : naves) {
            System.out.println(n); // llama a toString()
        }
    }

    // -------------------------
    // Listar naves para reparar
    // -------------------------
    public void listarNavesParaReparar() {
        System.out.println("=== NAVES QUE NECESITAN REPARACIÓN ===");

        boolean hay = false;

        for (Nave n : naves) {
            if (n.isNecesitaReparacion()) {
                System.out.println(n);
                hay = true;
            }
        }

        if (!hay) {
            System.out.println("No hay naves marcadas para reparación.");
        }
    }

    // -------------------------
    // Total de misiles
    // -------------------------
    public int getTotalMisiles() {
        int total = 0;
        for (Nave n : naves) {
            total += n.getMisiles();
        }
        return total;
    }

    // -------------------------
    // Listar por facción
    // -------------------------
    public void listarPorFaccion(String faccion) {
        System.out.println("=== NAVES DE LA FACCIÓN: " + faccion + " ===");

        boolean hay = false;

        for (Nave n : naves) {
            // equalsIgnoreCase = compara ignorando mayúsculas/minúsculas
            if (n.getFaccion().equalsIgnoreCase(faccion)) {
                System.out.println(n);
                hay = true;
            }
        }

        if (!hay) {
            System.out.println("No se encontraron naves de esa facción.");
        }
    }

    // -------------------------
    // Contar por facción
    // -------------------------
    public int contarPorFaccion(String faccion) {
        int contador = 0;

        for (Nave n : naves) {
            if (n.getFaccion().equalsIgnoreCase(faccion)) {
                contador++;
            }
        }

        return contador;
    }

    // ==========================================================
    // Métodos auxiliares (para que el código quede limpio y robusto)
    // ==========================================================

    /**
     * Pide al usuario una facción válida: Tierra / Marte / Cinturon.
     */
    private String leerFaccionValida(Scanner sc) {
        while (true) {
            System.out.print("Facción (Tierra/Marte/Cinturon): ");
            String faccion = sc.nextLine().trim();

            if (esFaccionValida(faccion)) {
                // Normalizamos para que quede bonito y consistente
                return normalizarFaccion(faccion);
            }

            System.out.println("❌ Facción no válida. Usa: Tierra, Marte o Cinturon.");
        }
    }

    private boolean esFaccionValida(String faccion) {
        String f = faccion.trim().toLowerCase();
        return f.equals("tierra") || f.equals("marte") || f.equals("cinturon");
    }

    private String normalizarFaccion(String faccion) {
        String f = faccion.trim().toLowerCase();
        if (f.equals("tierra")) return "Tierra";
        if (f.equals("marte")) return "Marte";
        return "Cinturon";
    }

    /**
     * Lee un entero >= 0, repitiendo hasta que sea válido.
     */
    private int leerEnteroNoNegativo(Scanner sc, String mensaje) {
        while (true) {
            System.out.print(mensaje);
            String linea = sc.nextLine().trim();

            try {
                int valor = Integer.parseInt(linea);
                if (valor < 0) {
                    System.out.println("❌ No puede ser negativo.");
                } else {
                    return valor;
                }
            } catch (NumberFormatException e) {
                System.out.println("❌ Introduce un número entero válido.");
            }
        }
    }

    /**
     * Lee una respuesta tipo S/N y la convierte a boolean.
     * S -> true, N -> false
     */
    private boolean leerBooleanSN(Scanner sc, String mensaje) {
        while (true) {
            System.out.print(mensaje);
            String resp = sc.nextLine().trim().toLowerCase();

            if (resp.equals("s") || resp.equals("si") || resp.equals("sí")) return true;
            if (resp.equals("n") || resp.equals("no")) return false;

            System.out.println("❌ Respuesta no válida. Escribe S o N.");
        }
    }
}

3) ControlFlota.java (main + menú)





import java.util.Scanner;

/**
 * Controlador principal.
 *
 * Conceptos que se trabajan:
 * - Menú por consola repetitivo (do-while)
 * - switch para ejecutar opciones
 * - Reutilización de Scanner y validación de enteros
 */
public class ControlFlota {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        Flota flota = new Flota();

        // Naves iniciales opcionales (ambiente The Expanse)
        flota.agregarNave(new Nave("Rocinante", "Cinturon", 24, false));
        flota.agregarNave(new Nave("Donnager", "Marte", 60, true));
        flota.agregarNave(new Nave("Agatha King", "Tierra", 40, true));

        int opcion;

        do {
            mostrarMenu();
            opcion = leerEnteroSeguro(sc);

            switch (opcion) {

                case 1:
                    // Crear nave desde teclado
                    flota.crearNaveDesdeTeclado(sc);
                    break;

                case 2:
                    // Crear nave desde el main (valores fijos)
                    Nave n = new Nave("Nauvoo", "Cinturon", 80, false);
                    flota.agregarNave(n);
                    System.out.println("Nave creada desde main y añadida: " + n);
                    break;

                case 3:
                    flota.listarTodas();
                    break;

                case 4:
                    flota.listarNavesParaReparar();
                    break;

                case 5:
                    System.out.println("Número total de naves: " + flota.getNumeroNaves());
                    break;

                case 6:
                    System.out.println("Misiles totales en la flota: " + flota.getTotalMisiles());
                    break;

                case 7:
                    System.out.print("Introduce la facción (Tierra/Marte/Cinturon): ");
                    String fac = sc.nextLine().trim();
                    flota.listarPorFaccion(fac);
                    break;

                case 8:
                    System.out.print("Introduce la facción (Tierra/Marte/Cinturon): ");
                    String fac2 = sc.nextLine().trim();
                    int num = flota.contarPorFaccion(fac2);
                    System.out.println("Número de naves de la facción " + fac2 + ": " + num);
                    break;

                case 0:
                    System.out.println("Saliendo del sistema de control de flota...");
                    break;

                default:
                    System.out.println("Opción no válida.");
            }

            System.out.println(); // línea en blanco para separar “vueltas” del menú

        } while (opcion != 0);

        sc.close();
    }

    // -------------------------
    // Menú
    // -------------------------
    private static void mostrarMenu() {
        System.out.println("=== CONTROL DE FLOTA - GUERRA DEL SISTEMA SOLAR ===");
        System.out.println("1. Añadir nave (datos por teclado)");
        System.out.println("2. Añadir nave (creada en el main)");
        System.out.println("3. Listar todas las naves");
        System.out.println("4. Listar naves que necesitan reparación");
        System.out.println("5. Mostrar número total de naves");
        System.out.println("6. Mostrar número total de misiles");
        System.out.println("7. Listar naves por facción");
        System.out.println("8. Contar naves por facción");
        System.out.println("0. Salir");
        System.out.print("Elige una opción: ");
    }

    /**
     * Lee un entero de forma segura usando nextLine() + parseInt.
     * Ventaja: evita problemas típicos de Scanner con nextInt() y saltos de línea.
     */
    private static int leerEnteroSeguro(Scanner sc) {
        while (true) {
            try {
                return Integer.parseInt(sc.nextLine().trim());
            } catch (NumberFormatException e) {
                System.out.print("Introduce un número válido: ");
            }
        }
    }
}