Design decision for a game

P

pek

I am currently developing the House Of Cards card game (I can't seem
to find any relative info on the internet), but it doesn't really
matter. My problem is a design problem.

Say you have a class that holds a set of cards. When a card is added
it has to obey certain rules. For example, if it is full and no other
cards can be added, an exception should be thrown. If the card is not
the correct suite, again, an exception should be thrown etc.

Now, depending on the options of the game, some rules apply and some
don't. So clearly, the rules aren't inside the class itself, but they
are added by the engine using an addRule method. So I thought that I
could create an interface called Rule with a method called addCard.
The class holds a list of rules and every time a card is added it
calls them in the added order.

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?

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.

Just in case I'm not clear at all, let me explain a little more.

The class I am talking about is called House. This holds a set of
cards. A card has points depending on it's suite. The house can hold
up to 31 points. When a card is added and the sum of the points are
EXACTLY 31, the player wins 20 points in his total score and the house
empties so cards can be added once again. If the sum of points exceed
31, the house closes and no more cards can be added. The game has four
houses.

Those are the standard rules. Additionally:
a) if a house has a total of six cards (not so common), the player
wins 50 points in his total score and the house empties.
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.

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.

Any suggestions?

Thank you very much in advance.

Regards,
P. Peikidis
 
S

Stefan Ram

pek said:
A) the class that implements the Rule has to have a lot of information

(I have not understood read all details.)

A class should have high cohesion, which usually means that
it have to be small. It should not have dozens of fields when
these can be seperated into sets of related fields that can
be factored out to seperate classes.

But sometimes there is an exception to the rule of small classes.

When there are dozens of fields and they all form one big lump,
sometimes a large class is appropriate.

If you see this and you seen no obvious meands to split the
class then implement it as one large class.

In the course of developement sometimes later, an idea will
pop up how to split this large class that was not visible
at the start of the design.

Let me add a story about how you sometimes encounter paths
in the course of action you did not see initially:

»What often happens to me when climbing is that I look as
hard as I can for a hold to move my hand up to and I see
nothing. Nothing I can easily reach, nothing I can nearly
reach and not even anything I might reach if I was just a
bit taller or if I jumped. I feel utterly stuck and begin
to contemplate the immanent defeat of falling off.

But then I remember to look for new footholds.

Sometimes I've already had a go at this and haven't seen
anything promising, but in desperation I move one foot to
a new hold, perhaps one that is only an inch or so further
up the wall. And this is when something magical happens.
Although I am now only able to reach an inch further, I
can suddenly see a new hold for my hand, something I'm
able to grip firmly and use to pull myself to freedom and
triumph (or at least somewhere higher up to get stuck).
Even though I looked with all my desperation at the wall
above me, this hold remained completely invisible until I
moved my foot an inch --- what a difference that inch
made.«

http://www.mindhacks.com/blog/2008/03/rock_climbing_hacks.html

So, you might be able to see how you can split the class later.

You do not see this way now. BUt you might see it later.

Then, you can split the class by a refactoring.

Finding the natural positions for a split sometimes needs
experience:

»Life is limited, but knowledge is unlimited. To drive the
limited to the unlimited without stop is impossible. In
doing good, avoid fame. In doing bad, avoid disgrace.
Pursuing a middle course is a reasonable choice.

Prince Huai's cook was cutting up a bullock. Every blow of
his hand, every heave of his shoulders, every tread of his
foot, every thrust of his knee, all were in perfect
rhythm, like the harmonious music intended for the Emperor.

"Well done!" cried the Prince. "Your skill has advanced to
such an extent!"

"Sir", replied the cook laying down his chopper. "I have
always devoted to Tao which is higher than mere skill.
When I first began to cut up bullocks, I saw before me
whole bullocks. After three years of practice, I saw no
more whole animals. And now I work with my mind, not with
my eyes. I glide through joints and cavities in the
natural constitution of the animal. I do not even touch
the convolution of muscles or tendon, and never attempt to
cut through large bones.

A good cook changes the chopper once a year because he
cuts. An ordinary cook once a month because he hacks. But
I have had this chopper for 19 years. Although I have cut
thousands of bullocks, its edge is still like new. For at
the joints there are always intestines, and insert a blade
without thickness into the intestine leaves plenty of room
for the blade to move about.

Nevertheless, when I come upon a knotty part which is
difficult to tackle, I am all caution. Fixing my eyes on
it, I stay my hand and gently apply my blade, until the
part yields like earth crumbling to the ground. Then I
take out my chopper and stand up, look around, and pause
with an air of triumph. Then wiping my chopper, I put it
carefully away."

"Bravo!" cried the Prince. "From the words of this cook I
have now learned how to take care of my life."«

http://www.networkchinese.com/others/note_sub6.html
 
T

Tom Anderson

Say you have a class that holds a set of cards. When a card is added it
has to obey certain rules. For example, if it is full and no other cards
can be added, an exception should be thrown. If the card is not the
correct suite, again, an exception should be thrown etc.

Tiny comment: the word is 'suit', like a set of clothes, not 'suite'. I'm
guessing english is not your first language - although this is the only
error i noticed in your post!
Now, depending on the options of the game, some rules apply and some
don't. So clearly, the rules aren't inside the class itself, but they
are added by the engine using an addRule method. So I thought that I
could create an interface called Rule with a method called addCard. The
class holds a list of rules and every time a card is added it calls them
in the added order.

Okay. Firstly, you have two different kinds of rules here. The first kind
is a permissibility rule: it says whether a card can be added to a house
or not. The second kind is an action rule: it says that when a certain
situation comes to pass, something should happen.

I wouldn't try and handle both kinds of rule within one framework myself.
I'd deal with permissibility and action rules separately.

If your only permissibility rules are about matching suit and not
exceeding 31 points, i don't think i'd reify these. I'd just write two
guard clauses at the top of House.addCard to check for those conditions
and throw an exception if they apply. If there are further permissibility
rules, or if they can change (say between variants of the game), i'd
reify.

(Incidentally, are people familiar with the term 'reify'? It's an old OO
term, but one that seems not to be used much these days - it simply means
to make something into an object.)

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
 
P

pek

I don't know about the "clearly" part...no doubt someone could come up
with a design in which the card container (the "House") actually knows all
the rules and handles them accordingly. :)
Yeap, you're right. Someone could actually hard code the Rules in the
House class. But personally I try to abstract things as much as
possible. And detaching the rules is "clearly" a step of
scalability. ;)
I think you're on the right track, but instead of the Rule interface
having a specific method to be called, I think you could abstract further
by having your Rule interface implementation implement a listener
interface, and add itself as a listener to the container class to be
notified of changes to the container state.

You could do it the other way, but if you're going to go for the
listener-driven API, why not go whole-hog? :)


It seems to me that the rule interface should _be_ a listener for the
container's listener interface, and provide a listener interface for
monitoring changes in the rule-centric state of the game.

Then, you'd create the container, create one or more rules that are added
to the container as listeners, and then attach your GUI to the rules as
listeners, and optionally also to the container (if you want to present to
the user container state as well as rule state...which seems like a
natural thing to do).

The container's listener interface could as simple as "hey, the container
state changed" and then let the listeners query the container for its
current state. Alternatively, the listener interface could report exactly
what change happened. If you want to get really fancy, you could have the
listener interface manage things like thresholds for certain state
changes. For example, the container could have an "add listener" method
that also takes a point threshold so that the listener is only notified
when the points in the container meet the threshold requirement.

The container would provide methods for managing its state, such as adding
a card, emptying the container, closing the container, etc. Rule
implementations would use these methods to manage their own reactions to
the events that occur. Of course, you need some mechanism for dealing
with conflicts between rule implementations; it's not clear from your post
how this would be dealt with, though you seem to imply that you could have
multiple rule implementations attached at any given moment.

OK.. I think I understand some things here. I won't be fancy, so
threshold is a little overkill (although I did like the idea). What I
see problematic here is this:
class House {
...
public void addCard(Card card) {
// do some things, or probably nothing because the rules would
take care of it
...
// inform listeners
for (HouseListener lstnr : listeners) {
lstnr.cardAdded(this, card);
}
}
...
}
class SixCardsRule implements HouseListener {
...
public void cardAdded(House house, Card card) {
if ( house.getCards().size() == 5 ) {
// then adding this card satisfies this Rule. So,
house.setCards(new ArrayList<Card>());
// Now notify everyone. The 50 is for the score to be added
for (RuleListener lstnrs : listeners) {
lstnrs.ruleSatisfied("Six cards in total",50);
}
}
}
...
}

Does this look OK? Because I think it does, although I think that
adding the score to the RuleListener is a little odd. What if nobody
is listening and the score isn't added anywhere? What if the rule,
although satisfied, has nothing to do with scoring?
:S
Am I complicating things more than they should be or is it my idea?
It seems to me that the rule implementation simply manages the container
state as appropriate, and the container provides the appropriate listener
interface so that listeners can be notified of changes to the container.
The classes that implement the rule interface don't so much "inform" the
container to "fire an event" as they simply do what they need to do to the
container, and the container itself recognizes the specific changes in
state that require notification to listeners added to the container.




What happens if the sixth card brings the total to exactly 31? How do you
decide which rule implementation deals with the points? Or does the
player get 70 points total in that case? (In which case there wouldn't be
a conflict).

Great question! I have no idea! :S What do you suggest? I also find it
easier to simply add 70 points, but finding a way to prioritize the
rules sounds more challenging. Any suggestions?
What's the difference between "any card in the house are erased" and "the
house empties"?
Sorry for my english. It is the exact same thing. The list of cards in
a house is simply emptied in both cases.
How does the game end other than adding a joker of the
wrong suit to a house?
The game starts with a standard 52 card deck and 4 jokers. So it also
ends when there are no other cards to deal.
Is it possible for this other game-ending
condition to occur at the same time a joker of the correct suit is added
to a house?
And similar to above, what happens if a joker rule is
satisfied at the same time as another (adding up to 31 points, reaching
six cards)?
The joker never stays in a house. Either the game is over or the house
is cleared and no cards are left (adding 50 to the score).

Great questions by the way! Very good feedback! That's more than I
expected! Thank you for this too ;)
It seems to me that you need a way of managing multiple controllers of the
house container class, to impose some structure on the precedence of
operations and of rules. Once you do that, then the "rules for the house"
are really just operations that the rule implementations perform based on
events raised by the container. That'd then be your bridge right there.

Pete

So what do you think about the code I posted previously with the
Listeners? Am I doing it OK?

Thank you very much for your help!
 
P

pek

Tiny comment: the word is 'suit', like a set of clothes, not 'suite'. I'm
guessing english is not your first language - although this is the only
error i noticed in your post!
Thank you for pointing it out so politely. ;) I'm from Greece, so
indeed, my first language isn't English.
Okay. Firstly, you have two different kinds of rules here. The first kind
is a permissibility rule: it says whether a card can be added to a house
or not. The second kind is an action rule: it says that when a certain
situation comes to pass, something should happen.

I wouldn't try and handle both kinds of rule within one framework myself.
I'd deal with permissibility and action rules separately.
Hmmm.. Good idea! I'll do that! So by now I have two types of
interfaces: PermissibilityHouseRule and ActionHouseRule. Stupid
question: Are they any way inherited by a HouseRule interface?
Although I can't find any reason why, I feel it could be.
If your only permissibility rules are about matching suit and not
exceeding 31 points, i don't think i'd reify these. I'd just write two
guard clauses at the top of House.addCard to check for those conditions
and throw an exception if they apply. If there are further permissibility
rules, or if they can change (say between variants of the game), i'd
reify.

I'm probably gonna add more and more permissibility rules, so I'll
reify.
(Incidentally, are people familiar with the term 'reify'? It's an old OO
term, but one that seems not to be used much these days - it simply means
to make something into an object.)
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.


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.


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!


If it doesn't what?




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

This whole implementation sounds like a great and easy idea. But I
have one question. What if an ActionHouseRule ends the game? Like in
the case of the Joker:
If a Joker of Spades is enter in a House of Hearts, the game is over.
If a Joker of Spades is added to a House of Spades, then the cards in
the house are emptied and the player gains points.
This isn't a permissibility rule, and there is case where the game is
over. So how do I implement the game over?

Thank you for your time.
 
T

Tom Anderson

Thank you for pointing it out so politely. ;) I'm from Greece, so
indeed, my first language isn't English.

Aha. I thought someone whose english was as good as yours would appreciate
an opportunity to improve it even further, even if only in a small way!
Hmmm.. Good idea! I'll do that! So by now I have two types of
interfaces: PermissibilityHouseRule and ActionHouseRule. Stupid
question: Are they any way inherited by a HouseRule interface? Although
I can't find any reason why, I feel it could be.

Trust your feelings! It doesn't do any harm to inherit them from a common
interface, and it helps to document the code.

Also, both kinds of rules will need a getName() or getDescription()
method, so you can declare that in the root interface.
Nope. Never heard of! Nice to know though! Thanks for sharing. ;)

No problem. I'm sorry it's from a latin root, and not greek!
This whole implementation sounds like a great and easy idea. But I
have one question. What if an ActionHouseRule ends the game? Like in
the case of the Joker:
If a Joker of Spades is enter in a House of Hearts, the game is over.
If a Joker of Spades is added to a House of Spades, then the cards in
the house are emptied and the player gains points.
This isn't a permissibility rule, and there is case where the game is
over. So how do I implement the game over?

I'd add a method to the ActionRule interface through which a rule can
indicate it ends the game. This is after applying the refactoring i
mention, so the interface looks like:

interface ActionRule extends Rule {
public String description() ;
public boolean endsGame() ;
public int score() ;
public boolean applies(House h) ;
}

With the addCard looking like:

public List<Rule> addCard(Card card) {
// do permissibility checks here - i omit them
List<ActionRule> applied = new ArrayList<ActionRule> ;
for (Rule rule: rules) {
if (rule.apply(this)) applied.add(rule) ;
}
return applied ;
}

And the game controller having code like:

List<Rule> applied = house.addCard(card) ;
for (Rule rule : applied) {
if (rule.endsGame()) {
tellUser("GAME OVER: " + rule.description() + "!") ;
gameOver = true ;
}
else
tellUser("rule applied: " + rule.description() + "; scored " + rule.score()) ;
score += rule.score() ;
}
tellUser("total score: " + score) ;
}

But if there's a permissibility rule that says you can't put a card in a
house whose suit doesn't match, how can you get to the situation where you
put a joker of spades in a house of hearts?

tom
 
T

Tom Anderson

I think ultimately I'd go with _some_ variation on this last approach
(that is, the one where the Rule supports listeners for events separated
into appropriate categories, whether in the same interface or in two or
more), but any of the above would probably work (including what you
posted, if you really want to do it that way).

I'm thinking having a list of listeners on each Rule is overkill - are
there ever cases where you'd want to listen to one Rule but not others?
How about putting the listeners on the House, and having the rule call a
method on the House which gets it to dispatch the event? You might even
want the listeners to be on the Game object.

tom
 
P

pek

[...]
OK.. I think I understand some things here. I won't be fancy, so
threshold is a little overkill (although I did like the idea). What I
see problematic here is this:
class House {
...
public void addCard(Card card) {
// do some things, or probably nothing because the rules would
take care of it
...
// inform listeners
for (HouseListener lstnr : listeners) {
lstnr.cardAdded(this, card);
}
}
...
}

That part seems fine, as far as it goes.
class SixCardsRule implements HouseListener {
...
public void cardAdded(House house, Card card) {
if ( house.getCards().size() == 5 ) {
// then adding this card satisfies this Rule. So,
house.setCards(new ArrayList<Card>());
// Now notify everyone. The 50 is for the score to be added
for (RuleListener lstnrs : listeners) {
lstnrs.ruleSatisfied("Six cards in total",50);
}
}
}
...
}

This part I'm not so sure of.

Without seeing your whole architecture, it's hard to say for sure. But it
seems to me that someone other than the Rule should be maintaining the
score. I'm not sure if this is the House, or if you have some other class
that's the entire Game. But it seems to me that the Rule should not
necessarily be raising score-change events itself, but rather should be
calling some method somewhere that adds 50 points to the score. Objects
that need to be notified of score changes would be attached as a listener
to _that_ object.
Correct, I forgot to mention that indeed I do have a different class
that handles the game logic called Engine. It contains an int for the
game's score.
Now, if you _also_ want to provide for notification of when a specific
rule is satisfied, your Rules could allow those listeners to be added.
And they would be notified much as you show above. Except that the score
would not necessarily be part of the method parameters, at least not in my
view.

Alternatively, if you _do_ want the Rule notifications to include the
score, then either _all_ rule-satisfying conditions should affect the
score, or you need to expand your RuleListener interface so that there are
different methods, some of which include a point total to be added to the
score, and others that don't. Or perhaps you provide just one method in
the interface that is the "score changed" notification", and that's sent
separately from other notifications, like "rule satisfied".

Any of these could work. Which is "best" is hard to say. For my tastes,
I'd prefer either the first suggestion or the last. If you intend for
there only to ever be a single scoring object, then the first might be
more appropriate. Then each Rule would have to know which object was that
single scoring object and would directly call a method on that object to
update the score.

On the other hand, if you want your design to be more flexible, such that
you can have multiple scorers present, then it probably makes more sense
for the Rules to use the RuleListener interface to report score changes.
Each scoring object can then subscribe as appropriate to the rules
relevant for that scoring object.
I am thinking about implementing online support, but currently I'll
stick to the single player. I think I don't have time. I'll keep this
in mind though.
As an example of this, consider something like (following your previous
listener interface pattern...you may want to consider instead following
the usual Java model, where an "Event" class is defined that includes all
of the relevant data, including the source and the specifics of the event):

public interface RuleListener
{
void ruleSatisfied(Rule sender, string ruleName);
void scoreChange(Rule sender, int points);
}
This sounds interesting. I'll totally give it a try.
Then scoring objects can subscribe to the Rules as needed, and the UI and
other interested objects can also subscribe. If it turns out that there's
little or no overlap between these two types of subscribers, you might
even break the interface into two, with one interface dedicated to things
that are just "activity notification" sorts of things, and the other
dedicated to things that actually change the game state. Often one event
from each might be raised, but only objects of the appropriate
functionality would subscribe to the specific listener group. That way
you don't waste a lot of time having, for example, having UI objects
receiving and ignoring notifications for game state changes, and having
game state objects receiving and ignoring notifications for UI events.
Yes, there should be two types of interfaces.
I think ultimately I'd go with _some_ variation on this last approach
(that is, the one where the Rule supports listeners for events separated
into appropriate categories, whether in the same interface or in two or
more), but any of the above would probably work (including what you
posted, if you really want to do it that way).

By the way, I'm not sure that the House should expose the collection
implementation. That is, rather than a "setCards" method that takes the
actual collection, it probably makes more sense to have a "clearCards"
method that resets the internal implementaton. If you really need a way
to add or set multiple cards at once from a non-empty collection, you
could still have a more general-purpose method that takes a List<Card>
instead of some specific collection type.

Yeap, I totally agree. I added clearCards().
 
P

pek

Aha. I thought someone whose english was as good as yours would appreciate
an opportunity to improve it even further, even if only in a small way!
Thank you (again). ;) Well, what really annoys is when people take for
granted that English is the only language on earth and if you make a
mistake your retarded. That's why I liked it when you said "I'm
guessing english is not your first language". ;)
Trust your feelings! It doesn't do any harm to inherit them from a common
interface, and it helps to document the code.

Also, both kinds of rules will need a getName() or getDescription()
method, so you can declare that in the root interface.
Great idea! ;)
No problem. I'm sorry it's from a latin root, and not greek!


I'd add a method to the ActionRule interface through which a rule can
indicate it ends the game. This is after applying the refactoring i
mention, so the interface looks like:

interface ActionRule extends Rule {
public String description() ;
public boolean endsGame() ;
public int score() ;
public boolean applies(House h) ;

}

With the addCard looking like:

public List<Rule> addCard(Card card) {
// do permissibility checks here - i omit them
List<ActionRule> applied = new ArrayList<ActionRule> ;
for (Rule rule: rules) {
if (rule.apply(this)) applied.add(rule) ;
}
return applied ;

}

And the game controller having code like:

List<Rule> applied = house.addCard(card) ;
for (Rule rule : applied) {
if (rule.endsGame()) {
tellUser("GAME OVER: " + rule.description() + "!") ;
gameOver = true ;
}
else
tellUser("rule applied: " + rule.description() + "; scored " + rule.score()) ;
score += rule.score() ;
}
tellUser("total score: " + score) ;

}
That sounds really good! I'll definitely try this.
But if there's a permissibility rule that says you can't put a card in a
house whose suit doesn't match, how can you get to the situation where you
put a joker of spades in a house of hearts?
First, the rule that looks for wrong suit in a house can first look if
it is a joker card and permit it to be added.
Then the Rule would look something like this:
class JokerRule implements ActionRule {
private boolean gameOver = false;
private int score = 0;

public String description() { return "Joker Rule"; }
public boolean endsGame() { return gameOver; }
public int score() { return score; }
public boolean applies(House h) {
Card tmp = house.getCards().get( house.getCards().size() -
1 );
if ( tmp.getRank() == CardRank.JOKER ) {
if ( tmp.getSuit() == house.getSuit() )
house.emptyCards();
this.score = 50;
} else {
this.gameOver = true;
}
}

}

What do you think?
 
P

pek

Sorry, I sort of got distracted by one part of the question, and ignored
another part.

In particular, at least part of what I'm thinking of in the above is the
possibility that at least some of the RuleListener interface(s) are there
to support UI. In that respect, I definitely can see how some of the UI
would want to subscribe to only some subset of the rules, assuming that
part of the UI only presents information about that subset.

But this all depends on the exact way that the members of the RuleListener
interface(s) are defined, as well as how the rest of the program is
modularized (I'm mainly thinking UI here, but there could be other aspects
as well for all I know).

One crazy example: suppose we want to be able to run multiple games at
once with the same set of cards. I don't know if this is even possible,
given that some rule-based actions can affect the "houses" of cards, and
so at first blush it seems like it's not possible for the rules to be
treated as mutually independent. But let's say it is. :) Then, you
could have multiple UI presentations, one for each actual game, all hooked
to the same collection of cards.

A less crazy example: you've got "lights" in the UI that blink,
illuminate, or otherwise indicate to the user what happens based on the
rules interpretations. They just want to show when specific actions in
specific rules are triggered. Well, inasmuch as some actions are unique
for a specific rule, there's no need for a UI component specific to a
given rule to need to be subscribed to every other rule as well.

Again, all this depends a lot on details I don't have. I can't say for
sure what _is_ appropriate. I can only make suggestions as to what might
be appropriate. The OP will have to filter the advice and use only what's
applicable to his specific scenario. :)

Pete

OK, so I finally made it and it works........awesome! I mean, I
practically jumped from my seat when it worked. Software development
(along with it's design phase) is art! :p And it's all thanks to you
two, Peter Duniho and Tom Anderson. I can't thank you enough.

Here is what I did, in case you are wondering:

I combined both of your architectures. The game has:
A class Engine that controls all the logic of the game
A class House that controls the House logic
A class Main which is the GUI
A class JHouse which is a wrapper JPanel for a House
Two listeners for raising events (HouseListener and EngineListener)
Two interfaces for the Rules (ActionRule and PermissionRule)
And various Rules that implement them

When the Main GUI starts, it initializes an Engine and adds itself as
an EngineListener. Every action that the Engine does that results in a
game state change, it notifies it's listeners. So the Main GUI updates
it's components appropriately.

When the game starts, the startNewGame method of the Engine is called
from the Main GUI given some parameters for which rules should be
applied. The Engine then adds those rules to each of the four Houses
it creates and generally initializes the game state. Once finished
initializing, it notifies the EngineListeners that there is a new
game. The Main GUI (as an EngineListener) then initializes the
components.

It also initializes four JHouses with their appropriate House. The
Main GUI then registers as a MouseListeners to each of them. That way,
when a JHouse was clicked, it calls it's getHouse() method to obtain
which House in the game it is and then calls the Engine to add the
player's hand card to that house. The Engine simply obeys and doesn't
care about the Rules (it only cares if the game hasn't started or if
the player doesn't have a card etc.). The Engine is also a
HouseListener, so when the state of a House changes (score, closed
etc.) it gets informed to start calculating the general score of the
game, if it ended etc.

The best part of this architecture is that it is based on listeners
and rules that practical do everything automatically. The Engine
doesn't do any card checking when it needs to add it to the House, it
just adds it. The House then runs all the rules and again doesn't care
what happened. The Rules do all the work. Some close the House while
others end the game. Either way, the Engine will get informed from the
House that something changed and it will do the rest. Later on the
Main GUI (as an EngineListener) is informed from the Engine that
something has changed and changes the components appropriately.

That's it! Simply and elegant! :p OK OK, I know, I am very happy with
the results. Again, I can't thank you enough. I couldn't have thought
any of these without your help. Hell, I didn't even know where to
start, or how to implement a Rule architecture.

Thanks again (and again and again...).

Panagiotis Peikidis
 
A

andreas

Why you complicate so much a so simple problem ?
I think that you forgot analyze the problem before to proceed to
design decisions, my advice is to model whole game (rules, stacks of
cards etc) in a more abstracted way, e.g. forget about classes methods
and all stuff specific to the particular programming language and
attack the problem starting from its conceptual view, then apply any
analysis technique you, divide and conquer or a la guerrilla warfare
way. Anyways the objective is to make a crystal clear picture of your
problem.

My personal opinion is that most of card games can be modeled as
states e.g. any combination of cards in various lists of cards (e.g.
stack, closed, open etc) representing a particular state, the state
may be valid or invalid one (this is where rules apply), in other
words imagine rules as a function that has as it's domain any possible
state of the game and the range true|false; this function validates if
cards are in correct place.

By applying the validation function on every change of the state (for
example card put in specific stack) you can keep rules of the game in
order.

If you want to validate the state partially (maybe for speed reasons)
you can brake up the domain in smaller parts and for each part apply
function validating the part, again by applying validation piecewise
all outcomes should be true in order to ensure the validity of whole
game.

Now let's see possible design in Java that will implement all the
above. Abstractly. You have two parts (where each part may consist of
many objects) :

1. The state
2. The Rules

Let's suppose we have a class Rules providing a method

bool validate(State)

each time the state changes you give it to the validate() method and
get a result if everything is ok or awry.
If rules are correct and the State represents the domain clearly and
correctly you have a bulletproof game.

If you want to complicate things more you can apply more complex
validation techniques (consult GoF book :)) but it seems there is no
reason to complicate them in such problem.
 
P

pek

Why you complicate so much a so simple problem ?
I think that you forgot analyze the problem before to proceed to
design decisions, my advice is to model whole game (rules, stacks of
cards etc) in a more abstracted way, e.g. forget about classes methods
and all stuff specific to the particular programming language and
attack the problem starting from its conceptual view, then apply any
analysis technique you, divide and conquer or a la guerrilla warfare
way. Anyways the objective is to make a crystal clear picture of your
problem.

My personal opinion is that most of card games can be modeled as
states e.g. any combination of cards in various lists of cards (e.g.
stack, closed, open etc) representing a particular state, the state
may be valid or invalid one (this is where rules apply), in other
words imagine rules as a function that has as it's domain any possible
state of the game and the range true|false; this function validates if
cards are in correct place.

By applying the validation function on every change of the state (for
example card put in specific stack) you can keep rules of the game in
order.

If you want to validate the state partially (maybe for speed reasons)
you can brake up the domain in smaller parts and for each part apply
function validating the part, again by applying validation piecewise
all outcomes should be true in order to ensure the validity of whole
game.

Now let's see possible design in Java that will implement all the
above. Abstractly. You have two parts (where each part may consist of
many objects) :

1. The state
2. The Rules

Let's suppose we have a class Rules providing a method

bool validate(State)

each time the state changes you give it to the validate() method and
get a result if everything is ok or awry.
If rules are correct and the State represents the domain clearly and
correctly you have a bulletproof game.

If you want to complicate things more you can apply more complex
validation techniques (consult GoF book :)) but it seems there is no
reason to complicate them in such problem.

So, if I understood correctly, you are saying that House should add
the card anyway, and then run all the rules. Each rule will examine
the state of the house as it thinks and return true (if the state is
ok or the rule doesn't make sense) or false (if the state is erroneous
according to the rule).

Is this correct? If yes, that means that the House will add the card
first and then run the rules. If any rules reports an erroneous state,
what will the house do? Will it remove the card and throw an exception?
 
P

pek

So, if I understood correctly, you are saying that House should add
the card anyway, and then run all the rules. Each rule will examine
the state of the house as it thinks and return true (if the state is
ok or the rule doesn't make sense) or false (if the state is erroneous
according to the rule).

Is this correct? If yes, that means that the House will add the card
first and then run the rules. If any rules reports an erroneous state,
what will the house do? Will it remove the card and throw an exception?

In case anyone is wondering, I finished the game and uploaded it to my
site. It's at http://treazy.com/apps/javacorner. The game is called
House of Cards.

Again, thank you for all your advises. I couldn't have done it without
you.
 
T

Tom Anderson

Why you complicate so much a so simple problem ?

[snip]

Andreas, your suggestion is not only every bit as complicated as the
solution Pek chose, it doesn't actually solve the problems his did!

tom
 
P

pek

Why you complicate so much a so simple problem ?

Andreas, your suggestion is not only every bit as complicated as the
solution Pek chose, it doesn't actually solve the problems his did!

tom

One more thing before this discussion dies..
Remember the Joker rule? If a joker enters a house with a different
suit, the game is over, otherwise the cards in a house clear and the
player gains points (in this game, jokers have suit). A house of cards
can also close if the sum of card points in it exceeds 31 (each cards
has a number of points). The player wins if he uses all 56 cards in
the deck without losing. If you think about it, if a House closes and
the joker with the same suit is still in the deck, eventually the
player will lose. So it is pointless.

Currently my system goes like this:
The house has a list of rules which every time a card is going to be
added, it runs them and gets the results (whether the card can enter,
it reached 31 etc.). When a player wants to add a card to the house,
he clicks a component in the GUI. The GUI then calls the engine to add
the card in a house and the engine simply calls the corresponding
house to add the card. In other words, the Engine (although it
contains all the game logic - starts new games, checks for game over
etc.) it doesn't care about entering a card in the house since the
house has this functionality.

Now, determining whether the deck contains a joker of a certain suit
cannot be done in this system simply because the house isn't aware of
such things as other houses or decks. The solution I can think is
passing the rules responsibility to the Engine and leaving the House
to be simply a data type. So then the Engine can check other houses
etc.

What do you think about this? Any comments/suggestions..?
 
P

pek

[...]
Now, determining whether the deck contains a joker of a certain suit
cannot be done in this system simply because the house isn't aware of
such things as other houses or decks. The solution I can think is
passing the rules responsibility to the Engine and leaving the House
to be simply a data type. So then the Engine can check other houses
etc.
What do you think about this? Any comments/suggestions..?

I'm not exactly clear on what "rules responsibility" means. Just because
a Rule has subscribed to a House's event, I don't see how that means that
the House is _responsible_ for the Rule per se.

But yes, it seems to me that Rules are not a House-level construct, but
rather a whole game- (Engine-) level construct, and as such would have
access to all House instances, through the Engine. I would, in fact,
expect that the Engine is the class that's actually managing the Rule
instances, even as each Rule instance may have subscribed to multiple
House instances to receive events that affect game state, etc.

Pete

Yes, that where my thoughts exactly. Thanks for your feedback..
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top