From f325a586d351abe4ac2d37ff6fec57d1627aa51c Mon Sep 17 00:00:00 2001 From: Araozu Date: Sun, 27 Dec 2020 13:07:33 -0500 Subject: [PATCH] Actualizar la funcion que maneja descartes --- src/juego/Juego.kt | 147 +++++++++++-------------------------------- src/juego/Jugador.kt | 71 ++++++++++++++++++++- src/juego/Mano.kt | 37 ++++++++++- 3 files changed, 142 insertions(+), 113 deletions(-) diff --git a/src/juego/Juego.kt b/src/juego/Juego.kt index 70cd471..15c61d8 100644 --- a/src/juego/Juego.kt +++ b/src/juego/Juego.kt @@ -8,8 +8,8 @@ class Juego(val usuarios: ArrayList>) { private val cartas: Array = GestorJuegos.generarCartas() internal var jugadores = Array(4) { JugadorBot(this, "Bot $it") } + private var ordenJugadores = Array(4) { jugadores[it].idUsuario } - private val ordenJugadores = Array(4) { "" } private var gestorDora = GestorDora(cartas) private var estadoJuego = EstadoJuego.Espera private var posCartaActual = 10 @@ -17,55 +17,40 @@ class Juego(val usuarios: ArrayList>) { private var dragonPartida = Dragon.Negro private var oportunidadesRestantes = 0 - suspend fun iniciarJuego(ws: WebSocketSession) { + suspend fun iniciarJuego() { if (estadoJuego != EstadoJuego.Espera) return - if (conexiones.size < 4) { - ws.send(Frame.Text("{\"operacion\": \"error\", \"razon\": \"Usuarios insuficientes\"}")) - return - } - estadoJuego = EstadoJuego.Iniciado - // Asignar orden de jugadores - var i = 0 - val posInicio = (Math.random() * 4).toInt() - conexiones.forEach { (idUsuario, _) -> - ordenJugadores[i] = idUsuario - val dragonActual = Dragon.get(i) + val nuevoArrJugadores = Array(4) { JugadorBot(this, "-") } + val jugadoresRestantes = arrayListOf(0, 1, 2, 3) + for (i in 0 until 4) { + val nuevoIndice = (Math.random() * jugadoresRestantes.size).toInt() + nuevoArrJugadores[i] = jugadores[nuevoIndice] + jugadoresRestantes.remove(nuevoIndice) + } + + dragonPartida = Dragon.get((Math.random() * 4).toInt()) + + for ((i, jugador) in nuevoArrJugadores.withIndex()) { val cartasL = arrayListOf() - for (j in posCartaActual until (posCartaActual + 10)) { cartasL.add(cartas[j]) } posCartaActual += 10 - val mano = if (i == posInicio) { - val sigCarta = cartas[posCartaActual] - posCartaActual++ - gestorDora.actualizarDora() - dragonPartida = dragonActual - posJugadorActual = i - - Mano(cartasL, sigCarta = sigCarta, dragon = dragonActual) - } else { - Mano(cartasL, dragon = dragonActual) - } - - manos[idUsuario] = mano - i++ + jugador.inicializarCartas(cartasL) + jugador.inicializarDragon(Dragon.get(i)) + jugador.send(Frame.Text("{\"operacion\": \"juego_iniciado\"}")) } - conexiones.forEach { (_, socket) -> - socket.send(Frame.Text("{\"operacion\": \"juego_iniciado\"}")) - } - - conexiones.clear() + jugadores = nuevoArrJugadores + ordenJugadores = Array(4) { jugadores[it].idUsuario } } private fun obtenerDatosJuegoActuales(): DatosJuego { - val idJugadorTurnoActual = ordenJugadores[posJugadorActual] + val idJugadorTurnoActual = jugadores[posJugadorActual].idUsuario return DatosJuego( dora = arrayListOf(), manos = hashMapOf(), @@ -85,6 +70,8 @@ class Juego(val usuarios: ArrayList>) { } suspend fun agregarConexion(idUsuario: String, conexion: WebSocketSession) { + if (estadoJuego != EstadoJuego.Espera) return + // Buscar si el jugador ya existia jugadores.forEach { if (it.idUsuario == idUsuario) { @@ -113,95 +100,33 @@ class Juego(val usuarios: ArrayList>) { posJugadorActual = (posJugadorActual + 1) % 4 oportunidadesRestantes = 0 - val idSigUsuario = ordenJugadores[posJugadorActual] + // Si se acabaron las cartas + if (posCartaActual >= cartas.size) { + estadoJuego = EstadoJuego.Terminado + return + } - // Extraer sig carta. TODO: Verificar que no quedan cartas y establecer empate + // Sino val sigCarta = cartas[posCartaActual] posCartaActual++ - // Asignar nueva carta - val manoSigJugador = manos[idSigUsuario]!! - manoSigJugador.sigCarta = sigCarta - - // TODO: Arreglar. Roto. - val oportunidadWin = OportunidadWin.verificar(sigCarta, manoSigJugador.cartas, manoSigJugador.cartasReveladas) - if (oportunidadWin != null) { - manoSigJugador.oportunidades.add(oportunidadWin) - } - + // Asignar carta + jugadores[posJugadorActual].recibirCarta(sigCarta) + // Verificar Tsumo + jugadores[posJugadorActual].verificarTsumo() } - private fun esUsuarioIzq(idUsuarioIzq: String, idUsuario1: String): Boolean { - var posUsuario1 = 0 - var posUsuarioIzq = 0 - for ((posActual, idUsuario) in ordenJugadores.withIndex()) { - if (idUsuario == idUsuario1) posUsuario1 = posActual - if (idUsuario == idUsuarioIzq) posUsuarioIzq = posActual - } - return (posUsuarioIzq + 1) % 4 == posUsuario1 - } - - suspend fun manejarDescarte(idUsuario: String, carta: Int) { - if (ordenJugadores[posJugadorActual] != idUsuario) return + suspend fun manejarDescarte(idUsuario: String, cartaDescartada: Int) { + // Si un jugador del que no es turno intenta descartar + if (jugadores[posJugadorActual].idUsuario != idUsuario) return // Si el jugador del turno actual ya descarto, otros jugadores tienen oportunidades // e intento descartar de nuevo if (oportunidadesRestantes > 0) return - val m = manos[idUsuario]!! + val cantidadOportunidades = jugadores[posJugadorActual].descartarCarta(cartaDescartada) - if (m.sigCarta == carta) { - m.sigCarta = -1 - } else { - val posCarta = m.cartas.indexOf(carta) - if (posCarta != -1) { - m.cartas.removeAt(posCarta) - - // Tras llamar un Seq/Tri el jugador no tiene una carta adicional en su mano. - if (m.sigCarta != -1) m.cartas.add(m.sigCarta) - - m.sigCarta = -1 - } else { - return - } - } - - m.descartes.add(carta) - - // Verificar seq/tri/win - var hayOportunidades = false - for ((idUsuarioActual, mano) in manos) { - // No buscar oportunidades en el usuario que acaba de descartar. - if (idUsuarioActual == idUsuario) continue - - // Solo verificar seq en el jugador a la derecha del que descarto - if (esUsuarioIzq(idUsuario, idUsuarioActual)) { - val oportunidadSeq = OportunidadSeq.verificar(carta, mano.cartas) - if (oportunidadSeq != null) { - hayOportunidades = true - oportunidadesRestantes++ - mano.oportunidades.add(oportunidadSeq) - } - } - - // Oportunidades tri - val oportunidadTri = OportunidadTri.verificar(carta, mano.cartas) - if (oportunidadTri != null) { - hayOportunidades = true - oportunidadesRestantes++ - mano.oportunidades.add(oportunidadTri) - } - - // Oportunidades win (ron) - val oportunidadWin = OportunidadWin.verificar(carta, mano.cartas, mano.cartasReveladas) - if (oportunidadWin != null) { - hayOportunidades = true - oportunidadesRestantes++ - mano.oportunidades.add(oportunidadWin) - } - } - - if (hayOportunidades) { + if (cantidadOportunidades > 0) { // Enviar datos enviarDatosATodos() } else { diff --git a/src/juego/Jugador.kt b/src/juego/Jugador.kt index 9fc4f1c..515d5e9 100644 --- a/src/juego/Jugador.kt +++ b/src/juego/Jugador.kt @@ -13,14 +13,75 @@ sealed class Jugador(val juego: Juego, val idUsuario: String) { abstract suspend fun send(v: Frame.Text) val mano = Mano() - fun inicializarMano(cartas: ArrayList) { + fun inicializarCartas(cartas: ArrayList) { mano.cartas = cartas } + fun inicializarDragon(dragon: Dragon) { + mano.dragon = dragon + } + abstract fun actualizarConexion(ws: WebSocketSession) abstract suspend fun enviarDatos(datos: DatosJuego) + fun recibirCarta(carta: Int) { + mano.sigCarta = carta + } + + /** + * Intenta descartar una carta de la mano y devuelve si dicho descarte + * brinda oportunidades a otros jugadores + * @param cartaDescartada La carta a remover de la mano + * @return La cantidad de oportunidades + */ + fun descartarCarta(cartaDescartada: Int): Int { + val cartaFueDescartada = mano.descartarCarta(cartaDescartada) + + if (!cartaFueDescartada) return -1 + + var oportunidadesRestantes = 0 + var posicionJugadorActual = -1 + for ((i, jugador) in juego.jugadores.withIndex()) { + if (this === jugador) { + posicionJugadorActual = i + continue + } + + var hayOportunidad = false + val mano = jugador.mano + + // Verificar seq en jugador a la derecha + if ((posicionJugadorActual + 1) % 4 == i) { + val oportunidadSeq = OportunidadSeq.verificar(cartaDescartada, mano.cartas) + if (oportunidadSeq != null) { + hayOportunidad = true + mano.oportunidades.add(oportunidadSeq) + } + } + + // Oportunidades tri + val oportunidadTri = OportunidadTri.verificar(cartaDescartada, mano.cartas) + if (oportunidadTri != null) { + hayOportunidad = true + mano.oportunidades.add(oportunidadTri) + } + + // Oportunidades win (ron) + val oportunidadWin = OportunidadWin.verificar(cartaDescartada, mano.cartas, mano.cartasReveladas) + if (oportunidadWin != null) { + hayOportunidad = true + mano.oportunidades.add(oportunidadWin) + } + + if (hayOportunidad) oportunidadesRestantes++ + } + + return oportunidadesRestantes + } + + abstract fun verificarTsumo() + } class JugadorHumano(juego: Juego, idUsuario: String, private var ws: WebSocketSession) : Jugador(juego, idUsuario) { @@ -53,6 +114,10 @@ class JugadorHumano(juego: Juego, idUsuario: String, private var ws: WebSocketSe ws.send(Frame.Text("{\"operacion\": \"actualizar_datos\", \"datos\": ${gson.toJson(datosJuego)}}")) } + override fun verificarTsumo() { + System.err.println("Tsumo no implementado D:") + } + } class JugadorBot(juego: Juego, idUsuario: String) : Jugador(juego, idUsuario) { @@ -77,4 +142,8 @@ class JugadorBot(juego: Juego, idUsuario: String) : Jugador(juego, idUsuario) { } + override fun verificarTsumo() { + System.err.println("Tsumo no implementado D:") + } + } diff --git a/src/juego/Mano.kt b/src/juego/Mano.kt index 847adde..3d3938c 100644 --- a/src/juego/Mano.kt +++ b/src/juego/Mano.kt @@ -6,7 +6,7 @@ data class Mano( val descartes: ArrayList = arrayListOf(), var sigCarta: Int = -1, var oportunidades: ArrayList = arrayListOf(), - val dragon: Dragon = Dragon.Negro + var dragon: Dragon = Dragon.Negro ) { fun obtenerManoPrivada(): Mano { @@ -19,6 +19,41 @@ data class Mano( ) } + private fun validarHay10Cartas(): Boolean = + cartas.size + (cartasReveladas.size * 3) + (if (sigCarta != -1) 1 else 0) - 1 == 10 + /** + * Intenta descartar una carta de la mano y devuelve si fue correcto + * @param cartaDescartada La carta a remover de la mano + * @return true si se descarto la carta, false sino + */ + fun descartarCarta(cartaDescartada: Int): Boolean { + if (!validarHay10Cartas()) { + System.err.println("Error al descartar carta: Hacerlo dejaria al jugador con menos de 10 cartas") + return false + } + + if (sigCarta == cartaDescartada) { + sigCarta = -1 + } else { + val posCarta = cartas.indexOf(cartaDescartada) + if (posCarta != -1) { + cartas.removeAt(posCarta) + + // Incluir la carta entrante a la mano del jugador + if (sigCarta != -1) { + cartas.add(sigCarta) + } + } else { + System.err.println("Error al descartar carta: El jugador no tiene dicha carta.") + return false + } + } + + descartes.add(cartaDescartada) + return true + } + + // TODO: Cachear la mano privada y actualizarla solo cuando se llama tri/seq }