Thank you for pointing it out so politely. ;) I'm from Greece, so
Hmmm.. Good idea! I'll do that! So by now I have two types of
interfaces: PermissibilityHouseRule and ActionHouseRule. Stupid
Nope. Never heard of! Nice to know though! Thanks for sharing. ;)
The second kind of rule, i would reify, since there are quite a few of
them.
But, in order for this to work, I found two problems: A) the class that
implements the Rule has to have a lot of information (the list of cards,
if it is already closed etc.). How do I work around this? Should the
method of the interface have a list of the needed information in
parameters? Should the class pass itself in all rules and provide
getters for all attributes?
That's what i'd do:
public interface Rule {
public int apply(House house) ;
}
Specifically, i wouldn't have rules apply to cards, but to houses. When
you add a card, you're not going to each rule and asking it what it thinks
of that card, you're really saying "here's the state of the house - is
there anything you want to do?". A rule could then use getters on the
House to examine it, and mutators to make any changes; it would return the
number of points awarded. House then looks like:
public class House {
public static final int MAX_POINTS = 31 ;
private Set<Card> cards ;
private List<Rule> rules ; // shared with other houses
private Suit suit ;
private int points ;
public int addCard(Card card) throws CardException {
if (points > MAX_POINTS) throw new HouseClosedException(this) ;
if (suit != null)
if (card.suit() != suit) throw new WrongSuitException(card, this) ;
else suit = card.suit() ;
cards.add(card) ;
points += card.points() ;
int score = 0 ;
for (Rule rule : rules)
score += rule.apply(this) ;
return score ;
}
public int getPoints() {
return points ;
}
public int numCards() {
return cards.size() ;
}
public Suit getSuit() {
return suit ;
}
public boolean hasCard(Card card) {
return cards.contains(card) ;
}
public void empty() {
cards.clear() ;
suit = null ;
points = 0 ;
}
}
And the rules:
public class ThirtyOnePointRule implements Rule {
public int apply(House house) {
if (house.getPoints() == House.MAX_POINTS) {
house.empty() ;
return 20 ;
}
return 0 ;
}
}
public class SixCardRule implements Rule {
public int apply(House house) {
if (house.numCards() == 6) {
house.empty() ;
return 50 ;
}
return 0 ;
}
}
public class JokerRule implements Rule {
public int apply(House house) {
if (house.hasCard(house.getSuit().JOKER)) {
house.empty() ;
return 50 ;
}
return 0 ;
}
}
I leave Card and Suit to your imagination. They aren't complicated.
B) because different rules have different reactions, I also create a
Listener for that class. Every time something important happens, the
registered listeners get informed. But I have no idea how the class that
implements the Rule can inform the other class to fire an event to the
registered listeners.
I'm not sure that a listener mechanism is the right way to do this. Who
are the listeners? Is it just the GUI? Can rules trigger other rules?
If there's only one listener, then a listener mechanism is probably
overkill. Instead, if you need to present a list of which rules have
applied, i'd modify House.addCard so that it builds up a List<Rule> of
rules which were applied, and returns those to the caller, which will be
the GUI.
In fact, i'd refactor my above design. I'd add a method int score() to
Rule, which gives the number of points that rule is worth, and a String
name(), which gives the rule's description (eg "house reached 31 points").
I'd modify Rule.apply to return a boolean, simply indicating whether that
rule applies. In House.addCard, rather than adding up a score, i'd just
build a List<Rule> of rules which applied (ie returned true from
Rule.apply), and return that instead of a score. In the GUI, or some kind
of controller object, i'd then iterate over the list of rules, printing
out the rule's description and score, and totalling up the score as it
went. This not only separates presentation from game logic, but card
movement from scoring logic!
b) each house is of a particular suite. If a joker of the same suite
(the jokers have suites in this game) is added, any card in the house
are erased and the player wins 50 points in his total score. But if it
doesn't the game is over.
If it doesn't what?
Now, the rule with the six cards fires an event to the listeners that
the rule was satisfied. One of the listeners is the GUI and it reacts
by displaying information. The same thing goes for the 31 points rule
and any rule that others need to know about.
These are events that are fired and listeners react to. But these also
are the rules for the house.
So everything comes down to design decision. Because the rules vary,
and could be expanded, they need to be outside of the House. And
because the events depend on the rules, there has to be a bridge
between them.
I think you should closely examine the idea that you need an event
mechanism. If you can remove that, you remove a lot of complexity.
tom
--
see im down wid yo sci fi crew
This whole implementation sounds like a great and easy idea. But I
have one question. What if an ActionHouseRule ends the game? Like in
If a Joker of Spades is enter in a House of Hearts, the game is over.
the house are emptied and the player gains points.
over. So how do I implement the game over?