Estoy tratando de tener una idea de cómo diseñar y pensar de una manera orientada a objetos y quiero obtener comentarios de la comunidad sobre este tema. El siguiente es un ejemplo de un juego de ajedrez que deseo diseñar de manera orientada a objetos. Este es un diseño muy amplio y mi enfoque en esta etapa es solo identificar quién es responsable de qué mensajes y cómo los objetos interactúan entre sí para simular el juego. Indique si hay elementos de mal diseño (alto acoplamiento, mala cohesión, etc.) y cómo mejorarlos.
El juego de ajedrez tiene las siguientes clases
- Tablero
- Jugador
- Pieza
- Cuadrado
- Ajedrez
El tablero está formado por cuadrados, por lo que se puede hacer responsable de crear y administrar objetos cuadrados. Cada pieza también está en un cuadrado, por lo que cada pieza también tiene una referencia al cuadrado en el que se encuentra. (¿Esto tiene sentido?). Entonces, cada pieza es responsable de moverse de una casilla a otra. La clase de jugador contiene referencias a todas las piezas que posee y también es responsable de su creación (¿Debería el jugador crear piezas?). El jugador tiene un método takeTurn que a su vez llama a un método movePiece que pertenece a la clase de pieza que cambia la ubicación de la pieza de su ubicación actual a otra ubicación. Ahora estoy confundido sobre de qué debe ser responsable exactamente la clase de la Junta. Supuse que era necesario para determinar el estado actual del juego y saber cuándo termina el juego. Pero cuando una pieza lo cambia ' s ubicación ¿cómo se debe actualizar el tablero? ¿Debería mantener una matriz separada de cuadrados en los que existen piezas y que se actualiza a medida que las piezas se mueven?
Además, ChessGame crea inicialmente el tablero y los objetos del jugador que, a su vez, crean cuadrados y piezas respectivamente y comienzan la simulación. Brevemente, este podría ser el aspecto del código en ChessGame
Player p1 =new Player();
Player p2 = new Player();
Board b = new Board();
while(b.isGameOver())
{
p1.takeTurn(); // calls movePiece on the Piece object
p2.takeTurn();
}
No tengo claro cómo se actualizará el estado de la placa. ¿Debe la pieza tener una referencia al tablero? ¿Dónde debería estar la responsabilidad? ¿Quién tiene qué referencias? Ayúdenme con sus aportes y señalen problemas en este diseño. Deliberadamente no me estoy enfocando en ningún algoritmo o más detalles del juego, ya que solo estoy interesado en el aspecto del diseño. Espero que esta comunidad pueda brindar información valiosa.
takeTurn()
pagar si el movimiento de p1 termina el juego. Comentario menos quisquilloso: me parece más natural llamar a los jugadoreswhite
yblack
.canMove()
función. Y cuando se realiza el movimiento, todas las demás piezas actualizan su propia copia interna del tablero. Sé que no es óptimo, pero fue interesante en ese momento aprender C ++. Más tarde, un amigo que no era ajedrecista me dijo que tendríaclasses
para cada casilla en lugar de cada pieza. Y ese comentario me pareció muy interesante.Respuestas:
De hecho, acabo de escribir una implementación completa en C # de un tablero de ajedrez, piezas, reglas, etc. Así es como lo modelé (la implementación real se eliminó ya que no quiero quitarle toda la diversión a tu codificación):
La idea básica es que Juego / Tablero / etc. simplemente almacena el estado del juego. Puede manipularlos para, por ejemplo, establecer una posición, si eso es lo que desea. Tengo una clase que implementa mi interfaz IGameRules que es responsable de:
Separar las reglas de las clases de juego / tablero también significa que puede implementar variantes con relativa facilidad. Todos los métodos de la interfaz de reglas toman un
Game
objeto que pueden inspeccionar para determinar qué movimientos son válidos.Tenga en cuenta que no almaceno información del jugador en
Game
. Tengo una clase separadaTable
que se encarga de almacenar los metadatos del juego, como quién estaba jugando, cuándo tuvo lugar el juego, etc.EDITAR: Tenga en cuenta que el propósito de esta respuesta no es realmente brindarle un código de plantilla que pueda completar; mi código en realidad tiene un poco más de información almacenada en cada elemento, más métodos, etc. El propósito es guiarlo hacia el objetivo que estás intentando alcanzar.
fuente
Move
es una clase de modo que usted puede almacenar todo el historial de movimientos en una lista de movimientos, con la notación y la información auxiliar, como lo fue capturado pieza, lo que es un peón podría haber sido ascendido a, etc.Game
delega en un implementadorIGameRules
o se hacen cumplir reglas fuera del objeto? Esto último parece inapropiado ya que el juego no puede proteger su propio estado, ¿no?Aquí está mi idea, para un juego de ajedrez bastante básico:
fuente
Recientemente creé un programa de ajedrez en PHP ( sitio web haga clic aquí , fuente haga clic aquí ) y lo hice orientado a objetos. Aquí están las clases que utilicé.
generate_legal_moves()
código aquí. A ese método se le da un tablero, a quién le toca el turno, y algunas variables para establecer el nivel de detalle de la salida, y genera todos los movimientos legales para ese puesto. Devuelve una lista de ChessMoves.int
s.Actualmente estoy tratando de convertir este código en una IA de ajedrez, por lo que debe ser RÁPIDO.
generate_legal_moves()
Optimicé la función de 1500 ms a 8 ms y todavía estoy trabajando en ella. Las lecciones que aprendí de eso son ...int
cuando sea posible. Es por eso queChessSquare
almacena el rango y el archivo comoint
, en lugar de almacenar también un alfanuméricostring
con notación de cuadrados de ajedrez legible por humanos, como "a4".Sé que esto es viejo, pero espero que ayude a alguien. ¡Buena suerte!
fuente