Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proyecto de Claudia y Roger #34

Open
15 tasks done
RogerMo01 opened this issue Jul 16, 2022 · 4 comments
Open
15 tasks done

Proyecto de Claudia y Roger #34

RogerMo01 opened this issue Jul 16, 2022 · 4 comments
Assignees
Labels
Aprobado Cuando se de la evaluación final por el colectivo de la asignatura

Comments

@RogerMo01
Copy link

RogerMo01 commented Jul 16, 2022

Modifique las líneas siguientes con los detalles relevantes:

Equipo

Proyecto

Checklist

(Esta lista es para el mentor. Hasta que no estén chequeados estos elementos no se procederá a la evaluación en persona.)

Básicos

  • El repositorio indicado existe y tiene un Readme.md no vacío.
  • Los miembros del equipo tienen un usuario de Github válido.
  • El proyecto puede ser ejecutado siguiendo las instrucciones del Readme.md.
  • El reporte existe y tiene la longitud adecuada.

Funcionalidades

  • El proyecto permite configurar al menos 5 elementos relevantes de la mecánica del dominó.
  • El proyecto contiene 2 implementaciones diferentes de cada elemento configurable.
  • El proyecto permite personalizar las estrategias de los jugadores virtuales.
  • El proyecto contiene al menos 3 implementaciones diferentes de jugadores virtuales.

Ingeniería de Software

  • Las estrategias de jugadores virtuales pueden combinarse con cualquier configuración del juego de forma transparente.
  • La interfaz gráfica permite configurar el juego en toda la extensión que brinda la lógica.
  • Las jerarquías de clases y demás abstracciones existentes son adecuadas para modelar el dominio.
  • El código muestra una organización y estructura mantenible y extensible, respetando las buenas prácticas de la ingeniería de software.

Documentación

  • El reporte técnico explica de forma suficientemente detallada los pormenores del proyecto.
  • Los nombres de clases, métodos y variables son descriptivos.
  • Los comentarios son legibles y útiles para entender el funcionamiento del código.

Revisión

Fecha prevista: 2020/XX/XX

Comentarios

(Para rellenar por el mentor)

@lead8000 lead8000 self-assigned this Aug 10, 2022
@lead8000
Copy link
Member

lead8000 commented Aug 10, 2022

Consideraciones generales

El Report.pdf lo que tiene está bien redactado, da una idea general de los aspectos variables del proyecto, pero no entra en muchos detalles, lo cual dificulta mucho la comprensión de su solución. El código tiene poca documentación, por lo que se hace muy difícil entender las clases y aspectos que no fueron abordados en el report.

A continuación les dejaré algunas de las principales preguntas que me fueron surgiendo a medida que fui revisando el proyecto:

Jerarquía de clases

  • ¿Por qué la clase Board es partial?

  • ¿Por qué el método Start() de Board imprime las manos de los jugadores?
    Hint: Todos los aspectos del funcionamiento del juego deben estar aislados de la forma en que se mostrará este.

  • El nombre del método Start() de Board no compagina con el funcionamiento del mismo.

  • No queda clara la funcionalidad de la clase Board.
    Hint: Recuerden el principio de responsabilidad única.

  • ¿Por qué la clase Pass hereda de la clase Token_onBoard, si estos dos objetos no encierran el mismo concepto?
    Hint: Aquí sería válido cuestionarse hasta el porqué la clase Token_onBoard hereda de Token.

  • ¿Dónde surge la necesidad de crear una clase para modelar el comportamiento de Lapse?

  • ¿Por qué se modela el comportamiento de Setting con una clase abstracta?

  • ¿Por qué un jugador debe preocuparse por el color con el que se va a mostrar sus fichas?

Console App

  • ¿Las configuraciones del Max Token y la cantidad de jugadores pueden incrementar sus valores?

  • El segundo aspecto a elegir para la ejecución del juego es el Game Mode, luego de este se selecciona el template que se usará o configurar uno propio, en este último caso vuelve a salir la opción de seleccionar el Game Mode, ¿acaso esto no es redundante?

  • Cuando se esta configurando un template, para el juego por equipos no me permite formar más de 2 equipos. ¿Es posible hacerlo? ¿Cómo?

Conclusiones

El proyecto está poco intuitivo, el nombre de variables, métodos, clases no ayudan mucho. No queda claro cual es el flujo de ejecución del programa, ni el objetivo que cumplen muchas clases de la jerarquía. Se me quedaron muchas otras dudas respecto a las decisiones de diseño que tomaron, pero no me gustaría dar una opinión sin antes entender a profundidad las ideas principales que están detrás de cada clase o método que no están documentados.

Por último el juego tiene pocas abstracciones, tiene como aspecto configurable el Max de Token con las opciones de Double 6 - 12. Por ejemplo, configuraciones tan simplistas no se consideran un aspecto configurable en la mecánica del juego.

@RogerMo01
Copy link
Author

Dependencia de los colores hacia los jugadores

Anteriormente el color con el que un jugador, así como sus fichas, se iban a mostrar mediante la interfaz gráfica, era una propiedad más de la clase jugador. Este atributo, solo relacionado con la aplicación de consola no debería estar atado al jugador. Por ello hemos eliminado la dependencia dando a la consola la tarea de crear un diccionario con una relación de jugador-color. Hemos definido un método en la clase Utils.cs que asigna los colores y devuelve el diccionario correspondiente.

Interface IPlay

Ahora surge esta interfaz con el objetivo de abstraer el concepto de qué constituye una jugada. Una jugada puede ser tanto una ficha que se juega en la mesa, como un pase de un jugador sin opciones de jugada válida. De esta manera se elimina la relación de herencia que tenía la clase Pass de la clase Token_onBoard.

Menos responsabilidad

La clase Board tenía un método llamado Start() que se encargaba de hacer el recorrido de lo que significa una ronda del juego de Domino, así como mostrar las jugadas mientras se ejecutaba la partida. Para simplificar un poco las responsabilidades, el método se separa en dos partes: una para controlar el juego, y la otra dedicada por completo a la elección de las jugadas por los jugadores. La primera en Start(), y la segunda en GetPlay().

Inner Selector Judgment

Con un delegado abstraemos el criterio con que se elige el jugador que va a comenzar jugando en una partida. Quedan definidos en el archivo InnerPlayer.cs.

public delegate IPlayer Inner(Dictionary<IPlayer, List<Token>> PlayersTokens);

Las diferentes implementaciones actuales son:

Random:

De manera aleatoria se decide cual de los jugadores en mesa será el primero en colocar una de sus fichas al inicio de cada partida.

Bigger Token:

Si eres uno de los jugadores de los cuales no le gusta la ficha doble-9, la cual de seguro conoces como "la gorda", tendrás la oportunidad de ser el iniciador del juego y poder deshacerte de ella rápidamente.

En cuanto a código, lo que hacemos es recorrer cada una de las fichas de cada jugador para ver cual de ellos posee la ficha con mayor puntuación. Ojo, no tiene por qué ser el doble-9, todo depende de a cual doble máximo se esté jugando y las fichas que hayan sido repartidas.

Min Double:

Esta variación del juego es muy semejante a la anterior, con la diferencia de que al iterar por cada una de las fichas de los jugadores, el jugador seleccionado para ser el iniciador del juego será aquel que tenga en su poder el menor doble entre las fichas repartidas a los jugadores.

En caso de no exisitir dobles en mesa, o sea, que ningun jugador tenga en su mano una ficha de esta característica, lo cual es muy poco probable, el iniciador del juego será elegido de forma aleatoria.

Max Data:

Hemos querido que el iniciador del juego también pueda ser aquel que tiene la "mejor data", o sea, la mayor cantidad de caras repetidas entre las fichas de su mano.

Para la implementación, como nuestro delegado solo recibe un diccionario con los jugadores y sus fichas asignadas, tuvimos que auxiliarnos de dos métodos extras:

  • private static int Max_NumberToken(Dictionary<IPlayer, List<Token>> PlayersTokens){
           ... 
        }
    

    Este método fue implementado con el objetivo de saber cual es la cara de mayor valor entre las fichas de nuestros participantes.

  • private static List<(IPlayer, int[])> PlayersCountTokens(Dictionary<IPlayer, List<Token>> PlayersTokens, IPlayer[] players, int maxNumberToken){
        ...
        }
    

    Dada la información obtenida con el método anterior, creamos un array en el cual vamos a tener guardada la cantidad de cada una de las caras en las fichas en juego por cada uno de los jugadores.

    Por último, con la información anterior, nuestro método principal es capaz de seleccionar entre los jugadores aquel que tenga la "mejor data". Si existen dos jugadores con la cantidad máxima, el elegido será aquel que haya sido encontrado primero.

Para acoplar esta nueva funcionalidad al juego fue necesario incluir nuevo código en nuestro programa. Comenzando desde el inicio, creamos un nuevo método InnerSelectorMenu() que será ejecutado en el menú de personalización del juego, este se encarga de mostrar las opciones y permite al usuario elegir una. La opción elegida ahora va a ser una nueva propiedad de la clase Judge, a través de la cual llegará a la clase Board, en cuyo constructor se ejecutará el delegado. También fue necesario instanciar el delegado el los métodos donde se cargan las plantillas por defecto.

Por otra parte tuvimos la necesidad de crear un nuevo método en la clase CircularList, llamado RotateTill(), cuyo funcionamiento es: dada una instancia de CircularList y un elemento de la misma (pasado como parámetro), rota todos los elementos de manera que el elemento que recibe como parámetro, ahora sea el primero en la estructura de dato.

Lapse:

La clase Lapse fue reemplazada por un método en la clase Utils con el mismo funcionamiento. No tenía la complejidad suficiente para estar en una clase. Por eso se simplificó en un método.

@lead8000
Copy link
Member

Consideraciones generales

Partiendo de esta interface:

public interface IGame 
{
  GameResult Start();

  void SetGamePrinter(GamePrinter gamePrinter);
}

Según esta interface sus responsabilidades serían:

  • Un juego es un objeto que dada una función de inicialización y devuelve un GameResult
  • Dado un GamePrinter imprimir la ejecución del mismo.

Observaciones

  • Un juego para ser ejecutado no necesariamente debe de mostrarse, una jerarquía de esta forma lo está forzando.
  • El nombre del método Start() no compagina con la función que realiza.
  • La clase Board, que es la implementación concreta de dicha interface, sigue teniendo errores.
    • Lo primero es que su nombre no corresponde con lo que se supone que debe modelar (un juego).
    • Además de ser el encargado de la ejecución del juego, es quien guarda el historial de este, actualiza las manos de los jugadores, el estado de la mesa, selecciona un token random, etc. Claramente incumple el principio de responsabilidad única.
    • Mal uso de los modificadores de acceso (uso excesivo de public). Por ejemplo si su clase Board es la que lleva el control del juego, ¿por qué la lista de las jugadas sería pública?
  • Como los jugadores dependen de un Board para ejecutar su jugada y este objeto no está bien diseñado, se deja en duda si restructurando la jerarquía esta siga siendo una dependencia válida.

@RogerMo01
Copy link
Author

Desacoplamiento:

Dada la dependencia que existía entre las clases Board y Tournament con la visualización del juego durante la ejecución, hemos desacoplado las responsabilidades de las mismas, lo cual implicó la reestructuración de una parte de la jerarquía en la librería de clases.

Las responsabilidades de impresión de los resultados pasan ahora a estar por completo en la aplicación de consola. De esta manera se puede ejecutar una partida sin que necesariamente esta se muestre.

La clase Board deja de existir y ahora surge la clase Round, como la encargada de la ejecución de una ronda de juego de domino, mientras que Tournament se adapta a los cambios pero manteniendo su objetivo.

¿Cómo lograrlo?

Para ello se redefine la interface IGame con un único método:

public interface IGame
{
    IEnumerable<GameStatus> NextMove();
}

De esta manera las clases que la implementen van a tener este método que se encarga de devolver estados concretos del juego en cada momento. Utilizando yield return logramos obtener estos estados de forma Lazy. Los estados de juego de los IGame quedan definidos en la clase GameStatus.cs. A través de los GameStatus, la aplicación de consola recorre el juego y muestra al usuario la información necesaria para la visualización del juego.

Otros cambios:

Como consecuencia del desacoplamiento muchas clases de la jerarquía y métodos fueron modificados.

  • Los jugadores recibían como parámetro una instancia de Board para poder jugar, ahora con la desaparición de esta, surgió la clase BoardInfo.cs con los datos que un jugador necesita para poder devolver una jugada (las fichas en mesa, los extremos de la mesa, etc).
  • Surge la clase ConsoleApp.cs con el flujo principal de la ejecución del juego.
  • Desaparece la clase GamePrinter.cs, pues su objetivo era vinculado a la visualización mediante la interfaz gráfica.
  • Surge la clase estática ConsolePrinter.cs que reune a todos los métodos que son puramente de visualización e interacción con la consola.
  • Reestructuración en cuanto a organización de algunas clases en el repositorio.

Dada la dimensión de los cambios, tuvimos que reescribir una parte de la información del Reporte, donde quedan explicadas las nuevas características e implementaciones de nuestro proyecto "Dommie", así como otras funcionalidades implementadas que antes no quedaron detalladas.

@lead8000 lead8000 added the Listo para exponer Cuando estén todos los checkbox marcados y la fecha de exposición esté conveniada label Aug 30, 2022
@lead8000 lead8000 added Listo para evaluar Cuando se haya hecho la exposición y el mentor haya dado las conclusiones finales en el issue and removed Listo para exponer Cuando estén todos los checkbox marcados y la fecha de exposición esté conveniada labels Sep 8, 2022
@lead8000 lead8000 added Aprobado Cuando se de la evaluación final por el colectivo de la asignatura and removed Listo para evaluar Cuando se haya hecho la exposición y el mentor haya dado las conclusiones finales en el issue labels Oct 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Aprobado Cuando se de la evaluación final por el colectivo de la asignatura
Projects
None yet
Development

No branches or pull requests

2 participants