Logica_Piezas_Caballeria.js

import Pieza from '../Pieza.js';

/**
 * Clase que representa la pieza de Caballería en el juego.
 * @class Caballeria
 * @extends Pieza
 * @memberof Logica
 */
class Caballeria extends Pieza {
    /**
     * Constructor de la pieza Caballería.
     * @param {Tablero} tablero - tablero al que pertenece la pieza
     * @param {number} fil - fila
     * @param {number} col - columna
     * @param {string} jugador - 'J1' o 'J2'
     */
    constructor(tablero, fil, col, jugador) {
        super(tablero, 'Caballeria', fil, col, jugador, 3, 2, 0);
        this.saltoCaballeria = true;
        this.pesoBase = 2;
    }

    /**
     * Establece si la caballería puede saltar piezas.
     * @param {boolean} salto 
     */
    setSaltoCaballeria(salto) {
        this.saltoCaballeria = salto;
    }

    /**
     * Determina si la caballería puede saltar piezas.
     * @returns {boolean} - true si la caballería puede saltar piezas, false en caso contrario
     */
    getSaltoCaballeria() {
        return this.saltoCaballeria;
    }

    calculaPeso() {
        let bestCelda = null; // Guarda la celda que será atacada por formación
        let bestPeso = 0; // Mejor peso encontrado durante el análisis
        const celdasVisitadas = new Set(); // Evita procesar la misma celda múltiples veces
        celdasVisitadas.add(this.tablero.getCelda(this.fil, this.col));


        // Obtener celdas vecinas directas (distancia 1: arriba, abajo, izquierda, derecha)
        const celdasVecinas = this.getVecinos(this.tablero.getCelda(this.fil, this.col), celdasVisitadas, false);

        // Primera pasada: analizar vecinos directos en busca de enemigos y formaciones
        for (const vecino of celdasVecinas) {
            celdasVisitadas.add(vecino.celda);
            
            if (!vecino.celda.estaVacia() && vecino.celda.getPieza().getJugador() === 'J1' && !vecino.salto) {
                const result = this.detectaTipo(vecino.celda);
                if (result > bestPeso) {
                    bestPeso = result;
                    bestCelda = vecino.celda;
                }
            }
            
            if (vecino.celda.estaVacia()) {
                const segVecinos = this.getVecinos(vecino.celda, celdasVisitadas, true);
                
                for (const segVecino of segVecinos) {
                    celdasVisitadas.add(segVecino.celda);
                    
                    if (!segVecino.celda.estaVacia() && segVecino.celda.getPieza().getJugador() === 'J1') {
                        const segResult = this.detectaTipo(segVecino.celda);
                        if (segResult > bestPeso) {
                            bestPeso = segResult;
                            bestCelda = segVecino.celda;
                        }
                    }
                    
                    if (vecino.salto === false) {
                        if (segVecino.celda.estaVacia()) {
                            const terVecinos = this.getVecinos(segVecino.celda, celdasVisitadas, true);
                            
                            for (const terVecino of terVecinos) {
                                celdasVisitadas.add(terVecino.celda);
                                
                                const terResult = this.detectaTipo(terVecino.celda);
                                if (terResult > bestPeso) {
                                    bestPeso = terResult;
                                    bestCelda = terVecino.celda;
                                }
                            }
                        }
                    }
                }
            }
        }

        // DEBUG: Pintar celdas comprobadas

        return { peso: (bestPeso + this.pesoBase), bestCelda: bestCelda};
    }

    /**
 * Detecta el tipo de pieza en una celda y devuelve su valor táctico
 * Solo cuenta piezas del jugador 'J1' (enemigo)
 * @param {Celda} celda - Celda a analizar
 * @returns {number} Peso según tipo de pieza enemiga (0 si vacía o aliada)
 */
    detectaTipo(celda) {
        let peso = 0;
        // Solo contabiliza piezas enemigas del jugador J1
        if (!celda.estaVacia() && celda.getPieza().getJugador() === 'J1') {
            switch (celda.getPieza().getTipo()) {
                case 'Soldado':
                    peso = 1;
                    break;
                case 'Caballeria':
                    peso = 2;
                    break;
                case 'Artilleria':
                    peso = 3;
                    break;
                case 'Comandante':
                    peso = 4;
                    break;
                
            }
        }
        return peso;
    }

    /**
     * Obtiene las celdas vecinas válidas (arriba, abajo, izquierda, derecha)
     * Excluye vecinos fuera del tablero o ya visitados
     * @param {Celda} celda - Celda central desde la que buscar vecinos
     * @param {Set<Celda>} celdasVisitadas - Set de celdas ya procesadas (evita repeticiones)
     * @returns {Array<Celda>} Array de celdas vecinas válidas
     */
    getVecinos(celda, celdasVisitadas, salto) {
        const pos = celda.getPosicion();
        const fila = pos.fila;
        const col = pos.col;
        const res = [];
        let haSaltado = false;

        // Arriba
        if (fila > 0 && !celdasVisitadas.has(this.tablero.getCelda(fila - 1, col))) {
            let celdaArriba = this.tablero.getCelda(fila - 1, col);
            if (fila > 1 && !celdaArriba.estaVacia() && celdaArriba.getPieza().getJugador() === 'J2' && !salto) {
                const sigCelda = this.tablero.getCelda(fila - 2, col);
                if (sigCelda.estaVacia()) {
                    celdasVisitadas.add(celdaArriba);
                    celdaArriba = sigCelda;
                    haSaltado = true;
                }
            }
            res.push({ celda: celdaArriba, salto: haSaltado });
        }
        haSaltado = false;
        // Izquierda
        if (col > 0 && !celdasVisitadas.has(this.tablero.getCelda(fila, col - 1))) {
            let celdaIzquierda = this.tablero.getCelda(fila, col - 1);
            if (fila > 1 && !celdaIzquierda.estaVacia() && celdaIzquierda.getPieza().getJugador() === 'J2' && !salto) {
                const sigCelda = this.tablero.getCelda(fila, col - 2);
                if (sigCelda.estaVacia()) {
                    celdasVisitadas.add(celdaIzquierda);
                    celdaIzquierda = sigCelda;
                    haSaltado = true;
                }
            }
            res.push({ celda: celdaIzquierda, salto: haSaltado });
        }
        haSaltado = false;
        // Abajo
        if (fila < this.tablero.filas - 1 && !celdasVisitadas.has(this.tablero.getCelda(fila + 1, col))) {
            let celdaAbajo = this.tablero.getCelda(fila + 1, col);
            if (fila < this.tablero.filas - 2 && !celdaAbajo.estaVacia() && celdaAbajo.getPieza().getJugador() === 'J2' && !salto) {
                const sigCelda = this.tablero.getCelda(fila + 2, col);
                if (sigCelda.estaVacia()) {
                    celdasVisitadas.add(celdaAbajo);
                    celdaAbajo = sigCelda;
                    haSaltado = true;
                }
            }
            res.push({ celda: celdaAbajo, salto: haSaltado });
        }
        haSaltado = false;
        // Derecha
        if (col < this.tablero.columnas - 1 && !celdasVisitadas.has(this.tablero.getCelda(fila, col + 1))) {
            let celdaDerecha = this.tablero.getCelda(fila, col + 1);
            if (col < this.tablero.columnas - 2 && !celdaDerecha.estaVacia() && celdaDerecha.getPieza().getJugador() === 'J2' && !salto) {
                const sigCelda = this.tablero.getCelda(fila, col + 2);
                if (sigCelda.estaVacia()) {
                    celdasVisitadas.add(celdaDerecha);
                    celdaDerecha = sigCelda;
                    haSaltado = true;
                }
            }
            res.push({ celda: celdaDerecha, salto: haSaltado });
        }

        return res;
    }

}

export default Caballeria;