2010-10-25 18 views
6

Supposons que j'implémente ma propre version de Scrabble. J'ai actuellement une classe Board qui contient beaucoup de Squares. Un Square à son tour est composé d'un IBonus et un Piece. Les mises en œuvre de bonus sont en fait le bonus habituel pour Scrabble, mais il est possible que j'essaie d'ajouter un bonus nouveau et tordu pour pimenter le jeu - la flexibilité est ici primordiale!Conception d'un système de bonus flexible et extensible pour la mise en œuvre d'un jeu de Scrabble

alt text

Après avoir réfléchi pendant un certain temps je suis venu à la conclusion que pour IBonus mises en œuvre au travail, ils ont besoin de savoir l'ensemble Board et aussi sa position actuelle (sur la Board, il sait où il est et il peut vérifier la pièce qui est dans le même carré que le bonus est). Cela me semble aussi mauvais que fondamentalement il a besoin de connaître beaucoup d'informations. Donc, mon implémentation naïve serait de passer le Board comme argument à la méthode IBonus.calculate(), IBonus.calculate(Board board, Point position), c'est-à-dire.

En outre, il semble créer une référence circulaire. Ou ai-je tort? Je n'ai pas particulièrement aimé cette approche, donc je suis à la recherche d'autres approches possibles. Je sais que je peux faire calculate accepter une interface au lieu d'une classe concrète, c'est-à-dire, calculate(IBoard board) mais je ne suis pas tout à fait mieux que le premier cas. Je crains d'être trop concentré sur ma mise en œuvre actuelle pour être capable de penser à des conceptions totalement différentes qui pourraient s'adapter au moins aussi bien que des solutions à ce problème. Peut-être que je pourrais réorganiser l'ensemble du jeu et avoir les bonus à l'autre endroit, donc cela faciliterait ce calcul? Peut-être que je suis trop concentré sur les avoir sur le Board? J'espère certainement qu'il existe d'autres approches à ce problème là-bas!

Merci

+1

+1 pour les bons diagrammes –

+0

Quel outil avez-vous utilisé pour créer les diagrammes? –

+0

yUML, il vous permet de les créer et de les héberger en ligne. –

Répondre

4

Je suppose Conseil a l'état visible du jeu, et il y aurait d'autres objets tels que rack (un par joueur), et un DrawPile. "Double score si le mot contient un réel Z (non vide)" - vous devrez passer dans le mot, ou le tableau et la position du mot.

"Le double score si le mot est le plus long sur le tableau" nécessite l'ensemble du tableau. "Double score si la première lettre du mot correspond à une lettre sélectionnée au hasard à partir du DrawPile" nécessite le DrawPile bien sûr.

Donc, pour moi, cela dépend des règles que vous implémentez. Je serais à l'aise de passer le Board à l'implémentation IBonus score().

éditer - plus de pensées.

Donc une carte a des carrés de 17x17, ou peu importe. J'attribuerais une implémentation IBonus à chaque carré du tableau (il y aurait une implémentation appelée PlainEmptySquare inerte). Il suffirait d'instancier chaque implémentation de IBonus une seule fois - cela pourrait être référencé plusieurs fois. Je prendrais probablement le chemin bas et instancierais chacun explicitement, passant dans les arguments nécessaires. Si un type a besoin de la carte, transmettez-la. Si une autre personne a besoin de DrawPile, transmettez-la.Dans votre mise en œuvre, vous auriez peut-être 12 lignes de laideur./Hausser les épaules

+0

Je suis d'accord; Si vous voulez le plus de flexibilité pour concevoir des bonus fous, vous avez besoin de la plupart des informations disponibles. –

1

Quelque chose comme ce qui suit pourrait fonctionner:

CurrentGame a une Board, qui a une collection de Squares. Un Square peut avoir un IBonus, mais il n'y a pas de méthode Calculate() sur un Square. Un Square peut avoir un Piece, et un Piece peut avoir un Square (c'est-à-dire qu'un carré peut être ou ne pas être vide, et qu'une pièce peut ou non avoir été placée sur le plateau).

Board a également une méthode calculateScoreForTurn() qui accepterait une collection de Pieces représentant les pièces qui viennent d'être placées sur le plateau pour ce tour. Board connaît toutes les informations sur les pièces et les carrés qui viennent d'être placés, ainsi que sur les pièces et carrés environnants ou entrecroisés (le cas échéant) et dispose ainsi de toutes les informations nécessaires pour calculer le score.

+0

Mais comment gérez-vous différents types de bonus, alors? La logique de chaque type de bonus différent ne devrait-elle pas être encapsulée dans une classe différente? –

+1

Ce n'est probablement pas idéal du point de vue de la conception OO, mais pour moi, il semble préférable que toute la "logique des règles" existe en un seul endroit plutôt qu'un objet IBonus (qui concerne une seule tuile). Planche. Vous pourriez peut-être avoir un objet Scorer séparé, ainsi vous passerez le Board et une collection de Pieces juste placés, et il retournera le score pour ce tour. Il semble approprié qu'un marqueur connaisse toutes les règles. – jwaddell

+1

Je pense que le fait qu'un IBonus particulier puisse affecter plus que le morceau particulier auquel il est associé (y compris les morceaux placés lors de tours précédents) signifie que vous ne devriez pas encapsuler sa méthode de notation dans son carré. – jwaddell

1

Cela me frappe aussi mauvais que, fondamentalement, il a besoin de savoir beaucoup de informations

Je pense qu'il est nécessaire. Vous venez de passer une référence au tableau, sans réellement déplacer de grandes quantités de données.

1

Le conseil lui-même devra probablement conduire le pointage pour un tour donné. Au fur et à mesure que chaque tuile est placée, le conseil en prend note. Quand la dernière tuile (pour un tour) a été placée, le conseil doit obtenir tous les carrés qui ont une nouvelle tuile (le bonus pour ces carrés sera calculé) ET tous les tuiles précédemment placées que le tour en cours est " réutilisation ".

Par exemple, jouer CAT

C A T

C tombe sur le score double lettre. Donc, le score pour le tour est C.Value * 2 + A.Value + T.Value.

Le joueur suivant place un S pour faire CATS. S tombe sur Triple Word Score. Ainsi, le score pour le tour est (C.Value + A.Value + T.Value + S.Value) * 3. Quand un Bonus de Tuile a été appliqué, il doit être "Désactivé" pour que les futures "réutilisations" de ce Tile n'obtiennent pas aussi le Bonus.

L'implication est que certains bonus appliquent le carreau placé dans le carré tandis que d'autres s'appliquent à la collection de carreaux qui composent le nouveau mot APRÈS avoir calculé les bonus pour les lettres individuelles.

Étant donné un ou plusieurs carrés qui ont été remplis de carreaux pendant un tour, le tableau peut trouver le début du ou des mots qui ont été créés en traversant à gauche jusqu'au bord de la planche (ou jusqu'à un carré vide) et traverser jusqu'à la même condition. Le Conseil peut trouver la fin du ou des mots qui ont été créés en parcourant de la même manière le droit et le bas. Vous devez également parcourir le début et la fin des mots à chaque fois qu'un carreau nouvellement placé est adjacent à un carreau existant (vous pouvez créer plusieurs mots pendant un tour). Étant donné une collection de mots (chacun composé d'un carré contenant un LetterBonus possible et une mosaïque avec une valeur), le conseil (ou chaque mot lui-même) calcule le BaseValue (Somme des valeurs de carreaux - en appliquant LetterBonuses) et puis applique le WordBonus (le cas échéant) pour obtenir la valeur ultime de la Parole.