Package prop.hex.domini.controladors

Source Code of prop.hex.domini.controladors.PartidaCtrl

package prop.hex.domini.controladors;

import prop.cluster.domini.models.estats.EstatCasella;
import prop.cluster.domini.models.estats.EstatPartida;
import prop.hex.domini.controladors.IA.InteligenciaArtificialHexCtrl;
import prop.hex.domini.models.*;
import prop.hex.domini.models.enums.CombinacionsColors;
import prop.hex.domini.models.enums.ModesInici;
import prop.hex.domini.models.enums.TipusJugadors;
import prop.hex.gestors.PartidaHexGstr;
import prop.hex.gestors.RanquingGstr;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;
import java.util.Set;

/**
* Controlador de partida per al joc Hex. Programat seguint el patró singleton.
* Gestiona tot el flux d'execució d'una partida al joc de taula Hex a més de la càrrega i materialització de
* partides en memòria secundària.
* <p/>
* Internament, els jugadors estan indexats per posició en un array; el jugador A es troba en la posició 0 i el B en
* la posició 1.
*
* @author Isaac Sánchez Barrera (Grup 7.3, Hex)
*/
public final class PartidaCtrl
{

  /**
   * Instància del controlador. Feta així perquè segueix el patró <em>singleton</em>.
   *
   * @see #getInstancia()
   */
  private static PartidaCtrl instancia;

  /**
   * Instància amb la partida que s'està executant actualment.
   */
  private PartidaHex partida_actual;

  /**
   * Estat de la darrera partida. Es fa servir quan es finalitza la partida, per no tenir problemes d'accés a
   * punters nuls.
   *
   * @see #consultaEstatPartida()
   */
  private EstatPartida estat_darrera_partida = null;

  /**
   * Conté els usuaris preinicialitzats de la partida actual. Únicament son útils abans d'inicialitzar una partida.
   *
   * @see #preInicialitzaUsuariPartida(int, TipusJugadors, String, String)
   */
  private UsuariHex[] usuaris_preinicialitzats_partida;

  /**
   * Instàncies de les intel·ligències artificials per als jugadors no humans.
   *
   * @see #inicialitzaIAJugadors()
   */
  private InteligenciaArtificialHexCtrl[] ia_jugadors;

  /**
   * Constructor per defecte. Declarat privat perquè és una classe singleton.
   *
   * @see #getInstancia()
   */
  private PartidaCtrl()
  {
    netejaParametresPartidaActual();
  }

  /**
   * Neteja els paràmetres de la partida actual.
   * <p/>
   * S'encarrega d'esborrar tots els paràmetres de control sobre la partida que s'està jugant.
   */
  public final void netejaParametresPartidaActual()
  {
    partida_actual = null;
    usuaris_preinicialitzats_partida = new UsuariHex[2];
    ia_jugadors = new InteligenciaArtificialHexCtrl[2];
  }

  /**
   * Consultora de la instància actual del controlador de partida.
   * Si encara no s'ha inicialitzat l'objecte, crida el constructor. Si ja s'ha instanciat prèviament,
   * simplement retorna l'instancia ja creada.
   *
   * @return L'objecte singleton amb el el controlador de partida.
   * @see #instancia
   */
  public static synchronized PartidaCtrl getInstancia()
  {
    if ( instancia == null )
    {
      instancia = new PartidaCtrl();
    }

    return instancia;
  }

  /**
   * Comprova la consistència dels fitxers necessaris per al programa. Entre ells,
   * els fitxers amb les dades dels jugadors d'intel·ligència artificial i el del rànquing.
   * <p/>
   * L'estat real del joc pot seguir sent inconsistent, ja que si s'esborra un jugador manualment del directori de
   * dades no desapareix de les estadístiques. De la mateixa manera, si s'esborra el fitxer amb el rànquing aquest
   * no serà del tot correcte fins que tots els jugadors que havien jugat tornin a jugar.
   *
   * @throws IOException            Si hi ha algun problema d'entrada/sortida quan intentem llegir o crear el
   *                                rànquing o les intel·ligències artificials.
   * @throws ClassNotFoundException Si no es troben les classes UsuariHex o Ranquing.
   * @see RanquingGstr
   * @see UsuariCtrl#creaUsuari(String, String, TipusJugadors)
   */
  public static void comprovaConsistenciaFitxersIDades() throws IOException, ClassNotFoundException
  {
    // Comprovo la consistència del rànquing (si no existeix a disc el creo, si ja existeix el carrego a memòria)
    // Si no existeix el fitxer del rànquing, el creo
    if ( RanquingGstr.getInstancia().existeixElement() )
    {
      RanquingGstr.getInstancia().carregaElement();
    }

    // Comprovo consistència de jugadors màquina (han de figurar tots els usuaris de tipus màquina a disc)
    for ( TipusJugadors tipus_jugador_maquina : TipusJugadors.obteLlistatMaquines() )
    {
      if ( !UsuariCtrl.getInstancia().existeixUsuari( tipus_jugador_maquina.getNomUsuari() ) )
      {
        UsuariCtrl.getInstancia().creaUsuari( tipus_jugador_maquina.getNomUsuari(), "", tipus_jugador_maquina );
      }
    }

    RanquingGstr.getInstancia().guardaElement();
  }

  /**
   * Preinicialitza els usuaris que disputaran la partida.
   * <p/>
   * Carrega l'usuari corresponent al tipus de jugador seleccionat comprovant les credencials en cas que toqui,
   * carregant de disc la versió corresponent de la IA o instanciant un usuari convidat temporal si és el cas.
   * Cal cridar a aquesta funció abans d'inicialitzar la partida mitjançant inicialitzaPartida.
   *
   * @param num_jugador        Número de jugador que es vol preinicialitzar (0 si és el jugador A, 1 si és el B)
   * @param tipus_jugador      Tipus de jugador que es vol preinicialitzar
   * @param nom_usuari         Nom de l'usuari d'aquest jugador
   * @param contrasenya_usuari Contrasenya de l'usuari associat a aquest jugador
   * @throws IllegalArgumentException Si la contrasenya de l'usuari és incorrecta.
   * @throws FileNotFoundException    Si no es troba el fitxer amb les dades de l'usuari.
   * @throws IOException              Si hi ha algun problema d'entrada/sortida quan intentem carregar l'usuari de disc.
   * @throws ClassNotFoundException   Si no es troba la classe UsuariHex quan s'intenta carregar l'usuari de disc.
   * @throws NullPointerException     Si el fitxer de l'usuari és buit.
   * @see UsuariHex#UsuariHex(String, String, TipusJugadors)
   * @see UsuariCtrl#carregaUsuari(String, String, TipusJugadors)
   */
  public void preInicialitzaUsuariPartida( int num_jugador, TipusJugadors tipus_jugador, String nom_usuari,
                                           String contrasenya_usuari )
      throws IllegalArgumentException, FileNotFoundException, IOException, ClassNotFoundException,
             NullPointerException
  {
    UsuariCtrl usuari_ctrl = UsuariCtrl.getInstancia();

    // Si l'usuari a establir és de tipus jugador, comprovem si es tracta de l'usuari principal del joc,
    // en aquest cas, simplement l'establim. Si és el jugador secundari, comprovem les seves credencials.
    if ( TipusJugadors.JUGADOR == tipus_jugador )
    {
      if ( 0 == num_jugador || usuari_ctrl.getUsuariPrincipal().getNom().equals( nom_usuari ) )
      {
        usuaris_preinicialitzats_partida[num_jugador] = usuari_ctrl.getUsuariPrincipal();
      }
      else
      {
        usuaris_preinicialitzats_partida[num_jugador] =
            usuari_ctrl.carregaUsuari( nom_usuari, contrasenya_usuari, tipus_jugador );
      }
    }
    else if ( TipusJugadors.CONVIDAT == tipus_jugador )
    {
      // Si l'usuari a establir es de tipus convidat, creem un UsuariHex temporal amb el nom donat. Si no té
      // nom, en posem un de prefixat.
      if ( nom_usuari == null || nom_usuari.equals( "" ) )
      {
        nom_usuari = String.format( "Convidat %d", num_jugador + 1 );
      }
      usuaris_preinicialitzats_partida[num_jugador] = new UsuariHex( nom_usuari, "", tipus_jugador );
    }
    else
    {
      // Si l'usuari a establir es de tipus màquina, simplement el carregaré de disc
      usuaris_preinicialitzats_partida[num_jugador] =
          usuari_ctrl.carregaUsuari( tipus_jugador.getNomUsuari(), "", tipus_jugador );
    }
  }

  /**
   * Inicialitza les estructures de control per a la partida actual.
   *
   * @throws ClassNotFoundException Si no es pot carregar la classe de les intel·ligències artificials.
   * @throws IllegalAccessError     Si s'intenta accedir a un lloc no permès quan es carreguen les intel·ligències
   *                                artificials.
   * @throws InstantiationError     Si hi ha problemes amb la instanciació de les intel·ligències artificials.
   * @see #ia_jugadors
   * @see prop.hex.domini.controladors.IA.InteligenciaArtificialHexCtrl#obteMoviment(EstatCasella)
   * @see TipusJugadors
   */
  private void inicialitzaIAJugadors() throws ClassNotFoundException, IllegalAccessException, InstantiationException
  {
    ia_jugadors[0] = ( InteligenciaArtificialHexCtrl ) Class.forName( "prop.hex.domini.controladors.IA." +
                                                                      ( partida_actual.getJugadorA() )
                                                                          .getTipusJugador()
                                                                          .getClasseCorresponent() )
        .newInstance();
    ia_jugadors[0].setPartida( partida_actual );

    ia_jugadors[1] = ( InteligenciaArtificialHexCtrl ) Class.forName( "prop.hex.domini.controladors.IA." +
                                                                      ( partida_actual.getJugadorB() )
                                                                          .getTipusJugador()
                                                                          .getClasseCorresponent() )
        .newInstance();
    ia_jugadors[1].setPartida( partida_actual );
  }

  /**
   * Inicialitza una partida nova. Li assigna les preferències de l'usuari principal actual.
   *
   * @param mida_tauler      Mida del tauler de la partida.
   * @param nom_partida      Nom de la partida.
   * @param situacio_inicial Indica si la partida ve definida amb una situació inicial
   * @throws NullPointerException     Si no s'han preinicialitzat els usuaris de la partida prèviament.
   * @throws IllegalArgumentException Si no s'ha especificat un nom de partida o si ja existeix una partida amb
   *                                  aquest identificador
   * @throws ClassNotFoundException   Si no es pot carregar la classe de les intel·ligències artificials.
   * @throws InstantiationException   Si hi ha problemes amb la instanciació de les intel·ligències artificials.
   * @throws IllegalAccessException   Si s'intenta accedir a un lloc no permès quan es carreguen les
   *                                  intel·ligències artificials.
   * @see #usuaris_preinicialitzats_partida
   * @see PartidaHex#PartidaHex(UsuariHex, UsuariHex, TaulerHex, String, ModesInici, CombinacionsColors, boolean)
   */
  public void inicialitzaPartida( int mida_tauler, String nom_partida, boolean situacio_inicial )
      throws NullPointerException, IllegalArgumentException, ClassNotFoundException, InstantiationException,
             IllegalAccessException
  {
    if ( null == usuaris_preinicialitzats_partida[0] || null == usuaris_preinicialitzats_partida[1] )
    {
      throw new NullPointerException(
          "No s'han preinicialitzat els usuaris de la partida abans d'intentar-la crear." );
    }
    else if ( nom_partida.isEmpty() )
    {
      throw new IllegalArgumentException( "S'ha de definir un nom per poder començar la partida." );
    }
    else
    {
      partida_actual = new PartidaHex( usuaris_preinicialitzats_partida[0], usuaris_preinicialitzats_partida[1],
          new TaulerHex( mida_tauler ), nom_partida,
          UsuariCtrl.getInstancia().getUsuariPrincipal().getModeInici(),
          UsuariCtrl.getInstancia().obteCombinacioColors(), situacio_inicial );

      if ( PartidaHexGstr.getInstancia().existeixElement( partida_actual.getIdentificadorUnic() ) )
      {
        throw new IllegalArgumentException(
            "Ja existeix una partida amb aquest nom i per aquests usuaris a la mateixa data." );
      }

      inicialitzaIAJugadors();
    }
  }

  /**
   * Carrega de memòria secundària la partida identificada per identificador_partida i la estableix com la partida
   * en joc.
   *
   * @param id_partida              Identificador de la partida que es vol carregar
   * @param contrasenya_contrincant Contrasenya de l'usuari contrincant
   * @throws IOException            Si no es pot carregar la partida
   * @throws ClassNotFoundException Si no existeix la classe PartidaHex o la de la intel·ligència artificial.
   * @throws IllegalAccessError     Si hi ha un problema d'accés al fitxer amb la partida
   * @throws InstantiationError     Si hi ha un problema de classes a la instanciació de la partida que es vol
   *                                carregar
   * @see #inicialitzaIAJugadors()
   * @see PartidaHexGstr
   * @see UsuariCtrl#getUsuariPrincipal()
   */
  public void carregaPartida( String id_partida, String contrasenya_contrincant )
      throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException
  {
    partida_actual = PartidaHexGstr.getInstancia().carregaElement( id_partida );
    String nom_usuari_contrincant;
    TipusJugadors tipus_jugador_contrincant;
    if ( !partida_actual.getJugadorA().equals( UsuariCtrl.getInstancia().getUsuariPrincipal() ) )
    {
      nom_usuari_contrincant = partida_actual.getJugadorA().getNom();
      tipus_jugador_contrincant = partida_actual.getJugadorA().getTipusJugador();

      usuaris_preinicialitzats_partida[0] = UsuariCtrl.getInstancia()
          .carregaUsuari( nom_usuari_contrincant, contrasenya_contrincant, tipus_jugador_contrincant );
      usuaris_preinicialitzats_partida[1] = UsuariCtrl.getInstancia().getUsuariPrincipal();
    }
    else
    {
      nom_usuari_contrincant = partida_actual.getJugadorB().getNom();
      tipus_jugador_contrincant = partida_actual.getJugadorB().getTipusJugador();

      usuaris_preinicialitzats_partida[0] = UsuariCtrl.getInstancia().getUsuariPrincipal();
      usuaris_preinicialitzats_partida[1] = UsuariCtrl.getInstancia()
          .carregaUsuari( nom_usuari_contrincant, contrasenya_contrincant, tipus_jugador_contrincant );
    }

    partida_actual.setJugadorA( usuaris_preinicialitzats_partida[0] );
    partida_actual.setJugadorB( usuaris_preinicialitzats_partida[1] );

    inicialitzaIAJugadors();

    PartidaHexGstr.getInstancia().eliminaElement( id_partida );

    partida_actual.setInstantDarrerMoviment( new Date().getTime() );
  }

  /**
   * Elimina de memòria secundària la partida identificada per id_partida.
   *
   * @param id_partida Identificador de la partida que es vol eliminar
   */
  public void eliminaPartida( String id_partida )
  {
    PartidaHexGstr.getInstancia().eliminaElement( id_partida );
  }

  /**
   * Consulta quin usuari no ha iniciat sessió (si és el cas) per poder jugar a la partida actual.
   *
   * @param id_partida Identificador únic de la partida
   * @return El nom de l'usuari que no ha iniciat sessió (si és el cas). Si no n'hi ha, retorna null.
   * @throws IOException            Si no es pot carregar la partida
   * @throws ClassNotFoundException Si no existeix la classe PartidaHex.
   * @throws IllegalAccessError     Si hi ha un problema d'accés al fitxer amb la partida
   * @throws InstantiationError     Si hi ha un problema de classes a la instanciació de la partida que es vol
   *                                consultar
   * @see PartidaHexGstr#carregaElement(String)
   */
  public String usuariSenseAutenticarAPartida( String id_partida )
      throws IOException, ClassNotFoundException, IllegalAccessError, InstantiationError
  {
    String nom_usuari = null;

    PartidaHex partida_futura = PartidaHexGstr.getInstancia().carregaElement( id_partida );
    if ( !partida_futura.getJugadorA().equals( UsuariCtrl.getInstancia().getUsuariPrincipal() ) &&
         partida_futura.getJugadorA().getTipusJugador() == TipusJugadors.JUGADOR )
    {
      nom_usuari = partida_futura.getJugadorA().getNom();
    }
    else if ( !partida_futura.getJugadorB().equals( UsuariCtrl.getInstancia().getUsuariPrincipal() ) &&
              partida_futura.getJugadorB().getTipusJugador() == TipusJugadors.JUGADOR )
    {
      nom_usuari = partida_futura.getJugadorB().getNom();
    }

    return nom_usuari;
  }

  /**
   * Consulta les partides de l'usuari principal
   *
   * @return Una llista amb les dades de les partides. Dins de cada element de la llista, els elements són
   *         <ol start="0">
   *         <li>Identificador únic de la partida</li>
   *         <li>Nom de la partida</li>
   *         <li>Nom d'usuari de l'oponent (contra qui juga l'usuari principal de la sessió, no de la partida)</li>
   *         <li>String formatat amb la data i hora d'inici de la partida</li>
   *         </ol>
   * @see PartidaHexGstr#llistaPartidesUsuari(String)
   */
  public String[][] llistaPartidesUsuari()
  {
    String id_usuari = UsuariCtrl.getInstancia().getUsuariPrincipal().getIdentificadorUnic();
    Set<String> id_partides = PartidaHexGstr.getInstancia().llistaPartidesUsuari( id_usuari );
    String[][] llista_partides = new String[id_partides.size()][4];
    int i = 0;
    for ( String id_partida : id_partides )
    {
      String[] info_partida = new String[4];
      String[] camps = id_partida.split( "@" );

      // L'identificador s'inclou perquè el controlador de presentació pugui demanar la partida concreta.
      info_partida[0] = id_partida;

      // Es formaten la data i l'hora perquè no ho hagi de fer la vista.
      info_partida[3] = String.format( "%1$td/%1$tm/%1$tY %1$tR", Long.valueOf( camps[0] ) * 1000L );

      info_partida[1] = camps[1].replace( '-', ' ' );
      if ( id_usuari.equals( camps[2] ) )
      {
        info_partida[2] = camps[3].replace( '-', ' ' );
      }
      else
      {
        info_partida[2] = camps[2].replace( '-', ' ' );
      }

      llista_partides[i] = info_partida;
      i++;
    }

    return llista_partides;
  }

  /**
   * Esborra les partides d'un usuari
   *
   * @param id_usuari Identificador únic de l'usuari de qui es volen esborrar les partides.
   * @return Cert si s'han esborrat. Fals altrament.
   * @see PartidaHexGstr#eliminaElement(String)
   */
  public boolean eliminaPartidesUsuari( String id_usuari )
  {
    Set<String> id_partides = PartidaHexGstr.getInstancia().llistaPartidesUsuari( id_usuari );
    boolean resultat = true;
    for ( String id_partida : id_partides )
    {
      resultat = resultat && PartidaHexGstr.getInstancia().eliminaElement( id_partida );
    }

    return resultat;
  }

  /**
   * Guarda la partida actual.
   * <p/>
   * Cal tenir en compte que només es poden guardar les partides amb algun usuari registrat i que, a més,
   * no hagin finalitzat.
   *
   * @return Cert si s'ha guardat correctament. Fals altrament.
   * @throws FileNotFoundException         Si no existeix el fitxer que de la partida que es desa.
   * @throws IOException                   Si hi ha un error d'entrada/sortida
   * @throws UnsupportedOperationException Si es vol guardar una partida ja finalitzada o cap dels usuaris és
   *                                       registrat.
   * @see PartidaHexGstr#guardaElement(prop.hex.domini.models.PartidaHex)
   */
  public boolean guardaPartida() throws IOException, UnsupportedOperationException
  {
    if ( partida_actual.estaFinalitzada() )
    {
      throw new UnsupportedOperationException( "La partida ja ha finalitzat" );
    }
    else if ( partida_actual.getJugadorA().getTipusJugador() != TipusJugadors.JUGADOR &&
              partida_actual.getJugadorB().getTipusJugador() != TipusJugadors.JUGADOR )
    {
      throw new UnsupportedOperationException(
          "Per guardar la partida cal que un dels jugadors estigui registrat" );
    }
    else
    {
      return PartidaHexGstr.getInstancia().guardaElement( partida_actual );
    }
  }

  /**
   * Per una partida que té situació inicial, estableix que aquesta ja està acabada de definir.
   */
  public void acabaDeDefinirSituacioInicial()
  {
    partida_actual.setSituacioInicialAcabadaDeDefinir();
  }

  /**
   * Indica si la en la partida actual s'ha definit la situació inicial.
   */
  public boolean esPartidaAmbSituacioInicial()
  {
    return partida_actual.teSituacioInicial();
  }

  /**
   * Finalitza la partida actual.
   * <p/>
   * Actualitza les estadístiques dels usuaris si la partida ja ha finalitzat i no ha començat
   * definint una situació inicial.
   *
   * @see #consultaEstatPartida()
   * @see PartidaHex
   * @see PartidaHexGstr#eliminaElement(String)
   * @see Ranquing#actualitzaRanquingUsuari(prop.hex.domini.models.UsuariHex)
   * @see RanquingGstr#guardaElement()
   */
  public void finalitzaPartida() throws IOException
  {
    EstatPartida estat_actual = consultaEstatPartida();

    // Si la partida ha finalitzat i no ha començat definint una situació inicial,
    // actualitzem les estadístiques d'usuari
    if ( estat_actual != EstatPartida.NO_FINALITZADA )
    {
      // Si la partida està guardada, l'eliminem
      PartidaHexGstr.getInstancia().eliminaElement( partida_actual.getIdentificadorUnic() );

      // Si no ha començat definint situació inicial, actualitzem estadístiques d'usuari
      if ( !partida_actual.teSituacioInicial() )
      {
        UsuariHex usuari_a = partida_actual.getJugadorA();
        UsuariHex usuari_b = partida_actual.getJugadorB();

        if ( usuari_a.getTipusJugador() != TipusJugadors.CONVIDAT )
        {
          UsuariCtrl.getInstancia()
              .actualitzaEstadistiques( usuari_a, estat_actual == EstatPartida.GUANYA_JUGADOR_A,
                  usuari_b.getTipusJugador(), partida_actual.getTempsDeJoc( 0 ),
                  partida_actual.getTauler().getNumFitxesA() );

          Ranquing.getInstancia().actualitzaRanquingUsuari( usuari_a );
        }

        if ( usuari_b.getTipusJugador() != TipusJugadors.CONVIDAT )
        {
          UsuariCtrl.getInstancia()
              .actualitzaEstadistiques( usuari_b, estat_actual == EstatPartida.GUANYA_JUGADOR_B,
                  usuari_a.getTipusJugador(), partida_actual.getTempsDeJoc( 1 ),
                  partida_actual.getTauler().getNumFitxesB() );

          Ranquing.getInstancia().actualitzaRanquingUsuari( usuari_b );
        }
      }
    }

    // Guardem el rànquing al disc
    try
    {
      RanquingGstr.getInstancia().guardaElement();
    }
    catch ( IOException excepcio )
    {
      throw new IOException( "No s'ha pogut desar el ranquing" );
    }
  }

  /**
   * Tanca la partida actual i crea una de revenja si és el cas. Si es fa una revenja, intercanvia l'usuari que ha
   * jugat al primer torn pel segon.
   *
   * @param revenja Indica si es vol crear una partida de revenja.
   * @throws ClassNotFoundException Si no es pot carregar la classe de les intel·ligències artificials.
   * @throws InstantiationException Si hi ha problemes amb la instanciació de les intel·ligències artificials.
   * @throws IllegalAccessException Si s'intenta accedir a un lloc no permès quan es carreguen les intel·ligències
   *                                artificials.
   */
  public void tancaPartida( boolean revenja )
      throws ClassNotFoundException, InstantiationException, IllegalAccessException
  {
    if ( revenja )
    {
      UsuariHex auxiliar = usuaris_preinicialitzats_partida[0];
      usuaris_preinicialitzats_partida[0] = usuaris_preinicialitzats_partida[1];
      usuaris_preinicialitzats_partida[1] = auxiliar;

      inicialitzaPartida( partida_actual.getTauler().getMida(), partida_actual.getNom(), false );
    }
    else
    {
      netejaParametresPartidaActual();
    }
  }

  /**
   * Consulta una pista per al jugador que la demana.
   *
   * @return La casella on mouria la intel·ligència artificial configurada per a les pistes.
   * @see #getMovimentIATornActual()
   * @see PartidaHex#incrementaPistesUsades(int, int)
   */
  public Casella obtePista()
  {
    partida_actual.incrementaPistesUsades( getNumJugadorTornActual(), 1 );
    return getMovimentIATornActual();
  }

  /**
   * Executa un moviment d'una intel·ligència artificial (cal que sigui el seu torn)
   *
   * @return La casella on mou la intel·ligència artificial.
   * @see #getMovimentIATornActual()
   */
  public Casella executaMovimentIA()
  {
    partida_actual.setInstantDarrerMoviment( new Date().getTime() );
    Casella resultat_moviment = getMovimentIATornActual();
    mouFitxa( resultat_moviment.getFila(), resultat_moviment.getColumna() );

    return resultat_moviment;
  }

  /**
   * Mou la fitxa del jugador que toca segons el torn a la casella indicada per (fila, columna).
   * <p/>
   * Actualitza les estadístiques i propietats corresponents a la partida.
   *
   * @param fila    Fila de la casella
   * @param columna Columna de la casella
   * @return Cert si s'ha mogut la fitxa. Fals altrament.
   * @throws UnsupportedOperationException Si la partida ja ha finalitzat.
   * @see Casella
   * @see TaulerHex#esMovimentValid(EstatCasella, Casella)
   * @see TaulerHex#mouFitxa(EstatCasella, Casella)
   * @see PartidaHex#setDarreraFitxa(Casella)
   * @see PartidaHex#incrementaTempsDeJoc(int, long)
   * @see PartidaHex#incrementaTornsJugats(int)
   */
  public boolean mouFitxa( int fila, int columna ) throws UnsupportedOperationException
  {
    if ( partida_actual.estaFinalitzada() )
    {
      throw new UnsupportedOperationException( "La partida ja ha finalitzat" );
    }
    else
    {
      Casella destinacio = new Casella( fila, columna );
      if ( !partida_actual.getTauler().esMovimentValid( getTipusFitxesJugadorTornActual(), destinacio ) )
      {
        return false;
      }
      else
      {
        if ( partida_actual.getTauler().mouFitxa( getTipusFitxesJugadorTornActual(), destinacio ) )
        {
          partida_actual.setDarreraFitxa( destinacio );

          long instant_actual = new Date().getTime();

          partida_actual.incrementaTempsDeJoc( getNumJugadorTornActual(),
              instant_actual - partida_actual.getInstantDarrerMoviment() );

          partida_actual.incrementaTornsJugats( 1 );

          // Per actualitzar l'estat de la partida en el controlador.
          consultaEstatPartida();

          partida_actual.setInstantDarrerMoviment( instant_actual );

          return true;
        }
        else
        {
          return false;
        }
      }
    }
  }

  /**
   * Consulta si una casella és central.
   *
   * @param fila    Fila de la casella dins el tauler.
   * @param columna Columna de la casella dins el tauler.
   * @return Cert si la casella (fila, columna) és central. Fals altrament.
   * @throws IllegalArgumentException Si (fila, columna) no és una casella vàlida.
   * @see TaulerHex#esCasellaCentral(int, int)
   */
  public boolean esCasellaCentral( int fila, int columna ) throws IndexOutOfBoundsException
  {
    return partida_actual.getTauler().esCasellaCentral( fila, columna );
  }

  /**
   * Consulta l'estat de la partida.
   *
   * @return L'estat de la partida (si guanya algun jugador o encara no està finalitzada).
   * @see PartidaHex#comprovaEstatPartida(int, int)
   * @see PartidaHex#setFinalitzada(boolean)
   */
  public EstatPartida consultaEstatPartida()
  {
    if ( partida_actual != null )
    {
      estat_darrera_partida = partida_actual.comprovaEstatPartida();
      partida_actual.setFinalitzada( estat_darrera_partida != EstatPartida.NO_FINALITZADA );
    }

    return estat_darrera_partida;
  }

  /**
   * Intercanvia la darrera fitxa d'un jugador per l'altre. Útil si s'aplica la regla del pastís.
   *
   * @return Cert si s'ha canviat la fitxa. Fals altrament.
   * @see TaulerHex#intercanviaFitxa(Casella)
   * @see PartidaHex#incrementaTornsJugats(int)
   */
  public boolean intercanviaDarreraFitxa()
  {
    return esPotIntercanviarDarreraFitxa() &&
           ( partida_actual.getTauler() ).intercanviaFitxa( partida_actual.getDarreraFitxa() ) &&
           partida_actual.incrementaTornsJugats( 1 );
  }

  /**
   * Consulta si es pot intercanviar la darrera fitxa.
   *
   * @return Cert si es pot (està la regla del pastís i hi ha només una fitxa). Fals altrament.
   * @see #esReglaPastis()
   */
  public boolean esPotIntercanviarDarreraFitxa()
  {
    return ( partida_actual.getTornsJugats() == 1 && esReglaPastis() );
  }

  /**
   * Consulta si el joc actual té la regla del pastís.
   *
   * @return Cert si comença amb la regla del pastís. Fals altrament.
   * @see ModesInici#PASTIS
   */
  public boolean esReglaPastis()
  {
    return partida_actual.getModeInici() == ModesInici.PASTIS;
  }

  /**
   * Obté la partida actual en joc.
   *
   * @return PartidaHex amb la partida actual. Si no s'està jugant cap partida, o aquesta ha finalitzat,
   *         retorna null.
   */
  public PartidaHex getPartidaActual()
  {
    return partida_actual;
  }

  // Métodes auxiliars depenents del torn actual
  // ----------------------------------------------------------------------------------------------------------------

  /**
   * Consulta el número del jugador del torn actual. A juga els torns parells (comencen per 0) i B els senars.
   *
   * @return Retorna el número del jugador del torn actual (0 si és A, 1 si és B).
   * @see PartidaHex#getTornsJugats()
   */
  private int getNumJugadorTornActual()
  {
    return partida_actual.getTornsJugats() % 2;
  }

  /**
   * Retorna el jugador A o B depenent dels torns que s'hagin jugat
   *
   * @return jugador A o B depenent dels torns que s'hagin jugat
   * @see #getNumJugadorTornActual()
   */
  private UsuariHex obteJugadorTornActual()
  {
    if ( 0 == getNumJugadorTornActual() )
    {
      return partida_actual.getJugadorA();
    }
    else
    {
      return partida_actual.getJugadorB();
    }
  }

  /**
   * Consulta quin moviment faria la intel·ligència artificial del torn actual. Si és un torn humà,
   * fa servir la intel·ligència artificial de les pistes.
   *
   * @return El moviment que faria la intel·ligència artificial corresponent.
   * @see prop.hex.domini.controladors.IA.InteligenciaArtificialHexCtrl#obteMoviment(EstatCasella)
   */
  private Casella getMovimentIATornActual()
  {
    return ia_jugadors[getNumJugadorTornActual()].obteMoviment( getTipusFitxesJugadorTornActual() );
  }

  /**
   * Consulta si és un torn humà. Necessari perquè el controlador de presentació sàpiga si demanar un moviment
   * d'intel·ligència artificial al controlador o esperar que l'usuari esculli una casella.
   *
   * @return Cert si el jugador és humà. Fals altrament.
   * @see TipusJugadors
   */
  public boolean esTornHuma()
  {
    TipusJugadors tipus_jugador_actual = obteJugadorTornActual().getTipusJugador();

    return ( TipusJugadors.JUGADOR == tipus_jugador_actual || TipusJugadors.CONVIDAT == tipus_jugador_actual );
  }

  /**
   * Consulta amb quines fitxes juga el jugador del torn actual.
   *
   * @return El tipus de fitxa que fa servir el jugador del torn actual.
   * @see #getNumJugadorTornActual()
   * @see PartidaHex#getTipusFitxesJugador(int)
   */
  private EstatCasella getTipusFitxesJugadorTornActual()
  {
    return partida_actual.getTipusFitxesJugador( getNumJugadorTornActual() );
  }

  // Mètodes auxiliars per les vistes
  // ----------------------------------------------------------------------------------------------------------------

  /**
   * Consulta quin és l'estat de la casella en el moment actual.
   *
   * @param fila    Fila de la casella dins el tauler
   * @param columna Columna de la casella dins el tauler
   * @return L'estat de la casella (fila, columna).
   * @throws IndexOutOfBoundsException Si (fila, columna) no és una casella vàlida.
   * @see TaulerHex#getEstatCasella(int, int)
   */
  public EstatCasella getEstatCasella( int fila, int columna ) throws IndexOutOfBoundsException
  {
    return partida_actual.getTauler().getEstatCasella( fila, columna );
  }

  /**
   * Consulta els elements de control de la partida per a la vista.
   *
   * @return Els elements de control de la partida necessaris per a la capa de presentació. Aquests són
   *         <ol start="0">
   *         <li>Nombre màxim de pistes</li>
   *         <li>Mida del tauler</li>
   *         <li>Total de torns jugats</li>
   *         <li>Combinació de colors</li>
   *         <li>Mode d'inici</li>
   *         </ol>
   * @see CombinacionsColors
   * @see ModesInici
   */
  public Object[] getElementsDeControlPartida()
  {
    Object[] elements_de_control = new Object[5];

    elements_de_control[0] = PartidaHex.getMaxNumPistes();
    elements_de_control[1] = partida_actual.getTauler().getMida();
    elements_de_control[2] = partida_actual.getTornsJugats();
    elements_de_control[3] = partida_actual.getCombinacioColors();
    elements_de_control[4] = partida_actual.getModeInici();

    return elements_de_control;
  }

  /**
   * Consulta els element de control dels jugadors de la partida per a la vista.
   *
   * @return Els elements de control dels jugadors de la partida necessaris per a la capa de presentació. Aquests són
   *         <ol start="0">
   *         <li>Tipus de jugador</li>
   *         <li>Pistes usades pel jugador</li>
   *         <li>Temps de joc (en segons) del jugador</li>
   *         <li>Nom del jugador</li>
   *         <li>Número de fitxes del jugador</li>
   *         </ol>
   *         <p/>
   *         I, dins de cada element, els índexs 0 i 1 contenen dades del jugadors A i B respectivament.
   * @see TipusJugadors
   */
  public Object[][] getElementsDeControlJugadors()
  {
    Object[][] elements_de_control = new Object[5][2];

    elements_de_control[0][0] = partida_actual.getJugadorA().getTipusJugador();
    elements_de_control[1][0] = partida_actual.getPistesUsades( 0 );
    elements_de_control[2][0] = String.valueOf( partida_actual.getTempsDeJoc( 0 ) / 1000L ) + "." +
                                ( partida_actual.getTempsDeJoc( 0 ) % 1000L ) / 100 + " s";
    elements_de_control[3][0] = partida_actual.getJugadorA().getNom();
    elements_de_control[4][0] = partida_actual.getTauler().getNumFitxesA();
    elements_de_control[0][1] = partida_actual.getJugadorB().getTipusJugador();
    elements_de_control[1][1] = partida_actual.getPistesUsades( 1 );
    elements_de_control[2][1] = String.valueOf( partida_actual.getTempsDeJoc( 1 ) / 1000L ) + "." +
                                ( partida_actual.getTempsDeJoc( 1 ) % 1000L ) / 100 + " s";
    elements_de_control[3][1] = partida_actual.getJugadorB().getNom();
    elements_de_control[4][1] = partida_actual.getTauler().getNumFitxesB();

    return elements_de_control;
  }
}
TOP

Related Classes of prop.hex.domini.controladors.PartidaCtrl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.