/**
   * Este metodo marca un nuevo moviemiento realizado por el jugador pasado en parametro. La fila y
   * la columna indican el lugar del movimiento. El sistema guarda el movimiento en la cola de
   * movimientos del juego.
   *
   * @param fila numero de 0 a 2
   * @param columna numero de 0 a 2
   * @param jugador numero de 1 a 2 puede ser las constantes JUGADOR o COMPUTADORA
   */
  public void nuevoMovimiento(int fila, int columna, int jugador) throws TresEnRayaException {

    Jugada nueva = null;
    if (!movimientos.estaVacia()) {
      Jugada ultima = movimientos.ultimo();
      nueva = ultima.clonar();
    } else {
      nueva = new Jugada();
    }

    logger.debug(
        "Movimiento del jugador " + jugador + " a filaXcolumna: " + fila + " x " + columna);
    nueva.marcar(fila, columna, jugador);
    if (nueva.haGanado(jugador)) {
      estado = TERMINADO;
      quienGano = jugador;
    }

    movimientos.insertarAlFinal(nueva);

    quienJuega = (jugador == JUGADOR ? COMPUTADORA : JUGADOR);

    this.setChanged();
    this.notifyObservers();
  }
  /**
   * Luego de elegir entre las posibles jugadas, este metodo devuelve las coordenadas que nos llevan
   * a esa jugada elegida.
   *
   * @param jugador
   * @return
   */
  public int[] elegirMovimiento(int jugador) {
    Jugada ultima = movimientos.ultimo();

    Arbol<Jugada> arbolDecision = crearArbol(ultima, jugador);
    logger.debug("El arbol de decision tiene " + arbolDecision.cantidadNodos() + " nodos");
    logger.debug("El arbol de decision tiene profundidad " + arbolDecision.altura() + " nodos");
    logger.debug("El arbol de decision tiene grado " + arbolDecision.grado());

    this.numeroNodosUltima = arbolDecision.cantidadNodos();

    Jugada decision = elegirJugada(arbolDecision, jugador);

    int[] movida = ultima.coordenadaParaLlegarA(decision);

    return movida;
  }
  /**
   * Crea un arbol de TODOS los posibles movimientos a partir de una jugada. Este metodo puede ser
   * bastantee pesado ya que puede crear un arbol de varios miles de nodos al menos para la primera
   * jugada. Alternativamente luego de cada jugada cambia de jugador para simular TODAS las posibles
   * jugadas.
   *
   * @param movida
   * @param jugador
   * @return
   */
  public Arbol<Jugada> crearArbol(Jugada movida, int jugador) {
    Arbol<Jugada> result = new Arbol<Jugada>();

    Arbol.Nodo<Jugada> nodoRaiz = result.insertarHijo(null, movida);

    Cadena<Jugada> posiblesJugadas = movida.getPosiblesJugadas(jugador);
    int otroJugador = (jugador == JUGADOR ? COMPUTADORA : JUGADOR);

    Iterator<Jugada> iter = posiblesJugadas.iterator();
    while (iter.hasNext()) {
      Jugada hijo = iter.next();
      Arbol.Nodo<Jugada> nodoHijo = result.insertarHijo(nodoRaiz, hijo);
      Arbol<Jugada> arbolHijo = crearArbol(hijo, otroJugador);

      nodoHijo.colocarHijosDeRaizDeArbol(arbolHijo);
    }

    return result;
  }