package com.rzg.zombieland.server.juego;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import com.rzg.zombieland.comunes.comunicacion.ProyeccionTablero;
import com.rzg.zombieland.comunes.comunicacion.ProyeccionTablero.POJOEntidad;
import com.rzg.zombieland.comunes.misc.Coordenada;
import com.rzg.zombieland.server.sesion.Jugador;
/**
* El tablero de juego, que contiene obst�culos, humanos y zombies.
*
* @author Nicolas, Manuel
*
*/
public class Tablero {
// El tablero en s�, con todos sus actores. Incluidos obst�culos.
private EntidadTablero[][] matriz;
// Jugadores que participan - Humanos solamente.
private List<Personaje> personajes;
// Listado de personajes convertidos en el orden en el que se convirtieron. El primero siempre
// es el zombie original.
private List<Personaje> jugadoresConvertidos;
/**
* Constructor por defecto. Aqu� se generar�n los obst�culos en forma
* 'aleatoria'
*/
public Tablero(int casilleros, List<? extends Jugador> jugadores, Jugador zombi) {
personajes = new ArrayList<Personaje>();
jugadoresConvertidos = new ArrayList<Personaje>();
Random rnd = new Random(); // Que quede claro que va a ser una cuesti�n
// de suerte
boolean resuelto = false; // Flag que me indica si ya posicione o no a
// la entidad.
matriz = new EntidadTablero[casilleros][casilleros];
// Ponemos al zombi - primero le asignamos el nombre.
Zombie personajeZombie = new Zombie(zombi, new Coordenada(casilleros / 2, casilleros / 2), this);
jugadoresConvertidos.add(personajeZombie);
personajes.add(personajeZombie);
// Siempre arranca en el medio.
matriz[casilleros / 2][casilleros / 2] = personajeZombie; // Lo ponemos
// en la
// matriz.
// Ponemos los obstaculos. Si la matriz es de 10x10, son 100 casilleros.
// Con 25 obst�culos estariamos bien -- Ser�a el 25%
// Con el 30%, usando el algoritmo aleatorio, puede terminar en un bucle
// infinito. Cosas que pasan.
// Totalmente aleatorio - Resultado: En 10 corridas,
// 4 veces encerr� a un jugador.
// Verificando que en las diagonales tampoco haya obstaculos -
// Resultado: Luz verde. En 100000 corridas, luz verde.
for (int i = 0; i < Math.pow(casilleros, 2) * 0.25; i++) {
resuelto = false;
while (!resuelto) {
Coordenada c = new Coordenada(Math.abs(rnd.nextInt()) % casilleros, Math.abs(rnd.nextInt())
% casilleros);
if (matriz[c.getX()][c.getY()] == null
&& matriz[c.getX() + 1 >= casilleros ? c.getX() : c.getX() + 1][c.getY() + 1 >= casilleros ? c
.getY() : c.getY() + 1] == null
&& matriz[c.getX() - 1 < 0 ? c.getX() : c.getX() - 1][c.getY() + 1 >= casilleros ? c
.getY() : c.getY() + 1] == null
&& matriz[c.getX() + 1 >= casilleros ? c.getX() : c.getX() + 1][c.getY() - 1 < 0 ? c
.getY() : c.getY() - 1] == null
&& matriz[c.getX() - 1 < 0 ? c.getX() : c.getX() - 1][c.getY() - 1 < 0 ? c
.getY() : c.getY() - 1] == null) {
matriz[c.getX()][c.getY()] = new Obstaculo(c);
resuelto = true;
}
}
}
// Ponemos a los humanos
for (Jugador jugador : jugadores) {
if (jugador == zombi)
continue;
resuelto = false;
while (!resuelto) {
Coordenada c = new Coordenada(Math.abs(rnd.nextInt()) % casilleros, Math.abs(rnd.nextInt())
% casilleros);
if (matriz[c.getX()][c.getY()] == null) {
Humano h = new Humano(jugador, c, this);
matriz[c.getX()][c.getY()] = h;
resuelto = true;
personajes.add(h);
}
}
}
}
/**
* @param superiorIzquierda
* @param inferiorDerecha
* @param tiempoTurno - el tiempo en milisegundos para que arranque el siguiente turno.
* @return la proyecci�n del tablero entre las dos esquinas dadas.
*/
private ProyeccionTablero getProyeccion(Coordenada superiorIzquierda,
Coordenada inferiorDerecha,
int tiempoTurno) {
superiorIzquierda = normalizar(superiorIzquierda);
inferiorDerecha = normalizar(inferiorDerecha);
List<POJOEntidad> entidades = new ArrayList<POJOEntidad>();
// Recorro mi matriz de entidades en los limites indicados por el
// metodo.
for (int i = superiorIzquierda.getX(); i <= inferiorDerecha.getX(); i++) {
for (int j = superiorIzquierda.getY(); j <= inferiorDerecha.getY(); j++) {
if (matriz[i][j] != null) {
// Agrego las entidades que encuentre a la lista de la
// proyeccion
entidades.add(new POJOEntidad("Elemento" + i + j, new Coordenada(i, j),
matriz[i][j].getAvatar()));
}
}
}
// Devuelvo la proyecci�n. Chiche bomb�n.
return new ProyeccionTablero(
matriz.length, superiorIzquierda, inferiorDerecha, entidades, tiempoTurno);
}
/**
* @param coordenada
* @return una coordenada que se ajusta a los l�mites del tablero de acuerdo a la coordanada
* dada.
*/
private Coordenada normalizar(Coordenada coordenada) {
if (coordenada.getX() >= matriz.length)
coordenada = new Coordenada(matriz.length - 1, coordenada.getY());
else if (coordenada.getX() < 0)
coordenada = new Coordenada(0, coordenada.getY());
if (coordenada.getY() >= matriz.length)
coordenada = new Coordenada(coordenada.getX(), matriz.length - 1);
else if (coordenada.getY() < 0)
coordenada = new Coordenada(coordenada.getX(), 0);
return coordenada;
}
/**
* Obtiene la entidad por coordenada.
*
* @param coordenada
* @return la entidad en la coordenada dada, o null si no hay ninguna.
*/
public EntidadTablero getEntidadEn(Coordenada coordenada) {
return matriz[coordenada.getX()][coordenada.getY()];
}
/**
* Mueve una entidad.
*
* @param desde
* - coordenada donde la entidad original se encuentra.
* @param hasta
* - coordenada de destino. Debe estar vac�a.
*/
public synchronized Coordenada moverEntidad(Coordenada desde, Coordenada hasta) {
// Primero pregunto si a la posici�n a la cual quiere desplazarse no hay
// nada
if (fueraDeLaMatriz(desde)) {
throw new InvalidParameterException(
"La coordenada desde est� fuera de los l�mites de la matriz");
}
if (fueraDeLaMatriz(hasta)) {
// No se mueva nada.
return desde;
}
if (matriz[hasta.getX()][hasta.getY()] == null) {
matriz[hasta.getX()][hasta.getY()] = matriz[desde.getX()][desde.getY()];
matriz[desde.getX()][desde.getY()] = null;
return hasta;
} else {
getEntidadEn(desde).colisionar(getEntidadEn(hasta));
getEntidadEn(hasta).colisionar(getEntidadEn(desde));
return desde;
}
}
/**
* @param coordenada
* @return true si la coordenada est� fuera de la matriz, false de lo contrario.
*/
private boolean fueraDeLaMatriz(Coordenada coordenada) {
return (coordenada.getX() >= matriz.length || coordenada.getX() < 0 ||
coordenada.getY() >= matriz.length || coordenada.getY() < 0);
}
/**
* Mueve a todos los personajes.
*/
public void moverTodos() {
synchronized (personajes) {
// Ordenamos los personajes de acuerdo al orden en el que realizaron los
// movimientos.
Collections.sort(personajes, new Comparator<Personaje>() {
@Override
public int compare(Personaje p1, Personaje p2) {
return p1.compareTo(p2);
}
});
for (Personaje personaje : personajes)
personaje.mover();
}
}
/**
* Quita a un jugador del tablero.
* @param jugadorEliminado
*/
public void removerJugador(Jugador jugadorEliminado) {
synchronized (personajes) {
boolean quedanZombies = false;
Iterator<Personaje> iterator = personajes.iterator();
while (iterator.hasNext()) {
Personaje personaje = iterator.next();
if (personaje.getJugador().getId().equals(jugadorEliminado.getId())) {
iterator.remove();
matriz[personaje.getPosicion().getX()][personaje.getPosicion().getY()] = null;
} else if (personaje.esZombie()) {
quedanZombies = true;
}
}
if (!quedanZombies) {
int index = new Random().nextInt(personajes.size());
Personaje personaje = personajes.get(index);
Coordenada posicion = personaje.getPosicion();
Zombie zombie = new Zombie(personaje.getJugador(), posicion, this);
personajes.set(index, zombie);
matriz[posicion.getX()][posicion.getY()] = zombie;
}
}
}
/**
* @return true si la partida finaliz�, false de lo contrario.
*/
public boolean partidaFinalizada() {
synchronized (personajes) {
for (Personaje personaje : personajes) {
if (!personaje.esZombie())
return false;
}
}
return true;
}
/**
* Remplaza la entidad en el tablero con la dada.
* @param posicion
* @param zombie
*/
public void remplazarEntidadEn(Coordenada posicion, Zombie zombie) {
synchronized (personajes) {
for (int i = 0; i < personajes.size(); i++) {
Personaje personaje = personajes.get(i);
if (personaje.getJugador().getId().equals(zombie.getJugador().getId()))
personajes.set(i, zombie);
}
}
matriz[posicion.getX()][posicion.getY()] = zombie;
}
public ProyeccionTablero getProyeccionJugador(Jugador jugador, int tiempoTurno) {
Personaje personajeJugador = null;
synchronized (personajes) {
for (Personaje personaje : personajes) {
if (personaje.getJugador().getId().equals(jugador.getId())) {
personajeJugador = personaje;
break;
}
}
}
Coordenada[] rectanguloVision;
if (personajeJugador == null) {
// Es la proyecci�n para un espectador.
rectanguloVision = new Coordenada[] {
new Coordenada(0, 0),
new Coordenada(matriz.length - 1, matriz.length - 1)
};
} else {
rectanguloVision = personajeJugador.getRectanguloVision();
}
return getProyeccion(rectanguloVision[0], rectanguloVision[1], tiempoTurno);
}
/**
* @return la esquina inferior derecha del tablero.
*/
public Coordenada getEsquinaInferiorDerecha() {
return new Coordenada(matriz.length - 1, matriz.length - 1);
}
/**
* @param numero - una posici�n N de jugador.
* @return el jugador que fue convertido en N lugar.
*/
public Jugador getJugadorConvertidoNumero(int numero) {
return jugadoresConvertidos.get(numero).getJugador();
}
/**
* A�ade uno al listado de personajes convertidos.
* @param personaje
*/
public void addPersonajeConvertido(Personaje personaje) {
jugadoresConvertidos.add(personaje);
}
}