Ejemplo n.º 1
0
    def player_finished(self, player: Player) -> GameUpdate:
        """
        Finaliza la partida para un jugador en concreto.
        """

        if player.has_finished():
            raise GameLogicException("El jugador ya ha terminado")

        self._players_finished += 1
        player.position = self._players_finished

        logger.info(f"{player.name} has finished at position {player.position}")

        # Vaciamos la mano del jugador y devolvemos las cartas a la baraja
        player.empty_hand(return_to=self.deck)
        # Vaciamos el cuerpo del jugador
        player.empty_body(return_to=self.deck)

        # Generamos un GameUpdate donde:
        # 1. Avisamos a todos los jugadores de que el jugador ha acabado.
        update = GameUpdate(self)
        update.repeat({"leaderboard": self._leaderboard()})
        # 2. Mostramos las pilas vacías
        empty_piles = GameUpdate(self)
        empty_piles.repeat({"bodies": {player.name: player.body.piles}})
        update.merge_with(empty_piles)
        # 3. Le enviamos al jugador la mano vacía
        empty_hand = GameUpdate(self)
        empty_hand.add(player.name, {"hand": player.hand})
        update.merge_with(empty_hand)

        return update
Ejemplo n.º 2
0
    def piles_update(self, game: "Game") -> GameUpdate:
        """
        Genera un diccionario indicando cambios a la pila del target.
        """

        update = GameUpdate(game)
        update.repeat({"bodies": {self.target.name: self.target.body.piles}})
        return update
Ejemplo n.º 3
0
    def bodies_update(self) -> GameUpdate:
        update = GameUpdate(self)

        data = {"bodies": {}}
        for player in self.players:
            data["bodies"][player.name] = player.body.piles

        update.repeat(data)
        return update
Ejemplo n.º 4
0
    def pause_update(self) -> GameUpdate:
        update = GameUpdate(self)

        data = {
            "paused": self.is_paused(),
            "paused_by": self._paused_by,
        }

        update.repeat(data)
        return update
Ejemplo n.º 5
0
    def finish_update(self) -> GameUpdate:
        update = GameUpdate(self)

        data = {"finished": self.is_finished()}
        if self.is_finished():
            data["leaderboard"] = self._leaderboard()
            data["playtime_mins"] = self._playtime_mins()

        update.repeat(data)
        return update
Ejemplo n.º 6
0
    def time_update(self) -> GameUpdate:
        update = GameUpdate(self)

        # No se envía si no hay timer o si no ha empezado
        if self._turn_timer is None:
            return update
        remaining = self._turn_timer.remaining_secs()
        if remaining is None:
            return update

        update.repeat({"remaining_turn_secs": remaining})
        return update
Ejemplo n.º 7
0
    def players_update(self) -> GameUpdate:
        update = GameUpdate(self)

        players = []
        for player in self.players:
            data = {"name": player.name}

            if player.is_ai:
                data["picture"] = BOT_PICTURE_ID
                data["is_ai"] = True

            players.append(data)

        update.repeat({"players": players})
        return update
Ejemplo n.º 8
0
    def apply(self, action: "PlayCard", game: "Game") -> GameUpdate:
        self.get_action_data(action, game)

        # Comprobamos que la pila tiene órgano
        if self.organ_pile.is_empty():
            raise GameLogicException("No puedes robar órganos inexistentes")

        # Comprobamos que ninguno de los dos órganos está inmunizado
        if self.organ_pile.is_immune():
            raise GameLogicException("No puedes robar órganos inmunes")

        # Comprobamos que el caller no tiene ya un órgano de ese color
        if not action.caller.body.organ_unique(self.organ_pile.organ):
            raise GameLogicException("Ya tienes un órgano de ese color")

        # Comprobamos que no se va a robar un órgano a sí mismo
        if action.caller == self.target:
            raise GameLogicException("No puedes robarte un órgano a ti mismo")

        # Obtenemos un espacio libre del caller
        self.empty_slot = None
        for (slot, pile) in enumerate(action.caller.body.piles):
            if pile.is_empty():
                self.empty_slot = slot
                break
        if self.empty_slot is None:
            raise GameLogicException("No tienes espacio libre")

        logger.info("organ-thief played")

        # Robamos la pila del target y la guardamos en el caller
        empty_pile = action.caller.body.piles[self.empty_slot]
        action.caller.body.piles[self.empty_slot] = self.organ_pile
        self.target.body.piles[self.organ_pile_slot] = empty_pile

        update = GameUpdate(game)
        # Añadimos el cuerpo del caller al GameUpdate
        update.repeat({
            "bodies": {
                self.target.name: self.target.body.piles,
                action.caller.name: action.caller.body.piles,
            },
        })

        update.msg = f"un Ladrón de Órganos sobre {self.target.name}"
        return update
Ejemplo n.º 9
0
    def apply(self, action: "PlayCard", game: "Game") -> GameUpdate:
        self.get_action_data(action, game)

        # Comprobamos que las dos pilas tienen órgano
        if self.organ_pile1.is_empty() or self.organ_pile2.is_empty():
            raise GameLogicException(
                "No puedes intercambiar órganos inexistentes")

        # Comprobamos que ninguno de los dos órganos está inmunizado
        if self.organ_pile1.is_immune() or self.organ_pile2.is_immune():
            raise GameLogicException("No puedes intercambiar órganos inmunes")

        # Comprobamos que no se haga un transplante a sí mismo.
        if self.player1 == self.player2:
            raise GameLogicException(
                "No puedes intercambiar óganos entre el mismo jugador")

        # Comprobamos que ninguno de los dos jugadores tienen ya un órgano del
        # mismo color del órgano a añadir. NOTE: Ignoramos las pilas sobre las
        # que se va a reemplazar, porque no crean conflicto.
        if not (self.player1.body.organ_unique(self.organ_pile2.organ,
                                               ignored_piles=[self.pile_slot1])
                and self.player2.body.organ_unique(
                    self.organ_pile1.organ, ignored_piles=[self.pile_slot2])):
            raise GameLogicException("Ya tiene un órgano de ese color")

        logger.info("transplant played")

        update = GameUpdate(game)

        # Intercambiamos las pilas de ambos jugadores
        tmp = self.player1.body.piles[self.pile_slot1]
        self.player1.body.piles[self.pile_slot1] = self.player2.body.piles[
            self.pile_slot2]
        self.player2.body.piles[self.pile_slot2] = tmp
        # Añadimos los dos cuerpos al GameUpdate
        update.repeat({
            "bodies": {
                self.player1.name: self.player1.body.piles,
                self.player2.name: self.player2.body.piles,
            },
        })

        update.msg = f"un Transplante entre {self.player1.name} y {self.player2.name}"
        return update
Ejemplo n.º 10
0
    def apply(self, action: "PlayCard", game: "Game") -> GameUpdate:
        self.get_action_data(action, game)

        if action.caller == self.target:
            raise GameLogicException(
                "No puedes intercambiar tu cuerpo contigo mismo")

        logger.info("medical-error played")

        update = GameUpdate(game)

        # Intercambiamos los cuerpos de ambos jugadores
        action.caller.body, self.target.body = self.target.body, action.caller.body
        # Añadimos los dos cuerpos al GameUpdate
        update.repeat({
            "bodies": {
                self.target.name: self.target.body.piles,
                action.caller.name: action.caller.body.piles,
            },
        })

        update.msg = f"un Error Médico sobre {self.target.name}"
        return update
Ejemplo n.º 11
0
 def current_turn_update(self) -> GameUpdate:
     update = GameUpdate(self)
     update.repeat({"current_turn": self.turn_player().name})
     return update
Ejemplo n.º 12
0
    def apply(self, action: "PlayCard", game: "Game") -> GameUpdate:
        logger.info("infection played")

        # Diccionario: color -> lista de pilas con virus de ese color
        virus = dict()
        for color in Color:
            virus[color] = []

        # Listamos los virus que tiene en el cuerpo accediendo en orden
        # aleatorio a las pilas.
        for pile in random.sample(action.caller.body.piles, 4):
            if pile.is_infected():
                color = pile.get_top_color()
                virus[color].append(pile)

        if all(map(lambda x: len(x) == 0, virus.values())):
            raise GameLogicException("No tienes virus disponibles")

        # Lista de pilas libres de todos los jugadores
        candidates = []

        # Accederemos a los jugadores en orden aleatorio
        unfinished = game.get_unfinished_players()
        random.shuffle(unfinished)
        for player in unfinished:
            # Eliminamos al caller de la iteración
            if player == action.caller:
                continue

            # Añadimos las pilas libres a la lista de candidatas
            candidates.extend(
                list(filter(lambda p: p.is_free(), player.body.piles)))

        if len(candidates) == 0:
            raise GameLogicException(
                "No hay nadie que pueda recibir tus virus")

        # Aplicamos un orden aleatorio también a las pilas candidatas
        for candidate_pile in random.sample(candidates, len(candidates)):
            color = candidate_pile.get_top_color()

            # Asignamos el primer virus de ese color y lo quitamos de los
            # posibles.

            if len(virus[color]) == 0:
                # Si no hay virus de ese color -> comprobamos si hay virus
                # multicolor
                if len(virus[Color.All]) > 0:
                    color = Color.All
                else:  # No tenemos opción
                    continue

            pile = virus[color].pop()
            # Eliminamos el virus del cuerpo del caller
            pile.pop_modifiers()
            # Lo colocamos en la pila candidata
            candidate_pile.add_modifier(Virus(color=color))

        # Por simplificar, devolvemos el cuerpo de todos los jugadores
        update = GameUpdate(game)
        for player in game.players:
            body_update = GameUpdate(game)
            body_update.repeat({"bodies": {player.name: player.body.piles}})
            update.merge_with(body_update)

        update.msg = "un Contagio"
        return update