From 4c081385f53882d57f728de09d1aa5f659cd074a Mon Sep 17 00:00:00 2001 From: renzon Date: Thu, 13 Nov 2014 14:04:18 -0200 Subject: [PATCH 1/6] Incluindo arquivo do Floobits no gitignore --- .gitignore | 4 ++++ README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6220a9500..156281421 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,10 @@ coverage.xml .pydevproject .idea +# Floobits + +.floorc.json + # Rope .ropeproject diff --git a/README.md b/README.md index 2fc310741..8da421483 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Python Birds Essa versão é a mais simples. Ela não contém replay nem reset, de forma que o jogo não pode retroceder. -Para versão mais complexa, acesse a branch [diversao](https://github.com/pythonprobr/pythonbirds/tree/diversao) +Para versão mais complexa, acesse a branch [master](https://github.com/pythonprobr/pythonbirds/tree/master) Projeto para Ensino de Programação Orientadas a Objetos em Python. From e26869ee1bc1d6f2fc0f9c5af91607df70a57f6a Mon Sep 17 00:00:00 2001 From: renzon Date: Sun, 16 Nov 2014 11:06:56 -0200 Subject: [PATCH 2/6] =?UTF-8?q?Retornando=20com=20solu=C3=A7=C3=A3o=20que?= =?UTF-8?q?=20tinha=20sido=20removida=20pelo=20merge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ---- atores.py | 56 +++++++++++++++++++++++++++++++++++++++++---------- fase.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 156281421..6220a9500 100644 --- a/.gitignore +++ b/.gitignore @@ -43,10 +43,6 @@ coverage.xml .pydevproject .idea -# Floobits - -.floorc.json - # Rope .ropeproject diff --git a/atores.py b/atores.py index b4519a9db..8f9a82f49 100644 --- a/atores.py +++ b/atores.py @@ -37,7 +37,7 @@ def calcular_posicao(self, tempo): :param tempo: o tempo do jogo :return: posição x, y do ator """ - return 1, 1 + return self.x, self.y def colidir(self, outro_ator, intervalo=1): """ @@ -51,20 +51,25 @@ def colidir(self, outro_ator, intervalo=1): :param intervalo: Intervalo a ser considerado :return: """ - pass + if self.status == DESTRUIDO or outro_ator.status == DESTRUIDO: + return + if self.x - intervalo <= outro_ator.x <= self.x + intervalo and self.y - intervalo <= outro_ator.y <= self.y + intervalo: + self.status = DESTRUIDO + outro_ator.status = DESTRUIDO class Obstaculo(Ator): - pass + _caracter_ativo = 'O' class Porco(Ator): - pass + _caracter_ativo = '@' + _caracter_destruido = '+' class Passaro(Ator): - velocidade_escalar = 10 + velocidade_escalar = None def __init__(self, x=0, y=0): """ @@ -88,7 +93,7 @@ def foi_lancado(self): :return: booleano """ - return True + return self._tempo_de_lancamento is not None def colidir_com_chao(self): """ @@ -96,7 +101,21 @@ def colidir_com_chao(self): o status dos Passaro deve ser alterado para destruido, bem como o seu caracter """ - pass + if self.y <= 0: + self.status = DESTRUIDO + + def _calcular_posicao_horizontal(self, delta_t): + self.x = self._x_inicial + self.velocidade_escalar * delta_t * math.cos(self._angulo_de_lancamento) + + def _calcular_posicao_vertical(self, delta_t): + self.y = (self._y_inicial + + self.velocidade_escalar * delta_t * math.sin(self._angulo_de_lancamento) - + (GRAVIDADE / 2) * delta_t ** 2) + + def _calcular_posicao(self, tempo): + delta_t = tempo - self._tempo_de_lancamento + self._calcular_posicao_vertical(delta_t) + self._calcular_posicao_horizontal(delta_t) def calcular_posicao(self, tempo): """ @@ -112,7 +131,11 @@ def calcular_posicao(self, tempo): :param tempo: tempo de jogo a ser calculada a posição :return: posição x, y """ - return 1, 1 + if self._tempo_de_lancamento is None: + return self._x_inicial, self._y_inicial + if self.status == ATIVO: + self._calcular_posicao(tempo) + return self.x, self.y def lancar(self, angulo, tempo_de_lancamento): @@ -124,12 +147,23 @@ def lancar(self, angulo, tempo_de_lancamento): :param tempo_de_lancamento: :return: """ - pass + self._tempo_de_lancamento = tempo_de_lancamento + self._angulo_de_lancamento = math.radians(angulo) + + def _aguardando_lancamento(self, tempo): + return not self.foi_lancado() or tempo < self._tempo_de_lancamento + + def _ja_colidiu(self): + return self.foi_lancado() and self.status() == DESTRUIDO class PassaroAmarelo(Passaro): - pass + velocidade_escalar = 30 # m/s + _caracter_ativo = 'A' + _caracter_destruido = 'a' class PassaroVermelho(Passaro): - pass \ No newline at end of file + velocidade_escalar = 20 # m/s + _caracter_ativo = 'V' + _caracter_destruido = 'v' diff --git a/fase.py b/fase.py index ea8f9af24..f54368e96 100644 --- a/fase.py +++ b/fase.py @@ -2,6 +2,7 @@ from itertools import chain from atores import ATIVO +# Status possíveis do jogo VITORIA = 'VITORIA' DERROTA = 'DERROTA' @@ -36,6 +37,8 @@ def __init__(self, intervalo_de_colisao=1): self._porcos = [] self._obstaculos = [] + def _adicionar_ator(self, lista, *atores): + lista.extend(atores) def adicionar_obstaculo(self, *obstaculos): """ @@ -43,7 +46,7 @@ def adicionar_obstaculo(self, *obstaculos): :param obstaculos: """ - pass + self._adicionar_ator(self._obstaculos, *obstaculos) def adicionar_porco(self, *porcos): """ @@ -51,7 +54,7 @@ def adicionar_porco(self, *porcos): :param porcos: """ - pass + self._adicionar_ator(self._porcos, *porcos) def adicionar_passaro(self, *passaros): """ @@ -59,7 +62,20 @@ def adicionar_passaro(self, *passaros): :param passaros: """ - pass + self._adicionar_ator(self._passaros, *passaros) + + # def acabou(self): + # """ + # Método que retorna verdadeiro se o jogo acabou e falso caso contrário + # + # O jogo pode acabar por dois motivos: + # + # 1. Não existem mais porcos ativos no jogo + # 2. Não existem mais pássaros ativos no jogo + # + # :return: booleano + # """ + # return self.status() != EM_ANDAMENTO def status(self): """ @@ -73,7 +89,11 @@ def status(self): :return: """ - return EM_ANDAMENTO + if not self._existe_porco_ativo(): + return VITORIA + if self._existe_passaro_ativo(): + return EM_ANDAMENTO + return DERROTA def lancar(self, angulo, tempo): """ @@ -86,7 +106,10 @@ def lancar(self, angulo, tempo): :param angulo: ângulo de lançamento :param tempo: Tempo de lançamento """ - pass + for passaro in self._passaros: + if not passaro.foi_lancado(): + passaro.lancar(angulo, tempo) + return def calcular_pontos(self, tempo): @@ -98,10 +121,32 @@ def calcular_pontos(self, tempo): :param tempo: tempo para o qual devem ser calculados os pontos :return: objeto do tipo Ponto """ - pontos=[] - + pontos = [self._calcular_ponto_de_passaro(p, tempo) for p in self._passaros] + obstaculos_e_porcos = chain(self._obstaculos, self._porcos) + pontos.extend([self._transformar_em_ponto(ator) for ator in obstaculos_e_porcos]) return pontos def _transformar_em_ponto(self, ator): return Ponto(ator.x, ator.y, ator.caracter()) + def _calcular_ponto_de_passaro(self, passaro, tempo, ): + passaro.calcular_posicao(tempo) + for ator in chain(self._obstaculos, self._porcos): + if ATIVO == passaro.status: + passaro.colidir(ator, self.intervalo_de_colisao) + passaro.colidir_com_chao() + else: + break + return self._transformar_em_ponto(passaro) + + def _existe_porco_ativo(self): + return self._verificar_se_existe_ator_ativo(self._porcos) + + def _verificar_se_existe_ator_ativo(self, atores): + for a in atores: + if a.status == ATIVO: + return True + return False + + def _existe_passaro_ativo(self): + return self._verificar_se_existe_ator_ativo(self._passaros) From 6c862055265dd293498ccd32e06f31bbdad3a232 Mon Sep 17 00:00:00 2001 From: renzon Date: Fri, 24 Apr 2015 17:19:52 -0300 Subject: [PATCH 3/6] close #12 --- placa_grafica_tkinter.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/placa_grafica_tkinter.py b/placa_grafica_tkinter.py index 918a02d17..ea020ccbb 100644 --- a/placa_grafica_tkinter.py +++ b/placa_grafica_tkinter.py @@ -43,13 +43,15 @@ def plotar(camada_de_atores, ponto): camada_de_atores.create_image((x, y), image=image, anchor=NW) -def animar(tela, camada_de_atores, fase, passo=0.01, delta_t=0.01): +def animar(tela, camada_de_atores, fase, passo=0.01, delta_t=0.04): tempo = 0 passo = int(1000 * passo) angulo = 0 multiplicador_rebobinar = 20 def _animar(): + tempo_de_inicio_de_animacao=time.time() + nonlocal tempo nonlocal delta_t nonlocal angulo @@ -76,7 +78,9 @@ def _animar(): camada_de_atores.create_text(35, 493, text="%d°" % angulo) for ponto in fase.calcular_pontos(tempo): plotar(camada_de_atores, ponto) - tela.after(passo, _animar) + tempo_gasto_com_animacao= round((time.time() - tempo_de_inicio_de_animacao)*1000) # Trans + tempo_proxima_animacao = passo - tempo_gasto_com_animacao if passo>tempo_gasto_com_animacao else 1 + tela.after(tempo_proxima_animacao, _animar) def _ouvir_comandos_lancamento(evento): nonlocal angulo From 645a10325af1ad080c9f71ccd86b8c48ed2d3cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20Perc=C3=BA?= Date: Sat, 16 May 2015 13:12:40 -0300 Subject: [PATCH 4/6] typos fix --- testes/atores_testes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testes/atores_testes.py b/testes/atores_testes.py index 087bd1864..518c1d063 100644 --- a/testes/atores_testes.py +++ b/testes/atores_testes.py @@ -119,9 +119,9 @@ def assert_colisao_atores_ativos(self, ator, ator2, intervalo=1): def assert_nao_colisao(self, ator, ator2): """ Se certifica que não colisão entre dois atores - Atenção: Esse não é método de teste porque nao se inicia com prefixo "text". + Atenção: Esse não é método de teste porque não se inicia com prefixo "text". Ele apenas encapsula a lógica de não colisão entre dois atores. - So seja, eles deve manter seus respectivos status mesmo depois da chamada do metodo colidir + Ou seja, eles devem manter seus respectivos status mesmo depois da chamada do método colidir """ # Armazenando status antes da colisão status_inicial_ator = ator.status From a94bdc838509351830ef1f3e3b251a2ea551ebdd Mon Sep 17 00:00:00 2001 From: renzon Date: Tue, 6 Dec 2016 17:21:19 -0200 Subject: [PATCH 5/6] =?UTF-8?q?melhora=20em=20l=C3=B3gica=20de=20colisao?= =?UTF-8?q?=20m=C3=A9todo=20lan=C3=A7ar=20gerando=20excecao=20se=20executa?= =?UTF-8?q?do=20mais=20de=20uma=20vez?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- atores.py | 57 +++++++++++++++++++++++++++++------------ fase.py | 9 ++++--- testes/atores_testes.py | 16 ++++++++++-- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/atores.py b/atores.py index 8f9a82f49..4e07b7255 100644 --- a/atores.py +++ b/atores.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals + import math DESTRUIDO = 'Destruido' @@ -17,7 +18,8 @@ class Ator(): def __init__(self, x=0, y=0): """ - Método de inicialização da classe. Deve inicializar os parâmetros x, y, caracter e status + Método de inicialização da classe. Deve inicializar os parâmetros x, + y, caracter e status :param x: Posição horizontal inicial do ator :param y: Posição vertical inicial do ator @@ -27,7 +29,8 @@ def __init__(self, x=0, y=0): self.status = ATIVO def caracter(self): - return self._caracter_ativo if self.status == ATIVO else self._caracter_destruido + return self._caracter_ativo if self.status == ATIVO else \ + self._caracter_destruido def calcular_posicao(self, tempo): """ @@ -43,8 +46,10 @@ def colidir(self, outro_ator, intervalo=1): """ Método que executa lógica de colisão entre dois atores. Só deve haver colisão se os dois atores tiverem seus status ativos. - Para colisão, é considerado um quadrado, com lado igual ao parâmetro intervalo, em volta do ponto onde se - encontra o ator. Se os atores estiverem dentro desse mesmo quadrado, seus status devem ser alterados para + Para colisão, é considerado um quadrado, com lado igual ao parâmetro + intervalo, em volta do ponto onde se + encontra o ator. Se os atores estiverem dentro desse mesmo quadrado, + seus status devem ser alterados para destruido, seus caracteres para destruido também. :param outro_ator: Ator a ser considerado na colisão @@ -54,7 +59,8 @@ def colidir(self, outro_ator, intervalo=1): if self.status == DESTRUIDO or outro_ator.status == DESTRUIDO: return - if self.x - intervalo <= outro_ator.x <= self.x + intervalo and self.y - intervalo <= outro_ator.y <= self.y + intervalo: + if abs(self.x - outro_ator.x) <= intervalo and abs( + self.y - outro_ator.y) <= intervalo: self.status = DESTRUIDO outro_ator.status = DESTRUIDO @@ -68,6 +74,10 @@ class Porco(Ator): _caracter_destruido = '+' +class DuploLancamentoExcecao(Exception): + pass + + class Passaro(Ator): velocidade_escalar = None @@ -75,7 +85,8 @@ def __init__(self, x=0, y=0): """ Método de inicialização de pássaro. - Deve chamar a inicialização de ator. Além disso, deve armazenar a posição inicial e incializar o tempo de + Deve chamar a inicialização de ator. Além disso, deve armazenar a + posição inicial e incializar o tempo de lançamento e angulo de lançamento :param x: @@ -89,7 +100,8 @@ def __init__(self, x=0, y=0): def foi_lancado(self): """ - Método que retorna verdaeira se o pássaro já foi lançado e falso caso contrário + Método que retorna verdadeiro se o pássaro já foi lançado e falso + caso contrário :return: booleano """ @@ -97,19 +109,24 @@ def foi_lancado(self): def colidir_com_chao(self): """ - Método que executa lógica de colisão com o chão. Toda vez que y for menor ou igual a 0, - o status dos Passaro deve ser alterado para destruido, bem como o seu caracter + Método que executa lógica de colisão com o chão. Toda vez que y for + menor ou igual a 0, + o status dos Passaro deve ser alterado para destruido, bem como o + seu caracter """ if self.y <= 0: self.status = DESTRUIDO def _calcular_posicao_horizontal(self, delta_t): - self.x = self._x_inicial + self.velocidade_escalar * delta_t * math.cos(self._angulo_de_lancamento) + self.x = self._x_inicial + self.velocidade_escalar * delta_t * \ + math.cos( + self._angulo_de_lancamento) def _calcular_posicao_vertical(self, delta_t): self.y = (self._y_inicial + - self.velocidade_escalar * delta_t * math.sin(self._angulo_de_lancamento) - + self.velocidade_escalar * delta_t * math.sin( + self._angulo_de_lancamento) - (GRAVIDADE / 2) * delta_t ** 2) def _calcular_posicao(self, tempo): @@ -121,12 +138,16 @@ def calcular_posicao(self, tempo): """ Método que cálcula a posição do passaro de acordo com o tempo. - Antes do lançamento o pássaro deve retornar o valor de sua posição inicial + Antes do lançamento o pássaro deve retornar o valor de sua posição + inicial - Depois do lançamento o pássaro deve calcular de acordo com sua posição inicial, velocidade escalar, - ângulo de lancamento, gravidade (constante GRAVIDADE) e o tempo do jogo. + Depois do lançamento o pássaro deve calcular de acordo com sua + posição inicial, velocidade escalar, + ângulo de lancamento, gravidade (constante GRAVIDADE) e o tempo do + jogo. - Após a colisão, ou seja, ter seus status destruido, o pássaro deve apenas retornar a última posição calculada. + Após a colisão, ou seja, ter seus status destruido, o pássaro deve + apenas retornar a última posição calculada. :param tempo: tempo de jogo a ser calculada a posição :return: posição x, y @@ -137,16 +158,18 @@ def calcular_posicao(self, tempo): self._calcular_posicao(tempo) return self.x, self.y - def lancar(self, angulo, tempo_de_lancamento): """ - Lógica que lança o pássaro. Deve armazenar o ângulo e o tempo de lançamento para posteriores cálculo. + Lógica que lança o pássaro. Deve armazenar o ângulo e o tempo de + lançamento para posteriores cálculo. O ângulo é passado em graus e deve ser transformado em radianos :param angulo: :param tempo_de_lancamento: :return: """ + if self.foi_lancado(): + raise DuploLancamentoExcecao('Pássaro já foi lançado') self._tempo_de_lancamento = tempo_de_lancamento self._angulo_de_lancamento = math.radians(angulo) diff --git a/fase.py b/fase.py index f54368e96..ffa7084ab 100644 --- a/fase.py +++ b/fase.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from itertools import chain -from atores import ATIVO +from atores import ATIVO, DuploLancamentoExcecao # Status possíveis do jogo @@ -104,11 +104,14 @@ def lancar(self, angulo, tempo): Se não houver esse tipo de pássaro, não deve fazer nada :param angulo: ângulo de lançamento - :param tempo: Tempo de lançamento + :param tempo: tempo de lançamento """ for passaro in self._passaros: - if not passaro.foi_lancado(): + try: passaro.lancar(angulo, tempo) + except DuploLancamentoExcecao: + continue + else: return diff --git a/testes/atores_testes.py b/testes/atores_testes.py index 518c1d063..5f4e66f0e 100644 --- a/testes/atores_testes.py +++ b/testes/atores_testes.py @@ -2,7 +2,8 @@ from __future__ import unicode_literals from unittest.case import TestCase -from atores import Ator, DESTRUIDO, ATIVO, Obstaculo, Porco, PassaroAmarelo, PassaroVermelho +from atores import Ator, DESTRUIDO, ATIVO, Obstaculo, Porco, PassaroAmarelo, PassaroVermelho, \ + DuploLancamentoExcecao class AtorTestes(TestCase): @@ -206,6 +207,15 @@ def teste_foi_lancado(self): self.assertTrue(passaro_vermelho.foi_lancado(), 'Se o método lançar foi executado, deve retornar verdadeiro') + def test_excecao_ao_lancar_passaro_pela_segunda_vez(self): + """Se certifica que pássaro só pode ser lançado uma vez""" + passaro = PassaroVermelho(0,0) + passaro.lancar(0,0) + with self.assertRaises(DuploLancamentoExcecao): + passaro.lancar(1,1) + self.assertEqual(passaro._angulo_de_lancamento,0,'Deveria continuar com angulo passado no primeiro lançamento') + self.assertEqual(passaro._tempo_de_lancamento,0,'Deveria continuar com tempo passado no primeiro lançamento') + def teste_colisao_com_chao(self): """ Testando que o passáro colido quando sua posição y é menor ou igual a 0 @@ -229,6 +239,7 @@ def teste_colisao_com_chao(self): class PassaroAmareloTests(PassaroBaseTests): + """ Classe de Tests para passaros amarelos """ @@ -243,9 +254,10 @@ def teste_status(self): def teste_velocidade_escalar(self): self.assertEqual(30, PassaroAmarelo.velocidade_escalar) + def teste_lacamento_vertical(self): """ - Tests de lançamento vertical. Nele, o passaro só se move verticalmente e sua posição y se matém contanstante + Testes de lançamento vertical. Nele, o passaro só se move verticalmente e sua posição y se matém contanstante :return: """ passaro_amarelo = PassaroAmarelo(1, 1) From d5f55287fcefb286d4473515076a3b30057be36e Mon Sep 17 00:00:00 2001 From: renzon Date: Tue, 6 Dec 2016 21:54:00 -0200 Subject: [PATCH 6/6] =?UTF-8?q?Testes=20de=20fase=20divididos=20em=20integ?= =?UTF-8?q?racao=20e=20unit=C3=A1rios=20com=20Objetos=20Fake=20emulando=20?= =?UTF-8?q?Mock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- testes/fase_testes.py | 232 ++++++++++++++++----------------- testes/integracao.py | 188 ++++++++++++++++++++++++++ testes/testes_placa_grafica.py | 2 - 3 files changed, 297 insertions(+), 125 deletions(-) create mode 100644 testes/integracao.py diff --git a/testes/fase_testes.py b/testes/fase_testes.py index 85067fa95..8158a43f5 100644 --- a/testes/fase_testes.py +++ b/testes/fase_testes.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- -from itertools import chain import os +import sys from os import path from unittest.case import TestCase -import math -import sys project_dir = path.dirname(__file__) project_dir = path.join('..') @@ -16,211 +14,199 @@ project_dir = os.path.normpath(project_dir) sys.path.append(project_dir) -from atores import Obstaculo, Porco, PassaroVermelho, PassaroAmarelo, DESTRUIDO, ATIVO +from atores import (Obstaculo, Porco, PassaroVermelho, PassaroAmarelo, + DESTRUIDO, ATIVO, DuploLancamentoExcecao) from fase import Fase, Ponto, EM_ANDAMENTO, VITORIA, DERROTA +class AtorFake: + def __init__(self, x=0, y=0): + self.y = y + self.x = x + self.status = ATIVO + self.colidir_executado = False + self.calcular_posicao_executado = False + self.intervalo_colisao = None + + def calcular_posicao(self, tempo): + self.calcular_posicao_executado = True + + def colidir(self, outro_ator, intervalo): + self.colidir_executado = outro_ator.colidir_executado = True + self.intervalo_colisao = outro_ator.intervalo_colisao = intervalo + + def caracter(self): + return ' ' + + +class ObstaculoFake(AtorFake): + pass + + +class PorcoFake(AtorFake): + pass + + +class PassaroFake(AtorFake): + def __init__(self, x=0, y=0): + super().__init__(x, y) + self._lancado = False + self.colidir_com_chao_executado = False + + def foi_lancado(self): + return self._lancado + + def lancar(self, angulo, tempo): + if self._lancado: + raise DuploLancamentoExcecao() + self._lancado = True + + def colidir_com_chao(self): + self.colidir_com_chao_executado = True + + class FaseTestes(TestCase): def teste_adicionar_obstaculo(self): fase = Fase() self.assertListEqual([], fase._obstaculos) - obstaculo = Obstaculo() + obstaculo = ObstaculoFake() fase.adicionar_obstaculo(obstaculo) self.assertListEqual([obstaculo], fase._obstaculos) - obstaculo1, obstaculo2 = Obstaculo(), Obstaculo() + obstaculo1, obstaculo2 = ObstaculoFake(), ObstaculoFake() fase.adicionar_obstaculo(obstaculo1, obstaculo2) - self.assertListEqual([obstaculo, obstaculo1, obstaculo2], fase._obstaculos) + self.assertListEqual([obstaculo, obstaculo1, obstaculo2], + fase._obstaculos) def teste_adicionar_porco(self): fase = Fase() self.assertListEqual([], fase._porcos) - porco = Porco() + porco = PorcoFake() fase.adicionar_porco(porco) self.assertListEqual([porco], fase._porcos) - porco1, porco2 = Porco(), Porco() + porco1, porco2 = PorcoFake(), PorcoFake() fase.adicionar_porco(porco1, porco2) self.assertListEqual([porco, porco1, porco2], fase._porcos) def teste_adicionar_passaro(self): fase = Fase() self.assertListEqual([], fase._passaros) - passaro = PassaroVermelho() + passaro = PassaroFake() fase.adicionar_passaro(passaro) self.assertListEqual([passaro], fase._passaros) - passaro1, passaro2 = PassaroVermelho(), PassaroAmarelo() + passaro1, passaro2 = PassaroFake(), PassaroFake() fase.adicionar_passaro(passaro1, passaro2) self.assertListEqual([passaro, passaro1, passaro2], fase._passaros) - def teste_acabou_sem_porcos(self): fase = Fase() self.assertEqual(VITORIA, fase.status()) def teste_acabou_com_porcos_e_passaros(self): fase = Fase() - porcos = [Porco(1, 1) for i in range(2)] # criando 2 porcos - passaros = [PassaroAmarelo(1, 1) for i in range(2)] # criando 2 pássaros + porcos = [PorcoFake(1, 1) for _ in range(2)] # criando 2 porcos + passaros = [PassaroFake(1, 1) for _ in range(2)] # criando 2 pássaros fase.adicionar_porco(*porcos) fase.adicionar_passaro(*passaros) self.assertEqual(EM_ANDAMENTO, fase.status()) - # colidindo cada passaro com um porco no tempo 3 - for passaro, porco in zip(passaros, porcos): - passaro.colidir(porco, 3) - + for ator in porcos + passaros: + ator.status = DESTRUIDO self.assertEqual(VITORIA, fase.status()) fase.adicionar_obstaculo(Obstaculo()) - self.assertEqual(VITORIA, fase.status(), 'Obstáculo não interfere no fim do jogo') + self.assertEqual(VITORIA, fase.status(), + 'Obstáculo não interfere no fim do jogo') - fase.adicionar_porco(Porco()) - self.assertEqual(DERROTA, fase.status(), 'Com Porco ativo e sem pássaro para lançar, o jogo deveria acabar') + fase.adicionar_porco(PorcoFake()) + self.assertEqual(DERROTA, fase.status(), + 'Com Porco ativo e sem pássaro para lançar, o jogo ' + 'deveria acabar') - fase.adicionar_passaro(PassaroAmarelo()) + fase.adicionar_passaro(PassaroFake()) self.assertEqual(EM_ANDAMENTO, fase.status(), - 'Com Porco ativo e com pássaro para lançar, o jogo não deveria acabar') + 'Com Porco ativo e com pássaro para lançar, o jogo ' + 'não deveria acabar') def teste_status(self): fase = Fase() - porcos = [Porco(1, 1) for i in range(2)] - passaros = [PassaroAmarelo(1, 1) for i in range(2)] + porcos = [PorcoFake(1, 1) for _ in range(2)] + passaros = [PassaroFake(1, 1) for _ in range(2)] fase.adicionar_porco(*porcos) fase.adicionar_passaro(*passaros) self.assertEqual(EM_ANDAMENTO, fase.status()) - for passaro, porco in zip(passaros, porcos): - passaro.colidir(porco, 3) - + for ator in porcos + passaros: + ator.status = DESTRUIDO self.assertEqual(VITORIA, fase.status(), - 'Sem porcos ativos o jogo deveria terminar com vitória') + 'Sem porcos ativos o jogo deveria terminar com ' + 'vitória') - fase.adicionar_obstaculo(Obstaculo()) + fase.adicionar_obstaculo(ObstaculoFake()) self.assertEqual(VITORIA, fase.status(), 'Obstáculo não interfere para definir vitória') - porco = Porco() + porco = PorcoFake() fase.adicionar_porco(porco) self.assertEqual(DERROTA, fase.status(), - 'Com Porco ativo e sem pássaro para lançar, o jogo deveria acabar em derrota') + 'Com Porco ativo e sem pássaro para lançar, o jogo ' + 'deveria acabar em derrota') - fase.adicionar_passaro(PassaroAmarelo()) + fase.adicionar_passaro(PassaroFake()) self.assertEqual(EM_ANDAMENTO, fase.status(), - 'Com Porco ativo e com pássaro para lançar, o jogo não deveria acabar') + 'Com Porco ativo e com pássaro para lançar, o jogo ' + 'não deveria acabar') - porco.colidir(porco, 3) + porco.status = DESTRUIDO self.assertEqual(VITORIA, fase.status(), 'Sem porco ativo, o jogo deveria acabar com vitória') def teste_lancar_passaro_sem_erro_quando_nao_existe_passaro(self): - passaro_vermelho, passaro_amarelo = PassaroVermelho(1, 1), PassaroAmarelo(1, 1) + passaros = [PassaroFake(1, 1) for _ in range(2)] fase = Fase() - fase.adicionar_passaro(passaro_vermelho, passaro_amarelo) - self.assertFalse(passaro_vermelho.foi_lancado()) - self.assertFalse(passaro_amarelo.foi_lancado()) + fase.adicionar_passaro(*passaros) + self.assertFalse(passaros[0].foi_lancado()) + self.assertFalse(passaros[1].foi_lancado()) fase.lancar(90, 1) fase.lancar(45, 3) - fase.lancar(31, 5) # testando que lançar passaros depios de todos lançados não causa erro + fase.lancar(31, + 5) # testando que lançar passaros depios de todos + # lançados não causa erro - self.assertTrue(passaro_vermelho.foi_lancado()) - self.assertEqual(math.radians(90), passaro_vermelho._angulo_de_lancamento) - self.assertEqual(1, passaro_vermelho._tempo_de_lancamento) - - self.assertTrue(passaro_amarelo.foi_lancado()) - self.assertEqual(math.radians(45), passaro_amarelo._angulo_de_lancamento) - self.assertEqual(3, passaro_amarelo._tempo_de_lancamento) + self.assertTrue(passaros[0].foi_lancado()) + self.assertTrue(passaros[1].foi_lancado()) def teste_intervalo_de_colisao_padrão(self): ''' - Método que testa se o intervalo de colisão da Fase é repassado aos atores. Padrão de intervalo é 1 + Método que testa se o intervalo de colisão da Fase é repassado aos + atores. Padrão de intervalo é 1 ''' fase = Fase() - passaro = PassaroAmarelo(1, 1) + passaro = PassaroFake(1, 1) fase.adicionar_passaro(passaro) - porco = Porco(2, 2) + porco = PorcoFake(2, 2) fase.adicionar_porco(porco) fase.calcular_pontos(0) - self.assertEqual(DESTRUIDO, passaro.status) - self.assertEqual(DESTRUIDO, porco.status) + self.assertTrue(passaro.colidir_executado) + self.assertTrue(porco.colidir_executado) + self.assertTrue(passaro.calcular_posicao_executado) + self.assertTrue(passaro.colidir_com_chao_executado) + self.assertEqual(1, passaro.intervalo_colisao) + self.assertEqual(1, porco.intervalo_colisao) def teste_intervalo_de_colisao_nao_padrao(self): ''' - Método que testa se o intervalo de colisão da Fase é repassado aos atores. valor testado: 31 + Método que testa se o intervalo de colisão da Fase é repassado aos + atores. valor testado: 31 ''' fase = Fase(30) - passaro = PassaroAmarelo(1, 1) + passaro = PassaroFake(1, 1) fase.adicionar_passaro(passaro) - porco = Porco(31, 31) + porco = PorcoFake(31, 31) fase.adicionar_porco(porco) fase.calcular_pontos(0) - self.assertEqual(DESTRUIDO, passaro.status) - self.assertEqual(DESTRUIDO, porco.status) - - def teste_calcular_pontos(self): - fase_exemplo = criar_fase_exemplo() - expected = set([Ponto(3, 3, 'A'), Ponto(3, 3, 'A'), Ponto(31, 10, 'O'), Ponto(78, 1, '@'), - Ponto(70, 1, '@'), Ponto(3, 3, 'V')]) - self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(0))) - - fase_exemplo.lancar(45, 1) - - # i variando de 1 até 2.9 - for i in range(100, 300, 1): - fase_exemplo.calcular_pontos(i / 100) - - fase_exemplo.lancar(63, 3) - - # i variando de 3 até 3.9 - for i in range(300, 400, 1): - fase_exemplo.calcular_pontos(i / 100) - - fase_exemplo.lancar(23, 4) - - expected = set([Ponto(32, 11, 'v'), Ponto(17, 25, 'A'), Ponto(3, 3, 'A'), Ponto(31, 10, ' '), Ponto(78, 1, '@'), - Ponto(70, 1, '@')]) - - self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(4))) - - # i variando de 4 até 6.9 - for i in range(400, 700, 1): - fase_exemplo.calcular_pontos(i / 100) - - expected = set( - [Ponto(32, 11, 'v'), Ponto(57, 30, 'A'), Ponto(70, 2, 'a'), Ponto(31, 10, ' '), Ponto(78, 1, '@'), - Ponto(70, 1, '+')]) - - self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(7))) - - # i variando de 7 até 8.49 - for i in range(700, 849, 1): - fase_exemplo.calcular_pontos(i / 100) - print(fase_exemplo.calcular_pontos(8.5)) - - expected = set([Ponto(32, 11, 'v'), Ponto(77, 0, 'a'), Ponto(70, 2, 'a'), Ponto(31, 10, ' '), Ponto(78, 1, '+'), - Ponto(70, 1, '+')]) - - self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(8.5))) - - self.assertEqual(VITORIA, fase_exemplo.status()) - - -def criar_fase_exemplo(multiplicador=1): - fase_exemplo = Fase(1 if multiplicador == 1 else 32) - passaros = [PassaroVermelho(3 * multiplicador, 3 * multiplicador), - PassaroAmarelo(3 * multiplicador, 3 * multiplicador), - PassaroAmarelo(3 * multiplicador, 3 * multiplicador)] - porcos = [Porco(78 * multiplicador, multiplicador), Porco(70 * multiplicador, multiplicador)] - obstaculos = [Obstaculo(31 * multiplicador, 10 * multiplicador)] - - fase_exemplo.adicionar_passaro(*passaros) - fase_exemplo.adicionar_porco(*porcos) - fase_exemplo.adicionar_obstaculo(*obstaculos) - - return fase_exemplo - - -if __name__ == '__main__': - rodar_fase(criar_fase_exemplo(10)) + self.assertEqual(30, passaro.intervalo_colisao) + self.assertEqual(30, porco.intervalo_colisao) diff --git a/testes/integracao.py b/testes/integracao.py new file mode 100644 index 000000000..11f2f0178 --- /dev/null +++ b/testes/integracao.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +from itertools import chain + +import os +from os import path +from unittest.case import TestCase +import math +import sys + +project_dir = path.dirname(__file__) +project_dir = path.join('..') +sys.path.append(project_dir) +from placa_grafica_tkinter import rodar_fase + +project_dir = os.path.join(os.path.dirname(__file__), '..') +project_dir = os.path.normpath(project_dir) +sys.path.append(project_dir) + +from atores import Obstaculo, Porco, PassaroVermelho, PassaroAmarelo, DESTRUIDO, ATIVO, \ + Ator, Passaro +from fase import Fase, Ponto, EM_ANDAMENTO, VITORIA, DERROTA + +class FaseTestes(TestCase): + def teste_acabou_com_porcos_e_passaros(self): + fase = Fase() + porcos = [Porco(1, 1) for i in range(2)] # criando 2 porcos + passaros = [PassaroAmarelo(1, 1) for i in range(2)] # criando 2 pássaros + fase.adicionar_porco(*porcos) + fase.adicionar_passaro(*passaros) + + self.assertEqual(EM_ANDAMENTO, fase.status()) + + # colidindo cada passaro com um porco no tempo 3 + for passaro, porco in zip(passaros, porcos): + passaro.colidir(porco, 3) + + self.assertEqual(VITORIA, fase.status()) + + fase.adicionar_obstaculo(Obstaculo()) + self.assertEqual(VITORIA, fase.status(), 'Obstáculo não interfere no fim do jogo') + + fase.adicionar_porco(Porco()) + self.assertEqual(DERROTA, fase.status(), 'Com Porco ativo e sem pássaro para lançar, o jogo deveria acabar') + + fase.adicionar_passaro(PassaroAmarelo()) + self.assertEqual(EM_ANDAMENTO, fase.status(), + 'Com Porco ativo e com pássaro para lançar, o jogo não deveria acabar') + + def teste_status(self): + fase = Fase() + porcos = [Porco(1, 1) for i in range(2)] + passaros = [PassaroAmarelo(1, 1) for i in range(2)] + fase.adicionar_porco(*porcos) + fase.adicionar_passaro(*passaros) + self.assertEqual(EM_ANDAMENTO, fase.status()) + + for passaro, porco in zip(passaros, porcos): + passaro.colidir(porco, 3) + + self.assertEqual(VITORIA, fase.status(), + 'Sem porcos ativos o jogo deveria terminar com vitória') + + fase.adicionar_obstaculo(Obstaculo()) + self.assertEqual(VITORIA, fase.status(), + 'Obstáculo não interfere para definir vitória') + + porco = Porco() + fase.adicionar_porco(porco) + self.assertEqual(DERROTA, fase.status(), + 'Com Porco ativo e sem pássaro para lançar, o jogo deveria acabar em derrota') + + fase.adicionar_passaro(PassaroAmarelo()) + self.assertEqual(EM_ANDAMENTO, fase.status(), + 'Com Porco ativo e com pássaro para lançar, o jogo não deveria acabar') + + porco.colidir(porco, 3) + self.assertEqual(VITORIA, fase.status(), + 'Sem porco ativo, o jogo deveria acabar com vitória') + + def teste_lancar_passaro_sem_erro_quando_nao_existe_passaro(self): + passaro_vermelho, passaro_amarelo = PassaroVermelho(1, 1), PassaroAmarelo(1, 1) + fase = Fase() + fase.adicionar_passaro(passaro_vermelho, passaro_amarelo) + self.assertFalse(passaro_vermelho.foi_lancado()) + self.assertFalse(passaro_amarelo.foi_lancado()) + fase.lancar(90, 1) + fase.lancar(45, 3) + fase.lancar(31, 5) # testando que lançar passaros depios de todos lançados não causa erro + + self.assertTrue(passaro_vermelho.foi_lancado()) + self.assertEqual(math.radians(90), passaro_vermelho._angulo_de_lancamento) + self.assertEqual(1, passaro_vermelho._tempo_de_lancamento) + + self.assertTrue(passaro_amarelo.foi_lancado()) + self.assertEqual(math.radians(45), passaro_amarelo._angulo_de_lancamento) + self.assertEqual(3, passaro_amarelo._tempo_de_lancamento) + + def teste_intervalo_de_colisao_padrão(self): + ''' + Método que testa se o intervalo de colisão da Fase é repassado aos atores. Padrão de intervalo é 1 + ''' + fase = Fase() + passaro = PassaroAmarelo(1, 1) + fase.adicionar_passaro(passaro) + porco = Porco(2, 2) + fase.adicionar_porco(porco) + fase.calcular_pontos(0) + self.assertEqual(DESTRUIDO, passaro.status) + self.assertEqual(DESTRUIDO, porco.status) + + def teste_intervalo_de_colisao_nao_padrao(self): + ''' + Método que testa se o intervalo de colisão da Fase é repassado aos atores. valor testado: 31 + ''' + fase = Fase(30) + passaro = PassaroAmarelo(1, 1) + fase.adicionar_passaro(passaro) + porco = Porco(31, 31) + fase.adicionar_porco(porco) + fase.calcular_pontos(0) + self.assertEqual(DESTRUIDO, passaro.status) + self.assertEqual(DESTRUIDO, porco.status) + + def teste_calcular_pontos(self): + fase_exemplo = criar_fase_exemplo() + expected = set([Ponto(3, 3, 'A'), Ponto(3, 3, 'A'), Ponto(31, 10, 'O'), Ponto(78, 1, '@'), + Ponto(70, 1, '@'), Ponto(3, 3, 'V')]) + self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(0))) + + fase_exemplo.lancar(45, 1) + + # i variando de 1 até 2.9 + for i in range(100, 300, 1): + fase_exemplo.calcular_pontos(i / 100) + + fase_exemplo.lancar(63, 3) + + # i variando de 3 até 3.9 + for i in range(300, 400, 1): + fase_exemplo.calcular_pontos(i / 100) + + fase_exemplo.lancar(23, 4) + + expected = set([Ponto(32, 11, 'v'), Ponto(17, 25, 'A'), Ponto(3, 3, 'A'), Ponto(31, 10, ' '), Ponto(78, 1, '@'), + Ponto(70, 1, '@')]) + + self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(4))) + + # i variando de 4 até 6.9 + for i in range(400, 700, 1): + fase_exemplo.calcular_pontos(i / 100) + + expected = set( + [Ponto(32, 11, 'v'), Ponto(57, 30, 'A'), Ponto(70, 2, 'a'), Ponto(31, 10, ' '), Ponto(78, 1, '@'), + Ponto(70, 1, '+')]) + + self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(7))) + + # i variando de 7 até 8.49 + for i in range(700, 849, 1): + fase_exemplo.calcular_pontos(i / 100) + print(fase_exemplo.calcular_pontos(8.5)) + + expected = set([Ponto(32, 11, 'v'), Ponto(77, 0, 'a'), Ponto(70, 2, 'a'), Ponto(31, 10, ' '), Ponto(78, 1, '+'), + Ponto(70, 1, '+')]) + + self.assertSetEqual(expected, set(fase_exemplo.calcular_pontos(8.5))) + + self.assertEqual(VITORIA, fase_exemplo.status()) + + +def criar_fase_exemplo(multiplicador=1): + fase_exemplo = Fase(1 if multiplicador == 1 else 32) + passaros = [PassaroVermelho(3 * multiplicador, 3 * multiplicador), + PassaroAmarelo(3 * multiplicador, 3 * multiplicador), + PassaroAmarelo(3 * multiplicador, 3 * multiplicador)] + porcos = [Porco(78 * multiplicador, multiplicador), Porco(70 * multiplicador, multiplicador)] + obstaculos = [Obstaculo(31 * multiplicador, 10 * multiplicador)] + + fase_exemplo.adicionar_passaro(*passaros) + fase_exemplo.adicionar_porco(*porcos) + fase_exemplo.adicionar_obstaculo(*obstaculos) + + return fase_exemplo + + +if __name__ == '__main__': + rodar_fase(criar_fase_exemplo(10)) diff --git a/testes/testes_placa_grafica.py b/testes/testes_placa_grafica.py index 025c04004..556328f98 100644 --- a/testes/testes_placa_grafica.py +++ b/testes/testes_placa_grafica.py @@ -14,8 +14,6 @@ def teste_inverter_coordenadas(self): self.assertTupleEqual((10, 0), placa_grafica.normalizar_coordenadas(10, placa_grafica.ALTURA - 1)) def teste_desenhar_frame_vazio(self): - self.maxDiff = None - class PontoCartesiano(): def __init__(self, x, y, caracter): self.caracter = caracter