2010-10-25 12 views
6

Digamos que estoy implementando mi propia versión de Scrabble. Actualmente tengo una clase Board que contiene muchos Squares. A Square a su vez se compone de IBonus y Piece. Las implementaciones de bonificación son en realidad la bonificación habitual para Scrabble, pero es posible que intente agregar una bonificación nueva y retorcida para darle más sabor al juego. ¡La flexibilidad aquí es primordial!Diseñando un sistema de bonificación flexible y extensible para la implementación de un juego de Scrabble

alt text

Después de pensar un rato llegué a la conclusión de que para IBonus implementaciones para trabajar, que van a necesitar saber toda la Board y también su posición actual (en la Board, por lo que sabe dónde es y puede verificar la pieza que está en el mismo cuadrado que el bono). Esto me parece tan malo como básicamente, necesita saber mucha información.

lo tanto, mi aplicación ingenua sería pasar el Board como argumento para IBonus.calculate() método, IBonus.calculate(Board board, Point position), es decir.

Además, parece crear una referencia circular. ¿O estoy equivocado? alt text

No me gusta particularmente este enfoque, entonces estoy buscando otros enfoques posibles. Sé que puedo hacer que calculate acepte una interfaz en lugar de una clase concreta, es decir, calculate(IBoard board) pero I IMO no es tan mejor que el primer caso.

Me temo estar demasiado concentrado en mi implementación actual como para poder pensar en diseños completamente diferentes que podrían encajar al menos tan bien como soluciones a este problema. Tal vez podría volver a diseñar todo el juego y tener las bonificaciones en otro lugar, por lo que facilitaría este cálculo? Tal vez estoy demasiado centrado en tenerlos en el Board? ¡Ciertamente espero que haya otros enfoques para este problema!

Gracias

+1

+1 para buenos diagramas –

+0

¿Qué herramienta usaste para crear los diagramas? –

+0

yUML, te permite crearlos y alojarlos en línea. –

Respuesta

4

Asumo Junta tiene el estado de visibilidad del juego, y no habría otros objetos tales como rack (una por jugador), y una DrawPile.

"Puntuación doble si la palabra contiene una Z real (no en blanco)" - requeriría que pase la palabra, o la pizarra y la posición de la palabra.

"Puntuación doble si la palabra es la más larga en el tablero" requiere la Junta entera.

"Puntuación doble si la primera letra de la palabra coincide con una letra seleccionada al azar del DrawPile" requiere el DrawPile por supuesto.

Así que para mí solo depende de las reglas que implemente. Me sentiría cómodo con pasar Board a la implementación de puntuación de IBonus().

editar - más pensamientos.

Por lo tanto, un tablero tiene 17x17 cuadrados, o lo que sea. Asignaría una implementación de IBonus a cada cuadro del tablero (habría una implementación llamada PlainEmptySquare que era inerte). Solo necesitarías crear instancias de cada implementación de IBonus una vez, se podría hacer referencia a ella muchas veces. Probablemente tomaría el camino más bajo e instanciaría cada uno explícitamente, pasando los argumentos necesarios. Si un tipo necesita el tablero, páselo. Si otro necesita el DrawPile, pásalo.En su implementación, tendría quizás 12 líneas de fealdad./Encogerse

+0

Estoy de acuerdo; Si desea la mayor flexibilidad para diseñar bonificaciones locas, necesita la mayor cantidad de información disponible. –

1

algo como lo siguiente podría funcionar:

CurrentGame tiene un Board, que tiene una colección de Squares. Un Square podría tener un IBonus, sin embargo no hay un método Calculate() en un Square. Un Square puede tener un Piece, y un Piece puede tener un Square (es decir, un cuadrado puede estar o no estar vacío, y una pieza puede o no haberse colocado en el tablero).

Board también tiene un método calculateScoreForTurn() que aceptaría una colección de Pieces que representa las piezas que se acaban de colocar en el tablero para ese turno. Board conoce toda la información sobre las piezas y cuadrados que acaban de colocarse, así como las piezas y cuadrados circundantes o que se cruzan (si corresponde) y, por lo tanto, tiene toda la información necesaria para calcular el puntaje.

+0

Pero, ¿cómo manejas diferentes tipos de bonificaciones, entonces? ¿No debería encapsularse la lógica de cada tipo de bonificación diferente en una clase diferente? –

+1

Probablemente no sea ideal desde el punto de vista del diseño OO, pero a mí me parece mejor que exista una "lógica de reglas" en un solo lugar que tener un objeto IBonus (que concierne a un solo mosaico) realizar un trabajo que concierne al conjunto Tablero. Tal vez podría tener un objeto marcador separado, por lo que le pasa el tablero y una colección de piezas recién colocadas, y devuelve el puntaje para ese turno. Parece apropiado que un Anotador conozca todas las reglas. – jwaddell

+1

Creo que el hecho de que un IBonus particular pueda afectar algo más que la pieza en particular a la que está asociado (incluidas las piezas colocadas en turnos anteriores) significa que no debe encapsular su método de puntuación en su casilla. – jwaddell

1

Esto me parece tan malo como básicamente se necesita saber un montón de información

creo que es necesario. Solo está pasando una referencia al tablero, no causando grandes cantidades de datos moviéndose.

1

La Junta en sí probablemente tendrá que conducir la puntuación para una ronda determinada. A medida que se coloca cada Azulejo, la Junta lo toma nota. Cuando se haya colocado el último Azulejo (para un turno), el Tablero debe obtener todos los Cuadrados que tienen un recuadro recién agregado (se calculará el Bonus para estos Cuadrados) Y todos los Azulejos colocados previamente que el turno actual es " reutilizando ".

Por ejemplo, jugar al gato

C A T

C cae en letra doble puntuación. Entonces, el puntaje para el turno es C.Value * 2 + A.Value + T.Value.

El siguiente jugador coloca una S para hacer CATS. S cae en Triple Word Score. Entonces, el puntaje para el turno es (C.Value + A.Value + T.Value + S.Value) * 3. Cuando se aplica una bonificación de azulejo, debe estar "desactivada" para que las "reutilizaciones" futuras de esa loseta no reciban la bonificación.

La consecuencia es que algunos Bonos aplican el Mosaico colocado en el Cuadrado mientras que otros se aplican a la colección de Mosaicos que componen el nuevo Word DESPUÉS de que se hayan calculado los Bonos para las letras individuales.

Dado uno o más cuadrados que se han llenado con mosaico (s) durante un turno, la Junta puede encontrar el comienzo de la (s) palabra (s) que se han creado al atravesar la izquierda hasta el borde del tablero (o hasta un cuadrado vacío) y atravesando hasta la misma condición. La Junta puede encontrar el final de la (s) palabra (s) que se han creado al atravesar de manera similar a la derecha y hacia abajo. También debe pasar al principio y al final de las palabras cada vez que un mosaico recién colocado esté adyacente a un mosaico existente (podría crear muchas palabras durante un turno).

Dada una colección de Palabras (cada una compuesta por un Cuadrado que contiene un posible LetterBonus y un Azulejo con un Valor), el Tablero (o cada Palabra) calcula el Valor Base (Suma de Valores - aplicando cualquier LetterBonuses) y luego aplica WordBonus (si hay alguno) para obtener el máximo valor de la Palabra.

Cuestiones relacionadas