Nappula.java

package datastructureproject.luokat.nappulat;

import chess.model.Side;
import datastructureproject.luokat.Pelilauta;
import datastructureproject.luokat.apulaiset.ShakkiApu;
import datastructureproject.luokat.tietorakenteet.*;

/**
 * Kuvaa shakkinappulaa
 */
public abstract class Nappula {
    private Ruutu ruutu;
    protected Side puoli;
    protected char merkki;

    /**
     * 
     * @param merkki tata nappulaa kuvaava merkki
     * @param puoli kumpi pelaaja omistaa taman nappulan
     * @param ruutu nappulan sijainti pelilaudalla
     */
    public Nappula(char merkki, Side puoli, Ruutu ruutu) {
        this.merkki = merkki;
        this.puoli = puoli;
        this.ruutu = ruutu;
    }

    public Side getPuoli() {
        return puoli;
    }

    public int getX() {
        return ruutu.getX();
    }

    public int getY() {
        return ruutu.getY();
    }

    public void setRuutu(Ruutu r) {
        this.ruutu = r;
    }

    public void setRuutu(int x, int y) {
        this.ruutu.setX(x);
        this.ruutu.setY(y);
    }

    public Ruutu getRuutu() {
        return ruutu;
    }

    /**
     * Palauttaa nappulan y-akselin sijainnnin, kun sitä liikutetaan eteenpäin y-askelta
     * (toimii molemmilla puolilla)
     * 
     * @param y y-akselin askeleiden määrä
     * @return y-akselin koordinaatti
     */
    protected int getEteenpainY(int y) {
        return getRuutu().getEteenpainY(getPuoli(), y);
    }

    /**
     * 
     * @param lauta pelilaudan tilanne
     * @return mahdolliset siirrot tässä pelitilanteessa
     */
    public abstract Lista<Siirto> generoiSiirrot(Pelilauta lauta);

    /**
     * Palauttaa nappulan sallitut siirrot, kun se saa liikkua tiettyihin suuntiin loputtomasti. 
     * Tiettyyn suuntaan siirtojen etsiminen lopetetaan, kun mennään pelilaudan reunan yli
     * tai päädytään syömään vastustajan nappula. 
     * 
     * @param lauta pelitilanne pelilautana
     * @param suunnat suunnat joihin nappula saa liikkua
     * @return lista siirroista, joita nappula saa liikkua annettuihin suuntiin
     */
    protected Lista<Siirto> generoiSuoratSiirrot(Pelilauta lauta, int[][] suunnat) {
        Lista<Siirto> siirrot = new Lista<>();
        for (int[] pari: suunnat) {
            Ruutu r = getRuutu().kopioi();
            r.addX(pari[0]);
            r.addY(pari[1]);
            while (r.olenLaudalla(lauta)) {
                Nappula n = lauta.getNappula(r);
                if (n == null) {
                    siirrot.add(new Siirto(getRuutu().kopioi(), r.kopioi()));
                } else {
                    if (n.getPuoli() != getPuoli()) {
                        siirrot.add(new Siirto(getRuutu().kopioi(), r.kopioi()));
                    }
                    break;
                }
                
                r.addX(pari[0]);
                r.addY(pari[1]);
            }
        }

        return siirrot;
    }

    /**
     * Kopioi nappulan, niin että kopio ja alkuperäinen eivät vaikuta toisiinsa (deep copy)
     * @return kopio tästä nappulasta
     */
    public abstract Nappula kopioi();

    /**
     * 
     * 
     * @param lauta katseltava pelitilanne
     * @return onko tämä nappula uhattuna tässä tilanteessa
     */
    public boolean olenUhattuna(Pelilauta lauta) {
        Lista<Siirto> vastustajanLiikkeet = lauta.generoiSiirrot(ShakkiApu.vastustaja(getPuoli()));

        for (int i = 0; i < vastustajanLiikkeet.size(); i++) {
            Siirto s = vastustajanLiikkeet.get(i);
            if (s.getKohde().getX() == getX() &&  s.getKohde().getY() == getY()) {
                return true;
            }
        }

        return false;
    }

    public char getMerkki() {
        return this.getPuoli() == Side.WHITE ? merkki : versitaaliksi(merkki);
    }

    private static char versitaaliksi(char c) {
        switch (c) {
            case 'r':
                return 'R';
            case 'n':
                return 'N';
            case 'b':
                return 'B';
            case 'q':
                return 'Q';
            case 'k':
                return 'K';
            case 'p':
                return 'P';
            default:
                return '0';
        }
    }
    
}