import sys import random from types import NoneType import pygame as pg from modules.agente import Agente from modules.mapa import Mapa import modules.estrategia as ModEstrategia import modules.interaccoes as ModInteraccoes # 0 para desactivar flags # pg.FULLSCREEN para fullscreen mode flags = 0 # pg.FULLSCREEN sep_janelas: int = 10 # classe Frame para gerir diferentes frames dentro da janela principal class Frame: def __init__( self, tamanho_janela: tuple[int, int], coord_posicao: tuple[int, int], cor_fundo: pg.Color = pg.Color(0, 0, 0, 0), ): self.tamanho = tamanho_janela self.posicao = coord_posicao self.surface = pg.Surface(self.tamanho) self.cor = cor_fundo def rect(self) -> pg.Rect: return pg.Rect(self.posicao, self.tamanho) def desenhar(self, dest: pg.Surface, borda: int = 0, border_radius=0) -> None: pg.draw.rect(dest, pg.Color(0, 0, 0, 0), self.rect()) pg.draw.rect(dest, self.cor, self.rect(), borda, border_radius=border_radius) def criarFrames(janela_app: pg.Surface) -> tuple[Frame, Frame, Frame, Frame]: frame_mapa = Frame( ( janela_app.get_size()[1] - (sep_janelas) * 2, janela_app.get_size()[1] - (sep_janelas * 2), ), (sep_janelas, sep_janelas), pg.Color(0, 0, 0, 0), ) frame_info_mapa = Frame( ( janela_app.get_size()[0] - frame_mapa.tamanho[0] - (sep_janelas * 3), (janela_app.get_size()[1] - (sep_janelas * 2)) // 2, ), (frame_mapa.tamanho[0] + (sep_janelas * 2), sep_janelas), pg.Color(255, 255, 255, 0), ) frame_info_pos = Frame( ( janela_app.get_size()[0] - frame_mapa.tamanho[0] - (sep_janelas * 3), ((frame_info_mapa.tamanho[1] * 2) // 3) - sep_janelas, ), ( frame_mapa.tamanho[0] + (sep_janelas * 2), frame_info_mapa.tamanho[1] + (sep_janelas * 2), ), pg.Color(255, 255, 255, 0), ) frame_accoes = Frame( ( janela_app.get_size()[0] - frame_mapa.tamanho[0] - (sep_janelas * 3), janela_app.get_size()[1] - frame_info_mapa.tamanho[1] - frame_info_pos.tamanho[1] - (sep_janelas * 4), ), ( frame_mapa.tamanho[0] + 20, frame_info_mapa.tamanho[1] + frame_info_pos.tamanho[1] + 30, ), pg.Color(255, 255, 255, 0), ) return (frame_mapa, frame_info_mapa, frame_info_pos, frame_accoes) def devolveCor(agente: Agente) -> tuple[int, int, int, int]: if type(agente) is None: return (0, 0, 0, 0) else: match agente.estrategia: case "Neutro": return (255, 255, 255, 0) case "Tit4Tat": return (255, 255, 0, 0) case "Vingativo": return (255, 0, 0, 0) case "Lunatico": return (0, 0, 255, 0) case _: return (0, 0, 0, 0) def criarTabuleiro( surface: pg.Surface, mapa: Mapa, ) -> None: dimensao_tabuleiro: tuple[int, int] = mapa.dimensao dimensoes_surface_principal: tuple[int, int] = surface.get_size() max_altura: int = int((dimensoes_surface_principal[1] - 20) / dimensao_tabuleiro[0]) tamanho_quadrado: int = max_altura cor_quadrado: tuple[int, int, int, int] for pos_y in range(0, dimensao_tabuleiro[0]): for pos_x in range(0, dimensao_tabuleiro[1]): agente: Agente | None = mapa.posicao((pos_x, pos_y)) cor_quadrado = devolveCor(agente) pg.draw.rect( surface, cor_quadrado, [ 10 + (tamanho_quadrado * pos_x), 10 + (tamanho_quadrado * pos_y), tamanho_quadrado, tamanho_quadrado, ], 0, ) def criarMapa(janela_app: pg.Surface, frame: Frame, mapa: Mapa) -> None: lado: int = (frame.tamanho[1] - (10 * 2)) // mapa.dimensao[0] for pos_y in range(0, mapa.dimensao[1]): for pos_x in range(0, mapa.dimensao[0]): agente: Agente | None = mapa.posicao((pos_x, pos_y)) cor = devolveCor(agente) quadrado: pg.Rect = pg.Rect( 10 + (lado * pos_x), 10 + (lado * pos_y), lado, lado, ) pg.draw.rect(janela_app, cor, quadrado, 0) def popularMapa(mapa: Mapa) -> None: for pos_y in range(0, mapa.dimensao[0]): for pos_x in range(0, mapa.dimensao[1]): # escolher uma estrategia aleatoria estrategia = random.choice(ModEstrategia.listaNomesEstrategias()) # criar Agente com estrategia aleatoria e colocar na posicao y e x mapa.mundo[pos_y][pos_x] = Agente(estrategia, (pos_x, pos_y)) def prepararEstatistica(mapa: Mapa | None) -> dict[str, int]: if mapa is None: print("SEM MAPA!!") else: stats_estrategias: dict[str, int] = {} n_total_agentes: int = 0 # print("estatisticas mapa:") for tipo_estrategia in ModEstrategia.lista_estrategias: stats_estrategias[tipo_estrategia] = 0 for pos_y in range(0, mapa.dimensao[0]): for pos_x in range(0, mapa.dimensao[1]): tmp_agente = mapa.posicao((pos_y, pos_x)) stats_estrategias[tmp_agente.estrategia] += 1 n_total_agentes += 1 # for tipo_estrategia in stats_estrategias: # print( # f"{tipo_estrategia}: { # (stats_estrategias[tipo_estrategia] / n_total_agentes) * 100:3.2f}" # ) return stats_estrategias return {} def mostrarMapa(mapa: Mapa | None) -> None: # verificacao if isinstance(mapa, NoneType): raise TypeError("objecto passado do tipo None") # mostrar mapa com pontuação em cada posição for pos_y in range(0, mapa.dimensao[0]): for pos_x in range(0, mapa.dimensao[1]): tmp_agente: Agente | None = mapa.posicao((pos_x, pos_y)) if not isinstance(tmp_agente, NoneType): print(f"{tmp_agente.estrategia[0]:2}", end="") print("") def actualizarEstatisticas( janela: pg.Surface, frame_info_mapa: Frame, mapa: Mapa ) -> None: frame_info_mapa.desenhar(janela, 5, 10) font = pg.font.Font(None, 20) dict_estrat = prepararEstatistica(mapa) n_linhas = 0 for strat in dict_estrat: strat_label = font.render( f"{strat}: {(dict_estrat[strat] / mapa.dimensao[0] ** 2) * 100:3.2f}", False, pg.Color(255, 255, 255, 0), ) janela.blit( strat_label, ( frame_info_mapa.posicao[0] + (sep_janelas * 2), frame_info_mapa.posicao[1] + (sep_janelas * 2) + (30 * n_linhas), ), ) n_linhas += 1 def actualizarInfoPos( janela: pg.Surface, frame: Frame, mapa: Mapa, pos: tuple[int, int] ) -> None: # limpar frame_info_mapa frame.desenhar(janela, 5, 10) # mostrar informação sobre posicao seleccionada font = pg.font.Font(None, 20) info_posicao = font.render( f"{mapa.posicao(pos).estrategia}@{pos}", False, pg.Color(255, 255, 255, 0), ) janela.blit( info_posicao, ( frame.posicao[0] + (sep_janelas * 2), frame.posicao[1] + (sep_janelas * 2), ), ) def main(mapa: Mapa | None, tamanho_mapa: tuple[int, int]): if isinstance(mapa, NoneType): raise TypeError("não foi passado mapa (tipo None)") pg.init() janela = pg.display.set_mode((1280, 800), flags) pg.display.set_caption("Game Theory of Life") clock = pg.time.Clock() running: bool = True quadrado_seleccionado: pg.Rect | None = None # criar frames frame_mapa, frame_info_mapa, frame_info_pos, frame_accoes = criarFrames(janela) # mostrar frames no janela principal frame_mapa.desenhar(janela, 5, 10) frame_info_mapa.desenhar(janela, 5, 10) frame_info_pos.desenhar(janela, 5, 10) frame_accoes.desenhar(janela, 5, 10) while running: if quadrado_seleccionado: pg.draw.rect( janela, pg.Color(0, 0, 0, 0), quadrado_seleccionado, 2, border_radius=10, ) for event in pg.event.get(): if event.type == pg.QUIT: running = False if event.type == pg.KEYDOWN: # sair do mapa com 'q' (quit) if event.key == pg.K_q: running = False # mudar mapa com 'c' (change) if event.key == pg.K_c: novo_tamanho = int(input("tamanho do mapa: ")) tamanho_mapa = (novo_tamanho, novo_tamanho) mapa = Mapa(tamanho_mapa) popularMapa(mapa) # correr proxima iteração com 'n' (next) if event.key == pg.K_n: ModInteraccoes.correrInteraccoesEntreAgentes(mapa) # gerar novo mapa e popular (fazer reset) com 'r' if event.key == pg.K_r: mapa = Mapa(tamanho_mapa) popularMapa(mapa) if event.type == pg.MOUSEBUTTONDOWN: # botao 1 do rato clicado, seleccionar ou tirar selecao if pg.mouse.get_pressed(num_buttons=3)[0]: pos_rato: tuple[int, int] = pg.mouse.get_pos() tamanho_quadrado = (frame_mapa.tamanho[1] - 20) // mapa.dimensao[0] if pos_rato[0] < 10 or pos_rato[1] < 10: continue pos_x = (pos_rato[0] - 10) // tamanho_quadrado pos_y = (pos_rato[1] - 10) // tamanho_quadrado if pos_x >= mapa.dimensao[0] or pos_y >= mapa.dimensao[1]: continue quadrado_novo = pg.Rect( (pos_x * tamanho_quadrado) + sep_janelas, (pos_y * tamanho_quadrado) + sep_janelas, tamanho_quadrado, tamanho_quadrado, ) if quadrado_novo == quadrado_seleccionado: quadrado_seleccionado = None frame_info_pos.desenhar(janela, 5, 10) else: quadrado_seleccionado = quadrado_novo # actualizar info na frame_info_pos actualizarInfoPos(janela, frame_info_pos, mapa, (pos_x, pos_y)) # desenhar mapa frame_mapa.desenhar(janela) criarMapa(janela, frame_mapa, mapa) # criarTabuleiro(janela, mapa) # se quadrado estiver seleccionado, mostrá-lo if quadrado_seleccionado: pg.draw.rect( janela, pg.Color(0, 0, 0, 0), quadrado_seleccionado, 2, border_radius=20, ) # mostrar numero de iteração actual # mostrar dimensão do mapa # mostrar estatisticas actualizarEstatisticas(janela, frame_info_mapa, mapa) # mostrar frame_accoes pg.display.flip() clock.tick(60) pg.quit() sys.exit() if __name__ == "__main__": mapa_mundo: Mapa = Mapa((128, 128)) app = main(mapa_mundo, tamanho_mapa=(128, 128))