import sys import random from types import NoneType import pygame as pg from modules import mapa 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 = pg.FULLSCREEN sep_janelas: int = 10 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) -> None: pg.draw.rect(dest, pg.Color(0, 0, 0, 0), self.rect()) pg.draw.rect(dest, self.cor, self.rect(), 5, border_radius=20) 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(255, 255, 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(0, 0, 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(0, 255, 0, 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, 0, 0, 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]) # max_largura: int = int( # (dimensoes_surface_principal[0] - 20) / dimensao_tabuleiro[1] # ) tamanho_quadrado: int = max_altura # min([max_altura, max_largura]) 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 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) 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) # 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) 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) janela.fill(0) 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 = int( (janela.get_size()[1] - 20) / mapa.dimensao[0] ) if pos_rato[0] < 10 or pos_rato[1] < 10: continue pos_x = int((pos_rato[0] - 10) / tamanho_quadrado) pos_y = int((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) + 10, (pos_y * tamanho_quadrado) + 10, tamanho_quadrado, tamanho_quadrado, ) if quadrado_novo == quadrado_seleccionado: quadrado_seleccionado = None frame_info_pos.desenhar(janela) else: quadrado_seleccionado = quadrado_novo agente = mapa.posicao((pos_x, pos_y)) print(f"{agente.posicao} com {agente.estrategia}") # desenhar mapa frame_mapa.desenhar(janela) criarTabuleiro(janela, mapa) # mostrar numero de iteração actual # mostrar dimensão do mapa # mostrar estatisticas actualizarEstatisticas(janela, frame_info_mapa, mapa) # mostrar borda da posicao seleccionado com o rato frame_info_pos.desenhar(janela) if quadrado_seleccionado: pg.draw.rect( janela, pg.Color(0, 0, 0, 0), quadrado_seleccionado, 2, border_radius=20, ) # actualizar info na frame_info_pos actualizarInfoPos(janela, frame_info_pos, mapa, (pos_x, pos_y)) # mostrar frame accoes frame_accoes.desenhar(janela) 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))