fork download
  1. # als-parcial2-2021_23 (c) 2023 Baltasar MIT License <baltasarq@gmail.com>
  2.  
  3.  
  4. import json
  5.  
  6.  
  7. """
  8.  
  9. 1. (4 pts.) VideoESEI, un joven estudio de videojuegos,
  10. quiere llegar pronto al mercado con un juego run&gun,
  11. es decir, el jugador, uno de los Pj (personajes),
  12. siempre está corriendo, y disparando a enemigos para
  13. aumentar su puntuación (momento en el que debe ralentizarse).
  14. Como los plazos son muy justos,
  15. deciden utilizar Python como lenguaje de programación,
  16. y llegan a la clase listada más abajo.
  17. La clase debe almacenar el id (__id) y el delta (__delta) del Pj,
  18. de forma que el id es una cadena de caracteres que
  19. se pasa como parámetro, y el delta un número entero que indica
  20. cuántos píxeles avanza de cada vez, inicializado a cero.
  21. El método set_delta(nd: int) acepta un entero para cambiar el delta
  22. por el nd (nuevo delta), y __str_() devuelve la información en el
  23. formato "<nombre_clase> (<id>): <delta>".
  24. Hay que tener en cuenta las siguientes cuestiones:
  25. a) La clase Pj debe ser capaz de responder a las propiedades delta e id,
  26. aunque por razones de compatibilidad con la versión de Python
  27. que se distribuirá con el juego, no pueden ser propiedades como tal.
  28. Así, si p1 = Pj("Corredor"), entonces p1.delta devolverá el
  29. atributo __delta, y p1.id devuelve su atributo __id,
  30. a pesar de que no existan las propiedades id o delta.
  31. b) Cuando se crea p1 como PjCaminante,
  32. su delta debe inicializarse a PjCorredor.MIN_DELTA // 2.
  33. En cambio, cuando se crea como PjCorredor, debe inicializarse a
  34. PjCorredor.MIN_DELTA * 2.
  35. c) Cuando set_delta(nd) es llamado para modificar el delta con
  36. nd (nuevo delta), si el nuevo delta es mayor o igual
  37. que PjCorredor.MIN_DELTA, la clase del objeto debe cambiar
  38. automáticamente a PjCorredor. Si es más pequeño
  39. que PjCorredor.MIN_DELTA, debe cambiar a PjCaminante.
  40. Por ejemplo, si p1 = PjCaminante(“Mario”),
  41. por tanto type(p1) == PjCaminante;
  42. después de p1.set_delta(10), type(p1) == PjCorredor.
  43. d) Cuando dispara() es llamado siendo p1 un PjCorredor,
  44. automáticamente el delta debe cambiar a PjCorredor.MIN_DELTA // 2,
  45. y por tanto la clase de p1 debe pasar a ser PjCaminante.
  46. Así, si p1 = PJCorredor(“Flash”) y p1.dispara() (devuelve “BANG!”),
  47. entonces type(p1) == PJCaminante debe ser cierto.
  48.  
  49. 2. (3pts.) Cree los métodos to_str_json() -> str
  50. y from_str_json(s: str) -> Pj.
  51. El primero escribe la codificación JSON de los datos necesarios
  52. del objeto a una cadena de caracteres, el segundo (estático),
  53. toma una cadena de caracteres con el contenido necesario
  54. en formato JSON y crea un objeto PjCaminante o PjCorredor con dicho contenido,
  55. según sea apropiado.
  56. Estos métodos son utilizados desde to_json(f) y from_json(f)
  57. para volcar o crear los datos desde o hacia un archivo.
  58. """
  59. class Pj:
  60. def __init__(self, id):
  61. self.__id = id
  62. self.__delta = 0
  63.  
  64. def __getattr__(self, item):
  65. if item == "delta":
  66. return self.__delta
  67. elif item == "id":
  68. return self.__id
  69.  
  70. raise AttributeError(item)
  71.  
  72. def set_delta(self, value):
  73. self.__delta = value
  74.  
  75. def to_json(self, f) -> str:
  76. f.write(self.to_str_json())
  77.  
  78. def to_str_json(self) -> str:
  79. return json.dumps(self.__dict__)
  80.  
  81. @staticmethod
  82. def from_json(f):
  83. return Pj.from_str_json(str.join("\n", f.readlines()))
  84.  
  85. @staticmethod
  86. def from_str_json(s: str):
  87. toret = PjCaminante("")
  88. toret.__dict__ = json.loads(s)
  89. toret.set_delta(toret.delta)
  90. return toret
  91.  
  92. def __str__(self):
  93. return f"{self.__class__.__name__} ({self.id}): {self.delta}"
  94.  
  95.  
  96. class PjCorredor(Pj):
  97. MIN_DELTA = 4
  98. def __init__(self, id):
  99. super().__init__(id)
  100. self.set_delta(PjCorredor.MIN_DELTA * 2)
  101.  
  102. def set_delta(self, value):
  103. super().set_delta(value)
  104. if value < PjCorredor.MIN_DELTA:
  105. self.__class__ = PjCaminante
  106.  
  107. def dispara(self):
  108. self.set_delta(PjCorredor.MIN_DELTA // 2)
  109. return self.dispara()
  110.  
  111.  
  112. class PjCaminante(Pj):
  113. def __init__(self, id):
  114. super().__init__(id)
  115. self.set_delta(PjCorredor.MIN_DELTA // 2)
  116.  
  117. def set_delta(self, value):
  118. super().set_delta(value)
  119.  
  120. if value > PjCorredor.MIN_DELTA:
  121. self.__class__ = PjCorredor
  122.  
  123. def dispara(self):
  124. return "BANG!"
  125.  
  126.  
  127. """
  128. 3. (3pts.) Escriba la función filtra_pjs(f: callable, pjs: list[Pj) -> list[Pj],
  129. que recibe como parámetros una lista de objetos Pj y
  130. una función que devolverá verdadero o falso según el objeto Pj que se le pase.
  131. Deben utilizarse exclusivamente lambdas como parámetro de este método.
  132. Cree la función busca_pjs_veloces(pjs: list[Pj]) -> list[Pj],
  133. que llama a la función anterior para encontrar a aquellos Pj’s
  134. que tienen un delta superior a 5.
  135. """
  136.  
  137.  
  138. def filtra_pjs(f: callable, pjs: list[Pj]) -> list[Pj]:
  139. return [pj for pj in pjs if f(pj)] # opc1
  140. # return filter(f, pjs) # opc2
  141.  
  142.  
  143. """
  144. def busca_pjs_veloces(pjs: list[Pj]) -> list[Pj]:
  145. return filtra_pjs(lambda pj: pj.delta > 5, pjs) # opc1
  146. """
  147.  
  148. busca_pjs_veloces = lambda pjs: \
  149. filtra_pjs(lambda pj: pj.delta > 5, pjs) # opc2
  150.  
  151.  
  152. if __name__ == "__main__":
  153. pj1 = PjCaminante("Mario")
  154. print(str(pj1))
  155. pj1.set_delta(8)
  156. print(str(pj1))
  157. print(pj1.dispara())
  158. print(str(pj1))
  159.  
  160. print("\nGuardando y recuperando pj1 (Mario)")
  161. str_pj1 = pj1.to_str_json()
  162. print(Pj.from_str_json(str_pj1))
  163.  
  164. print("\nBuscando a los veloces de entre Mario(2), Flash(8) y Sonic(8)")
  165. pj2 = PjCorredor("Flash")
  166. pj3 = PjCorredor("Sonic")
  167. print(", ".join(str(pj) for pj in busca_pjs_veloces([pj1, pj2, pj3])))
  168.  
  169. """
  170. # Tests als-parcial2-2021_23 (c) 2023 Baltasar MIT License <baltasarq@gmail.com>
  171.  
  172.  
  173. import unittest
  174.  
  175. from als_parcial2_2021_23 import Pj, PjCorredor, PjCaminante, filtra_pjs, busca_pjs_veloces
  176.  
  177.  
  178. class TestPj(unittest.TestCase):
  179. def setUp(self):
  180. self.pj = Pj("Mario")
  181. self.pjcorredor = PjCorredor("Sonic")
  182. self.pjcaminante = PjCaminante("Yoshi")
  183.  
  184. def test_creacion_pj(self):
  185. self.assertEqual("Mario", self.pj.id)
  186. self.assertEqual(0, self.pj.delta)
  187. self.assertEqual("(Mario): 0", str(self.pj))
  188.  
  189. def test_creacion_pj_corredor(self):
  190. self.assertEqual("Sonic", self.pjcorredor.id)
  191. self.assertEqual(8, self.pjcorredor.delta)
  192. self.assertEqual("PjCorredor (Sonic): 8", str(self.pjcorredor))
  193.  
  194. def test_creacion_pj_caminante(self):
  195. self.assertEqual("Yoshi", self.pjcaminante.id)
  196. self.assertEqual(2, self.pjcaminante.delta)
  197. self.assertEqual("PjCaminante (Yoshi): 2", str(self.pjcaminante))
  198.  
  199. def test_modificacion_delta_pj(self):
  200. self.pj.set_delta(10)
  201. self.assertEqual(10, self.pj.delta)
  202. self.assertEqual(Pj, self.pj.__class__)
  203.  
  204. def test_modificacion_delta_corredor(self):
  205. self.pjcorredor.set_delta(10)
  206. self.assertEqual(10, self.pjcorredor.delta)
  207. self.assertEqual(PjCorredor, self.pjcorredor.__class__)
  208.  
  209. def test_modificacion_delta_caminante(self):
  210. self.pjcaminante.set_delta(3)
  211. self.assertEqual(3, self.pjcaminante.delta)
  212. self.assertEqual(PjCaminante, self.pjcaminante.__class__)
  213.  
  214. def test_modificacion_delta_caminante_a_corredor(self):
  215. self.pjcaminante.set_delta(10)
  216. self.assertEqual(10, self.pjcaminante.delta)
  217. self.assertEqual(PjCorredor, self.pjcaminante.__class__)
  218.  
  219. def test_modificacion_delta_corredor_a_caminante(self):
  220. self.pjcorredor.set_delta(2)
  221. self.assertEqual(2, self.pjcorredor.delta)
  222. self.assertEqual(PjCaminante, self.pjcorredor.__class__)
  223.  
  224. def test_bang_caminante(self):
  225. self.assertEqual("BANG!", self.pjcaminante.dispara())
  226. self.assertEqual(PjCaminante, self.pjcaminante.__class__)
  227.  
  228. def test_bang_corredor(self):
  229. self.assertEqual("BANG!", self.pjcorredor.dispara())
  230. self.assertEqual(PjCaminante, self.pjcorredor.__class__)
  231. self.assertEqual(PjCorredor.MIN_DELTA // 2, self.pjcorredor.delta)
  232.  
  233. def test_json(self):
  234. str_pj = self.pj.to_str_json()
  235. str_pjcaminante = self.pjcaminante.to_str_json()
  236. str_pjcorredor = self.pjcorredor.to_str_json()
  237.  
  238. pj2 = Pj.from_str_json(str_pj)
  239. pjcaminante2 = Pj.from_str_json(str_pjcaminante)
  240. pjcorredor2 = Pj.from_str_json(str_pjcorredor)
  241.  
  242. self.assertEqual(self.pj.id, pj2.id)
  243. self.assertEqual(self.pj.delta, pj2.delta)
  244.  
  245. self.assertEqual(self.pjcaminante.id, pjcaminante2.id)
  246. self.assertEqual(self.pjcaminante.delta, pjcaminante2.delta)
  247.  
  248. self.assertEqual(self.pjcorredor.id, pjcorredor2.id)
  249. self.assertEqual(self.pjcorredor.delta, pjcorredor2.delta)
  250.  
  251.  
  252. def test_filtra(self):
  253. pjs = [self.pj, self.pjcaminante, self.pjcorredor]
  254.  
  255. pjs_rapidos = busca_pjs_veloces(pjs)
  256. self.assertEqual([self.pjcorredor], pjs_rapidos)
  257.  
  258. pjs_lentos1 = filtra_pjs(lambda pj: pj.delta > 0 and pj.delta < PjCorredor.MIN_DELTA, pjs)
  259. pjs_lentos2 = filtra_pjs(lambda pj: type(pj) == PjCaminante, pjs)
  260. self.assertEqual(pjs_lentos1, pjs_lentos2)
  261.  
  262.  
  263. if __name__ == "__main__":
  264. unittest.main()
  265. """
Success #stdin #stdout 0.03s 10224KB
stdin
Standard input is empty
stdout
PjCaminante (Mario): 2
PjCorredor (Mario): 8
BANG!
PjCaminante (Mario): 2

Guardando y recuperando pj1 (Mario)
PjCaminante (Mario): 2

Buscando a los veloces de entre Mario(2), Flash(8) y Sonic(8)
PjCorredor (Flash): 8, PjCorredor (Sonic): 8