web-dev-qa-db-fra.com

L'utilisation du modèle Observer est-elle une bonne idée lors de la construction d'une partie d'échecs?

J'essaie de concevoir un jeu d'échecs en utilisant des concepts OOPs qui ont un élément d'interface utilisateur. Mon idée est de montrer le nombre de carrés/cellules dans lesquels une pièce peut voyager lorsqu'elle est sélectionnée. Fondamentalement, je veux montrer les chemins/directions dans lesquels il peut voyager/attaquer dans une couleur différente.

Quelque chose comme ce qui suit

( enter image description here )

J'ai donc conçu une classe abstraite Piece, qui, entre autres, a un objet Map qui garde la trace de toutes les cellules vers lesquelles il peut se déplacer dans le sens de la direction, quelque chose comme ceci Map<Direction, LinkedList<Cell>>

Supposons maintenant qu'un morceau de la propre équipe de la Reine vienne dans sa direction d'attaque dans la direction FORWARD et se place sur la cellule qui se trouve à chessBoard[6][4]

Quelle meilleure façon puis-je notifier le Queen ou tout autre élément observant cette cellule particulière de l'événement afin que chaque élément puisse appeler sa propre méthode de mise à jour et redessiner son chemin d'attaque?

Je pensais aller avec le modèle Observer où chaque cellule sera un sujet et seules les pièces qui les regarderont seront des observateurs. Donc, dans tous les cas, quelque chose se passe dans l'une des cellules surveillées par un ensemble particulier de pièces, seules ces pièces seront notifiées.

Mais je ne sais pas si c'est une bonne approche car je dois avoir au maximum 32 auditeurs pour chaque cellule. Je ne sais pas si elle sera évolutive.

Y a-t-il de meilleures façons de le faire?

Merci d'avoir pris le temps de lire.

16
Auro

Avoir un "objet Carte qui garde une trace de toutes les cellules vers lesquelles il peut se déplacer" me semble être un exemple d'optimisation prématurée.

Au lieu de se souvenir de toutes ces cellules pour chaque morceau "juste au cas où cela pourrait devenir lent", pourquoi ne pas donner à un morceau une méthode avec la planche comme paramètre, qui retourne le List<Cell> (Ou Map<Direction, LinkedList<Cell>> Correspondant ) en le calculant lors de l'appel de la méthode? De cette façon, aucune notification ou modèle d'observateur ou "32 auditeurs" ne sont plus nécessaires. Cela peut être discutable s'il s'agit vraiment d'une méthode de la pièce ou d'une méthode de la planche. Cependant, si vous mettez cette méthode dans la planche au lieu de la pièce, les pièces n'auront rien à savoir sur la planche, ce qui évite une dépendance cyclique entre les planches et les pièces.

S'il s'avère plus tard que cette méthode est appelée assez souvent pour la même carte inchangée, elle devient donc un goulot d'étranglement des performances (ce dont je doute), vous pouvez toujours mettre ses résultats en cache en utilisant mémorisation . Cela conduirait à une solution où un Map<Direction, LinkedList<Cell>> Par pièce est requis, mais sans la nécessité d'observer activement les autres changements de planche.

43
Doc Brown

Ma suggestion est de rendre les choses aussi simples que possible. Plus vous donnez d'informations à un objet, plus il devient complexe et plus il est difficile d'en garder la trace.

Décomposons votre programme en couches. Qu'y a-t-il?

  • Les morceaux. Ils savent seulement de quel type de pièce il s'agit et de quelle couleur ils sont (noir ou blanc)
  • Le tableau. Il ne connaît que les pièces et comment elles sont organisées.
  • L'état du jeu. L'état du jeu connaît le plateau, ainsi que les informations étrangères telles que les pièces capturées.
  • L'interface utilisateur. L'interface utilisateur connaît l'état du jeu. Il connaît également toutes les informations graphiques comme les sprites.

Les pièces. Une pièce est ... juste une pièce. Il a une couleur et un type (tour, roi, reine, etc.), mais c'est tout. Il peut répondre:

  • Que suis je? (Tour, roi, reine, etc.)
  • De quel côté dois-je appartenir? (Noir blanc)

Le Conseil. Un conseil est juste un tableau 2D où les cellules ont ou non des pièces. Il peut répondre:

  • Où sont les pièces?
  • Où sont les cases vides?

De plus, en fonction de l'état actuel de la carte, nous pouvons lui demander de calculer:

  • Quels carrés peuvent être attaqués par la pièce à un endroit particulier?
  • Une pièce particulière est-elle en danger?
  • Le roi est-il en échec?
  • Un déménagement proposé est-il légal?

Exemple: Faites le pas B3 to A4.

  • S'il n'y a pas de morceau sur B3, c'est illégal.
  • Si la pièce ne peut pas se déplacer en diagonale, c'est illégal.
  • Si A4 est occupé par un morceau de la même couleur, c'est illégal.
  • Si le roi est en échec et que le mouvement ne protège pas le roi, c'est illégal. Etc.

L'état du jeu. L'état du jeu garde une trace de ce qui s'est passé jusqu'à présent dans le jeu, ainsi que l'état actuel du plateau. Ceci comprend:

  • À quoi ressemble le tableau maintenant
  • Histoire des mouvements (comme "Queen prend B4")
  • Qui a capturé quelles pièces
  • A qui le tour?

L'interface utilisateur. Tbe UI est responsable de dessiner l'état du jeu et le plateau. On peut lui demander:

  • A quoi ressemblent les choses? (Quelles images-objets ou primitives graphiques sont utilisées pour dessiner une pièce ou la planche?)
  • Où dois-je dessiner des trucs?
  • Quand dois-je dessiner des trucs?

L'interface utilisateur doit être la seule qui gère les événements. Les pièces ne gèrent pas les événements. L'état du jeu ne gère pas les événements. Le conseil d'administration ne gère pas non plus les événements. Lorsqu'un événement se produit, l'interface utilisateur:

  • Vérifie si ce qui s'est passé était légal
  • Met à jour l'état du jeu si la chose était légale
  • Dessine le tableau mis à jour (et toutes les animations de mise à jour associées)

Comment puis-je faire les choses, comme mettre en évidence les mouvements possibles? Lorsqu'un utilisateur survole le tableau, l'interface utilisateur

  • Détermine de quel carré il s'agit
  • Obtient le tableau de l'état de jeu
  • Demande au plateau quelles cases peuvent être attaquées par cette pièce.

Cette dernière question peut être mise en œuvre sous la forme d'une fonction membre du conseil d'administration qui prend une position en entrée et renvoie une liste (ou un tableau) de positions qui peuvent être légalement attaquées.

Pourquoi utiliser cette approche? Chaque champ, chaque propriété, chaque membre que vous ajoutez à la classe ajoute l'état . Chaque bit d'état est quelque chose que vous devez gérer, suivre et mettre à jour si nécessaire. Le code devient un gâchis, et faire des changements est difficile car un petit changement vous oblige soudainement à modifier une douzaine de classes différentes.

Calculer une liste de mouvements légaux sur la base d'un tableau 2D de pièces est beaucoup moins cher que de mettre à jour en permanence un Map<Direction, LinkedList<Cell>> pour chaque pièce. Ce sera aussi moins de code.

En divisant le programme en couches et en confiant à chaque couche une responsabilité unique - contrôler la couche en dessous - nous pouvons écrire un programme propre, efficace et modulaire.

22
J. Antonio Perez

Les autres réponses ont déjà répondu comment vous pouviez faire ce que vous aviez demandé. Je veux seulement souligner ici que ni OOP ni les modèles de conception (oui, ce sont des choses très différentes) ne doivent être utilisés uniquement pour les utiliser.

Ce sont des outils et, en tant que tels, ils doivent être choisis en fonction de l'objectif que vous souhaitez atteindre, et non l'inverse.

Je ne peux pas comprendre de votre question si vous avez besoin de faire un programme d'échecs et que vous avez choisi de le faire avec OOP, ou si vous voulez apprendre OOP puis choisissez Chess comme conduit d'apprentissage) il.

Si c'est le dernier, comme je le soupçonne, ma suggestion est que vous commenciez par une barre inférieure, cependant.

Les jeux de société sont aussi une bonne façon d'apprendre OOP comme beaucoup d'autres, et mieux que la plupart que j'ai vu être utilisé. Cependant, je vous suggère de jouer avec un jeu plus simple, par exemple tic- tac-toe, puis remontez l'échelle de complexité (peut-être les dames, le dragueur de mines, le backgammon, etc.) jusqu'à ce que vous atteigniez les échecs et des jeux encore plus complexes.

Si votre objectif est d'apprendre la POO, l'approche que je suggère vous amènerait à apprendre beaucoup plus de concepts et de pratiques que simplement comment faire des échecs sur la POO.

3