Skip to content

"The Resistance" é um jogo de dedução social e blefe para 5 jogadores. O objetivo é para a equipe da Resistência (maioria) completar missões, enquanto os Espiões (minoria) tentam sabotá-las.

Notifications You must be signed in to change notification settings

itsryu/Resistance

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 

Repository files navigation

The Resistance

Este projeto é uma implementação do jogo de dedução social e blefe "The Resistance", adaptado para ser jogado em uma rede local (LAN). Ele proporciona uma experiência interativa onde os jogadores assumem papéis de Resistência ou Espiões e participam de diversas fases do jogo, como seleção de equipes, votação e sabotagem de missões.

O Jogo "The Resistance"

"The Resistance" é um jogo de dedução social e blefe para 5 jogadores. O objetivo é para a equipe da Resistência (maioria) completar missões, enquanto os Espiões (minoria) tentam sabotá-las.
Papéis:

  • Resistência: Trabalhadores leais; votam SUCESSO.
  • Espiões: Infiltrados; podem votar SUCESSO ou FALHA.
Fases do Jogo:
  1. O Líder propõe uma equipe.
  2. Os jogadores votam para aprovar ou rejeitar a equipe.
  3. Se a equipe for aprovada, os membros da equipe votam SUCESSO ou FALHA.
Condições de Vitória:
  • Resistência: Vence se 3 missões forem bem-sucedidas.
  • Espiões: Vencem se 3 missões falharem OU se 5 propostas de equipe forem rejeitadas consecutivamente.

Arquitetura do Código: Model-View-Controller (MVC)

O projeto segue o padrão arquitetural MVC para uma clara separação de responsabilidades, facilitando o desenvolvimento, a manutenção e a escalabilidade.

  • Modelo (src/models/model.py): Gerencia o estado do jogo e a lógica de negócios. Não possui conhecimento da interface do usuário ou da rede.
  • Visão (src/views/view.py, src/models/dialogs.py, src/main.py): Responsável pela interface gráfica do usuário, exibindo o estado do jogo e coletando entradas do jogador.
  • Controlador (src/controllers/controller.py): Atua como intermediário, processando entradas do usuário, atualizando o Modelo e a Visão, e gerenciando a comunicação de rede.
  • Rede (src/utils/network.py, src/models/messages.py): Camada responsável pela comunicação cliente-servidor, definindo o protocolo de mensagens.

Funcionalidades do Código

1. Modelo (src/models/model.py)

A classe GameModel encapsula todo o estado do jogo e suas regras. É o coração lógico do sistema.

  • Gerencia a atribuição de papéis (Resistência e Espião) aos jogadores.
  • Controla o placar das missões (sucessos e falhas).
  • Acompanha a rodada atual, o líder e o contador de propostas de equipe rejeitadas.
  • Processa votos de aprovação de equipe e escolhas de sabotagem.
  • Verifica as condições de vitória e determina o vencedor.
  • Oferece métodos para serializar e desserializar o estado do jogo (to_dict e from_dict), permitindo persistência.

2. Visão (src/views/view.py e src/models/dialogs.py)

Utiliza a biblioteca tkinter para construir a interface gráfica.

  • GameView (src/views/view.py): Exibe o placar, a rodada atual, o líder e um log de eventos do jogo.
  • src/models/dialogs.py: Contém classes para diálogos modais interativos (TeamSelectionDialog, YesNoDialog, MissionOutcomeDialog, GameOverDetailsDialog) que permitem aos jogadores realizar ações como selecionar equipes, votar e decidir sobre sabotagens.
  • As configurações de estilo (cores, fontes, etc.) são definidas em src/utils/settings.py e aplicadas aos widgets tkinter e ttk.

3. Controlador (src/controllers/controller.py)

Orquestra o fluxo do jogo, agindo como um ponto central de controle.

  • Inicializa o Modelo e a Visão.
  • Atua como servidor ou cliente de rede, dependendo da configuração.
  • Despacha mensagens de rede para os manipuladores apropriados.
  • Coordena as fases do jogo, solicitando entradas dos jogadores (via View) e atualizando o Modelo.
  • Responsável por salvar e carregar o estado do jogo, permitindo a retomada de partidas.

4. Rede (src/utils/network.py e src/models/messages.py)

Gerencia a comunicação entre os diferentes jogadores (clientes) e o servidor.

  • Network (classe base): Define a funcionalidade comum para enviar e receber mensagens via sockets TCP.
  • GameServer: Responsável por ouvir conexões, aceitar novos clientes e enviar mensagens para todos ou para clientes específicos.
  • GameClient: Responsável por conectar-se ao servidor e enviar/receber mensagens.
  • src/models/messages.py: Define as dataclasses para os diferentes tipos de mensagens trocadas no protocolo (ex: ConnectAckMessage, GameStateUpdateMessage, RequestTeamSelectionMessage, etc.).
  • As mensagens são serializadas/desserializadas em formato JSON para transmissão.

Uso de Threads para Concorrência e Responsividade

O projeto faz uso extensivo de threads para garantir que a aplicação permaneça responsiva e para lidar com operações de I/O bloqueantes (como rede) de forma assíncrona. Isso evita o congelamento da interface do usuário.

  • Recebimento de Mensagens (Network._receive_messages): Tanto o servidor quanto o cliente dedicam uma thread para ouvir continuamente por mensagens de entrada. Isso impede que a espera por dados de rede bloqueie a execução de outras partes do programa.
  • Aceitação de Conexões (GameServer._accept_connections): No servidor, uma thread separada é responsável por aceitar novas conexões de clientes e iniciar um thread para lidar com a configuração inicial de cada um. Isso permite que o servidor continue operando enquanto aguarda novos jogadores.
  • Lógica Principal do Jogo (GameController._run_game_logic_server): No lado do servidor, a orquestração das fases do jogo (proposta de equipe, votação, missão) ocorre em uma thread dedicada (self._game_logic_thread). Isso é crucial para que os timeouts e esperas por respostas dos jogadores não bloqueiem o thread principal da interface gráfica.
  • Conexão do Cliente (GameClient._connect_client_loop): A tentativa de conexão do cliente ao servidor também é realizada em uma thread separada para evitar que a GUI congele durante o processo de estabelecimento da conexão.
  • Atualizações da GUI (root.after): Embora a lógica e a rede rodem em threads separadas, todas as interações com a interface gráfica (widgets tkinter) são agendadas para serem executadas no thread principal da GUI usando self.root.after(). Isso garante a segurança e consistência das operações de UI, prevenindo erros de concorrência.

Mecanismos de Sincronização (Locks, Semaphores e Queues)

Para gerenciar o acesso a recursos compartilhados e garantir a integridade dos dados em um ambiente multithreaded, o projeto emprega locks, semáforos e filas (queues) thread-safe.

  • threading.Lock (GameServer._lock): Utilizado em src/utils/network.py para proteger o dicionário self.clients, que armazena os sockets conectados. Isso impede condições de corrida quando múltiplos threads (ex: o thread que aceita conexões e o thread que envia mensagens) tentam modificar a lista de clientes simultaneamente, garantindo a integridade dos dados da conexão.
  • threading.Lock (GameController._current_phase_lock): Em src/controllers/controller.py, este lock é fundamental para sincronizar o acesso e a modificação do GameModel. Ele garante que apenas uma operação (seja da thread de lógica do jogo ou de um manipulador de mensagens de rede) possa modificar o estado do jogo em um dado momento. Isso previne condições de corrida e garante a consistência lógica do jogo.
  • threading.Semaphore (GameServer._client_setup_semaphore): Adicionado em src/utils/network.py, este semáforo é utilizado para limitar o número de threads que podem realizar a configuração inicial de novas conexões de clientes simultaneamente (definido por _max_concurrent_client_setup, por exemplo, 3). Cada thread que lida com uma nova conexão (_handle_new_client_connection) adquire uma permissão do semáforo antes de prosseguir com a configuração, bloqueando se o limite for atingido. Isso ajuda a prevenir a sobrecarga do servidor em caso de muitas conexões simultâneas.
  • Filas Thread-Safe (queue.Queue):
    • self.message_queue (em src/utils/network.py): Usada por ambas as classes GameServer e GameClient para armazenar mensagens de rede recebidas de forma thread-safe.
    • self.team_selection_response_queue, self.vote_response_queues, self.sabotage_response_queues (em src/controllers/controller.py): Estas filas são usadas para coletar as respostas dos diálogos da GUI (que são executados no thread principal) e passá-las de volta para a thread de lógica do jogo. Elas garantem que as respostas sejam transmitidas de forma ordenada e thread-safe.

Como Executar

Para executar o jogo, siga os passos abaixo:

  1. Certifique-se de ter Python 3.12 instalado.
  2. Navegue até o diretório raiz do projeto no terminal.
  3. Para iniciar o Servidor:

    python -m src.main

    Selecione a opção "Servidor (Host)" no menu principal. O servidor ficará ouvindo na porta 12345 (definida em src/utils/settings.py).

  4. Para conectar como Cliente:

    python -m src.main

    Selecione a opção "Cliente (Entrar)" e digite o IP do servidor (Ex: 127.0.0.1 para jogar na mesma máquina, ou o IP da máquina host na rede). O cliente tentará conectar na porta 12345.

  5. O jogo requer 5 jogadores (definido em NUM_PLAYERS em src/utils/settings.py). Conecte os clientes necessários.
  6. No servidor, o botão "Iniciar Jogo" ficará ativo quando NUM_PLAYERS jogadores estiverem conectados.

About

"The Resistance" é um jogo de dedução social e blefe para 5 jogadores. O objetivo é para a equipe da Resistência (maioria) completar missões, enquanto os Espiões (minoria) tentam sabotá-las.

Topics

Resources

Stars

Watchers

Forks

Languages