Categoría: Retos JAVA

  • R8 [Solución]- El Escalafón Mágico de Hogwarts

    R8 [Solución]- El Escalafón Mágico de Hogwarts

    El Ministerio de Magia ha implantado un nuevo sistema de clasificación de magos para evaluar su progreso, capacidades y responsabilidades dentro del mundo mágico.

    1) Casa.java (enum)

    La enum sirve para tener un conjunto cerrado de valores (solo esas casas), evitando Strings sueltos.

    
    
    
    
    
    package modelo;
    
    public enum Casa {
        GRYFFINDOR,
        SLYTHERIN,
        RAVENCLAW,
        HUFFLEPUFF
    }
    

    2) Mago.java (clase base)

    Qué aporta esta clase

    • Define lo común a todos: nombre, nivel, vida, mana, casa.
    • Aplica un bonus inicial según la casa.
    • Tiene métodos base (entrenar, descansar, ficha, lanzarHechizo).
    • lanzarHechizo NO es abstracto: por defecto hace algo simple.
    
    
    
    
    
    package modelo;
    
    public class Mago {
    
        protected String nombre;
        protected int nivel; // 1..100
        protected int vida;  // 0..100
        protected int mana;  // 0..100
        protected Casa casa;
    
        public Mago(String nombre, Casa casa) {
            this.nombre = nombre;
            this.casa = casa;
    
            // Valores base
            this.nivel = 1;
            this.vida = 100;
            this.mana = 100;
    
            aplicarBonusCasa();
        }
    
        private void aplicarBonusCasa() {
            // Bonus simples y fáciles de ver en consola
            switch (casa) {
                case GRYFFINDOR:
                    vida += 10; // más resistencia
                    break;
                case SLYTHERIN:
                    mana += 10; // más “energía mágica”
                    break;
                case RAVENCLAW:
                    nivel += 1; // aprende más rápido (nivel inicial superior)
                    break;
                case HUFFLEPUFF:
                    vida += 5;
                    mana += 5; // equilibrio
                    break;
            }
            // Normalizamos límites
            vida = clamp(vida, 0, 100);
            mana = clamp(mana, 0, 100);
            nivel = clamp(nivel, 1, 100);
        }
    
        public void entrenar() {
            // Entrenar sube nivel, pero cansa
            nivel += 1;
            mana -= 5;
            vida -= 2;
    
            nivel = clamp(nivel, 1, 100);
            mana = clamp(mana, 0, 100);
            vida = clamp(vida, 0, 100);
        }
    
        public void descansar() {
            // Descansar recupera recursos
            mana += 10;
            vida += 10;
    
            mana = clamp(mana, 0, 100);
            vida = clamp(vida, 0, 100);
        }
    
        public String ficha() {
            return nombre + " | Casa: " + casa +
                   " | Nivel: " + nivel +
                   " | Vida: " + vida +
                   " | Mana: " + mana;
        }
    
        /**
         * Lanza un hechizo genérico. Las clases hijas lo mejoran.
         * Devuelve el "daño" (o 0 si no se puede).
         */
        public int lanzarHechizo(String hechizo) {
            int coste = 5;
            if (!gastarMana(coste)) return 0;
            return 3; // daño base genérico
        }
    
        protected boolean gastarMana(int cantidad) {
            if (mana < cantidad) {
                return false;
            }
            mana -= cantidad;
            mana = clamp(mana, 0, 100);
            return true;
        }
    
        public void recibirDaño(int daño) {
            vida -= daño;
            vida = clamp(vida, 0, 100);
        }
    
        protected int clamp(int valor, int min, int max) {
            if (valor < min) return min;
            if (valor > max) return max;
            return valor;
        }
    }
    

    3) Aprendiz.java

    Idea clave

    • Un Aprendiz tiene torpeza, así que puede fallar.
    • Aprende con practicarBasico().
    • Sobrescribe lanzarHechizo para permitir solo hechizos básicos.
    
    
    
    
    
    package modelo;
    
    import java.util.Random;
    
    public class Aprendiz extends Mago {
    
        protected int torpeza; // 0..100 (más torpeza = más fallos)
        protected Random rnd = new Random();
    
        public Aprendiz(String nombre, Casa casa) {
            super(nombre, casa);
    
            torpeza = 40;
    
            // Ajuste según casa (sencillo y visible)
            if (casa == Casa.RAVENCLAW) torpeza -= 10;   // más “cabeza”
            if (casa == Casa.HUFFLEPUFF) torpeza -= 5;   // constancia
            if (casa == Casa.SLYTHERIN) torpeza += 5;    // “se la juega más”
            torpeza = clamp(torpeza, 0, 100);
        }
    
        public void practicarBasico() {
            // Practicar reduce torpeza (mejora)
            if (!gastarMana(3)) return;
    
            torpeza -= 2;
            torpeza = clamp(torpeza, 0, 100);
    
            // Practicar también puede subir un poquito el nivel
            if (nivel < 100) nivel += 1;
        }
    
        @Override
        public int lanzarHechizo(String hechizo) {
            // Coste base
            if (!gastarMana(5)) return 0;
    
            // Probabilidad de fallo basada en torpeza
            int tirada = rnd.nextInt(100); // 0..99
            if (tirada < torpeza) {
                // falló
                return 0;
            }
    
            // Hechizos permitidos
            if (hechizo.equalsIgnoreCase("Lumos")) return 5;
            if (hechizo.equalsIgnoreCase("Alohomora")) return 7;
    
            // Si escribe otro, no lo conoce
            return 0;
        }
    
        public int getTorpeza() {
            return torpeza;
        }
    
        public void setTorpeza(int torpeza) {
            this.torpeza = clamp(torpeza, 0, 100);
        }
    }
    

    4) Hechicero.java

    Idea clave

    • Hereda de Aprendiz, pero ahora tiene controlVarita.
    • Puede hacer hechizos más potentes.
    • Los fallos deberían ser menos frecuentes: usamos torpeza pero “rebajada”.
    
    
    
    
    
    package modelo;
    
    import java.util.Random;
    
    public class Hechicero extends Aprendiz {
    
        protected int controlVarita; // 0..100
        protected Random rnd2 = new Random();
    
        public Hechicero(String nombre, Casa casa) {
            super(nombre, casa);
    
            controlVarita = 50;
    
            // Ravenclaw suele destacar en control
            if (casa == Casa.RAVENCLAW) controlVarita += 10;
            if (casa == Casa.GRYFFINDOR) controlVarita += 5;
    
            controlVarita = clamp(controlVarita, 0, 100);
        }
    
        public void estudiarEnBiblioteca() {
            if (!gastarMana(6)) return;
    
            controlVarita += 3;
            controlVarita = clamp(controlVarita, 0, 100);
    
            nivel += 1;
            nivel = clamp(nivel, 1, 100);
        }
    
        @Override
        public int lanzarHechizo(String hechizo) {
            if (!gastarMana(7)) return 0;
    
            // Los Hechiceros fallan menos: torpeza influye menos
            int torpezaEfectiva = clamp(torpeza - (controlVarita / 5), 0, 100);
            int tirada = rnd2.nextInt(100);
            if (tirada < torpezaEfectiva) return 0;
    
            // Hechizos
            if (hechizo.equalsIgnoreCase("Lumos")) return 6;
            if (hechizo.equalsIgnoreCase("Alohomora")) return 8;
            if (hechizo.equalsIgnoreCase("Expelliarmus")) return 12;
            if (hechizo.equalsIgnoreCase("Stupefy")) return 18;
    
            return 0;
        }
    
        public int getControlVarita() {
            return controlVarita;
        }
    }
    

    5) Auror.java

    Idea clave

    • Un Auror es “modo combate”: tiene experiencia y puede arrestar.
    • Añadimos métodos propios: patrullar() y arrestar(...).
    
    
    
    
    
    package modelo;
    
    public class Auror extends Hechicero {
    
        private int experienciaCombate; // 0..100
        private int arrestos;
    
        public Auror(String nombre, Casa casa) {
            super(nombre, casa);
    
            experienciaCombate = 40;
            arrestos = 0;
    
            if (casa == Casa.GRYFFINDOR) experienciaCombate += 10; // valentía
            if (casa == Casa.SLYTHERIN) experienciaCombate += 5;   // ambición táctica
            experienciaCombate = clamp(experienciaCombate, 0, 100);
        }
    
        public void patrullar() {
            if (!gastarMana(8)) return;
    
            experienciaCombate += 4;
            experienciaCombate = clamp(experienciaCombate, 0, 100);
    
            nivel += 1;
            nivel = clamp(nivel, 1, 100);
        }
    
        public boolean arrestar(Aprendiz objetivo) {
            // Regla: solo si está débil
            if (objetivo == null) return false;
    
            // Como vida es protected en Mago, podemos leerla aquí directamente:
            if (objetivo.vida <= 20) {
                arrestos++;
                return true;
            }
            return false;
        }
    
        @Override
        public int lanzarHechizo(String hechizo) {
            if (!gastarMana(9)) return 0;
    
            // Auror: daño mejorado por experienciaCombate
            if (hechizo.equalsIgnoreCase("Stupefy")) {
                return 20 + (experienciaCombate / 10);
            }
    
            // Protego: “defensa” simple -> recupera vida (no daño)
            if (hechizo.equalsIgnoreCase("Protego")) {
                vida += 10;
                vida = clamp(vida, 0, 100);
                return 0;
            }
    
            // Otros hechizos como en Hechicero (reutilizamos lógica)
            return super.lanzarHechizo(hechizo);
        }
    
        public int getArrestos() {
            return arrestos;
        }
    }
    

    6) Profesor.java

    Idea clave

    • Un Profesor enseña: puede reducir torpeza y subir nivel del alumno.
    • Sus hechizos son “eficientes”: consumen menos mana o fallan menos.
    
    
    
    
    
    package modelo;
    
    public class Profesor extends Hechicero {
    
        private String asignatura;
        private int prestigio; // 0..100
    
        public Profesor(String nombre, Casa casa, String asignatura) {
            super(nombre, casa);
            this.asignatura = asignatura;
    
            prestigio = 60;
            if (casa == Casa.SLYTHERIN) prestigio += 5;
            if (casa == Casa.RAVENCLAW) prestigio += 10;
            prestigio = clamp(prestigio, 0, 100);
        }
    
        public void enseñar(Aprendiz alumno) {
            if (alumno == null) return;
            if (!gastarMana(6)) return;
    
            // Enseñar reduce torpeza y sube nivel
            alumno.setTorpeza(alumno.getTorpeza() - 8);
            alumno.nivel = clamp(alumno.nivel + 1, 1, 100);
        }
    
        public void evaluar() {
            if (!gastarMana(4)) return;
            prestigio += 2;
            prestigio = clamp(prestigio, 0, 100);
        }
    
        @Override
        public int lanzarHechizo(String hechizo) {
            // Profesor: coste menor y resultados más estables
            int coste = 6;
            if (!gastarMana(coste)) return 0;
    
            // “Daño controlado”
            if (hechizo.equalsIgnoreCase("Expelliarmus")) return 14;
            if (hechizo.equalsIgnoreCase("Stupefy")) return 17;
            if (hechizo.equalsIgnoreCase("Lumos")) return 5;
            if (hechizo.equalsIgnoreCase("Alohomora")) return 7;
    
            return 0;
        }
    
        public String getAsignatura() {
            return asignatura;
        }
    }
    

    7) Main.java (sin listas de Mago, tipos concretos)

    package app;
    
    import modelo.*;
    
    public class Main {
    
        public static void main(String[] args) {
    
            Aprendiz harry = new Aprendiz("Harry", Casa.GRYFFINDOR);
            Aprendiz hermione = new Aprendiz("Hermione", Casa.RAVENCLAW);
    
            Hechicero draco = new Hechicero("Draco", Casa.SLYTHERIN);
            Hechicero luna = new Hechicero("Luna", Casa.HUFFLEPUFF);
    
            Auror kingsley = new Auror("Kingsley", Casa.HUFFLEPUFF);
            Profesor snape = new Profesor("Snape", Casa.SLYTHERIN, "Pociones");
    
            System.out.println("=== FICHAS INICIALES ===");
            System.out.println(harry.ficha());
            System.out.println(hermione.ficha());
            System.out.println(draco.ficha());
            System.out.println(luna.ficha());
            System.out.println(kingsley.ficha());
            System.out.println(snape.ficha());
    
            System.out.println("\n=== RONDA 1: PRACTICAR Y ESTUDIAR ===");
            harry.practicarBasico();
            hermione.practicarBasico();
            draco.estudiarEnBiblioteca();
            luna.estudiarEnBiblioteca();
            kingsley.patrullar();
            snape.evaluar();
    
            System.out.println(harry.ficha());
            System.out.println(hermione.ficha());
            System.out.println(draco.ficha());
            System.out.println(luna.ficha());
            System.out.println(kingsley.ficha());
            System.out.println(snape.ficha());
    
            System.out.println("\n=== RONDA 2: DUELO SIMPLE (daño a vida) ===");
            int d1 = draco.lanzarHechizo("Stupefy");
            harry.recibirDaño(d1);
            System.out.println("Draco lanza Stupefy a Harry. Daño: " + d1);
            System.out.println("Harry -> " + harry.ficha());
    
            int d2 = harry.lanzarHechizo("Lumos");
            draco.recibirDaño(d2);
            System.out.println("Harry lanza Lumos a Draco (sí, es cutre). Daño: " + d2);
            System.out.println("Draco -> " + draco.ficha());
    
            System.out.println("\n=== RONDA 3: PROFESOR EN ACCIÓN ===");
            snape.enseñar(harry);
            System.out.println("Snape enseña a Harry (baja torpeza y sube nivel).");
            System.out.println("Harry -> " + harry.ficha());
    
            System.out.println("\n=== RONDA 4: AUROR Y PROTEGO ===");
            int d3 = kingsley.lanzarHechizo("Stupefy");
            luna.recibirDaño(d3);
            System.out.println("Kingsley lanza Stupefy a Luna. Daño: " + d3);
            System.out.println("Luna -> " + luna.ficha());
    
            kingsley.lanzarHechizo("Protego");
            System.out.println("Kingsley usa Protego (se cura un poco).");
            System.out.println("Kingsley -> " + kingsley.ficha());
    
            System.out.println("\n=== RONDA 5: INTENTO DE ARRESTO ===");
            // Bajamos a propósito la vida de Hermione para probar arresto
            hermione.recibirDaño(85);
            System.out.println("Hermione queda débil: " + hermione.ficha());
    
            boolean arresto = kingsley.arrestar(hermione);
            System.out.println("¿Kingsley arresta a Hermione? " + arresto);
            System.out.println("Arrestos de Kingsley: " + kingsley.getArrestos());
        }
    }
    
    Aquí el alumnado ve claramente la herencia: cada clase tiene lo suyo.
    
    
    
    
    

    El conocimiento es poder… pero en Hogwarts, también lo es la herencia bien diseñada.