Velocity Reviews > Java > Designing a Card Game

# Designing a Card Game

Tom Anderson
Guest
Posts: n/a

 05-30-2008
On Thu, 29 May 2008, Lew wrote:

> Tom Anderson wrote:
> Ed Kirwan wrote:
>>> Though, admittedly, cards should be able to at least compare themselves
>>> with other cards, yet even this comparison may be game-dependent. That
>>> will be an interesting problem for you.

>
> Sure, consider Omaha Hi/Low. The Ace can be used as both the high card
> and the low card, in the same hand, even winning both times. How could
> the card hold the logic for that comparison, let alone the variations in
> games like Canasta or Baccarat,

Omaha Hi/Lo is a great example of why the approach of having
highness/lowness as part of the ace's type or state can't work. The basic
idea, of an ace being high or low, is the same as in many other games,
though.

I do wonder if there isn't a way to deal with aces within Rank. How about
- and this is really horrible, but i mention it for completeness - we say
that a Card will always try to claim it's greater than any card it's
compared to. So:

KING.compareTo(TEN) == 1
TEN.compareTo(KING) == -1
KING.compareTo(ACE) == 1
ACE.compareTo(KING) == 1 (!)

I think the common case in a program is asking whether some card beats
another, and this will work for that. Programs can also use this to ask if
a sequence of cards is in greatest-to-least order, dealing with aces
correctly. If you want to sort, though, you're stuffed!

Oh well, i suppose you could implement a Comparator<Rank>, perhaps
different for each game, to do this, so sorting works normally; you could
even have Comparators which could be fed context information from the rest
of the game before being applied.

I read that in Pinochle, not only is the ace high, but the 10 ranks right
after it, before the king!

> let alone Crazy Eights?

Does Crazy Eights have an ordering on the cards?

tom

--
Oh, well of course *everything* looks bad if you remember it

John B. Matthews
Guest
Posts: n/a

 05-30-2008
In article <(E-Mail Removed) >,
Tom Anderson <(E-Mail Removed)> wrote:

> On Fri, 30 May 2008, RedGrittyBrick wrote:

[fine example]
> Aha! I didn't realise you could do that. This enum stuff is all new to me!

Same here; I liked this stuff from Sun:

<http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html>
<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9>

Here's one I came up with to manage keyCodes in a game:

<http://robotchase.sourceforge.net/org/gcs/robot/Key.html>
<http://robotchase.svn.sourceforge.ne...unk/src/org/gc
s/robot/Key.java?view=markup>

John
--
John B. Matthews
trashgod at gmail dot com
home dot woh dot rr dot com slash jbmatthews

David Zimmerman
Guest
Posts: n/a

 05-30-2008

Tom Anderson wrote:
> On Thu, 29 May 2008, Lew wrote:
>
>> Tom Anderson wrote:
>> Ed Kirwan wrote:
>>>> Though, admittedly, cards should be able to at least compare
>>>> themselves with other cards, yet even this comparison may be
>>>> game-dependent. That will be an interesting problem for you.

>>
>> Sure, consider Omaha Hi/Low. The Ace can be used as both the high
>> card and the low card, in the same hand, even winning both times. How

>
> I read that in Pinochle, not only is the ace high, but the 10 ranks
> right after it, before the king!
>

or Euchre where the Jack's can move from where you expect them to be
above the ace and even change suit. The jack of trump is the highest
card in that suit and the Jack of the same color is the second highest.
So if Hearts are trump then the rank of the trump suit is
Jack of hearts, Jack of Diamonds, Ace, King, Queen, Ten, Nine of Hearts

pek
Guest
Posts: n/a

 05-31-2008
Well, IMO, in games where ACES (or any card) that can be in more than
one places should be checked using rules. The links that Kriwan
provided had some evaluator classes which I think is how you can deal
with placing the cards correctly.

Here is another interesting question. Using comparable, you can find
whether one card is before or after another, but can you find how many
"steps" is it? I thought enum had an easy way of finding the index of

public enum Rank {

ACE(1),TWO(2),THREE(3),FOUR(4),FIVE(5),SIX(6),SEVE N(7),EIGHT(,NINE(9),TEN(10),JACK(11),QUEEN(12),K ING(13);
private int index;
private Rank(int index) { this.index = index; }
public int getIndex() { return this.index; }
}

And yet another. Let's say that we have a Card class that other than
having a Rank and a Suit it has a Face (whether it is faced up or
down). Face.UP means that you can see the Rank and Suit of a Card
while Face.DOWN you cannot (think of cards in Klondike Solitaire).
Now, if a card is faced down and an object calls getRank() or
getSuit(), would throwing an Exception("The card is faced down, you
cannot see the rank or suit") be a good implementation or is this not
needed?

Sorry for extending this discussion further than it's original
topic.

pek
Guest
Posts: n/a

 05-31-2008
On May 31, 10:27 am, "Peter Duniho" <(E-Mail Removed)>
wrote:
> On Fri, 30 May 2008 22:59:05 -0700, pek <(E-Mail Removed)> wrote:
> > [...]
> > Here is another interesting question. Using comparable, you can find
> > whether one card is before or after another, but can you find how many
> > "steps" is it? [...]

>
> > And yet another. Let's say that we have a Card class that other than
> > having a Rank and a Suit it has a Face (whether it is faced up or
> > down). Face.UP means that you can see the Rank and Suit of a Card
> > while Face.DOWN you cannot (think of cards in Klondike Solitaire).

>
> I can't answer the enum question...haven't used Java enums enough yet.
>
> But as far as adding the "face" as a property of the card, I'm not sure
> I'd do that. Up to this point, your cards have had the very nice
> characteristic of being immutable. They just "are", and can be members of
> various collections, but any given card won't change. This keeps the
> class nice and simple.
>
> Adding a "face" property introduces mutability to the class, which may
> open the door to other tempatations to weigh down the class with too much
> functionality.
>
> > Now, if a card is faced down and an object calls getRank() or
> > getSuit(), would throwing an Exception("The card is faced down, you
> > cannot see the rank or suit") be a good implementation or is this not
> > needed?

>
> I'd say this is a good example of what I'm talking about. Once you think
> about having a "face" property, all of the sudden you're thinking of
> making the card responsible for other stuff. The above suggestion seems
> to me to go overboard. I mean, now the "face" property can turn the card
> instance from being some useful description of the card to an object that
> refuses to tell you anything at all about itself! Under that condition,
> how would a rules implementation be able to properly manage the state of
> the game, inasmuch as face-down cards still need to be considered?
>
> No, I think for situations where a card's visibility is important, that's
> probably better-managed by some other structural part of the game
> implementation. For example, cards that are face-up would be found in
> some specific collection, while cards that are face-down would be found in
> some other collection. The rules implementation can tell from where the
> cards are located whether they are visible to the player or not and can
> manage the game that way.
>
> Pete

Hmmm.. Seems fair.. I agree about the exception part. For "an object
that refuses to tell you anything at all about itself!" is surely a
bad thing. I didn't thought about it that way. And making to
collections of cards probably simplifies the problem. So I agree.

As for how many "steps" between enums, I completely forgot that enums
have the ordinal() method which return the index (exactly what I
wanted).

Thanks for your help and suggestions.

pek
Guest
Posts: n/a

 05-31-2008
On May 31, 3:58 pm, Lew <(E-Mail Removed)> wrote:
> Peter Duniho wrote:
> > On Fri, 30 May 2008 22:59:05 -0700, pek <(E-Mail Removed)> wrote:

>
> >> [...]
> >> Here is another interesting question. Using comparable, you can find
> >> whether one card is before or after another, but can you find how many
> >> "steps" is it? [...]

>
> >> And yet another. Let's say that we have a Card class that other than
> >> having a Rank and a Suit it has a Face (whether it is faced up or
> >> down). Face.UP means that you can see the Rank and Suit of a Card
> >> while Face.DOWN you cannot (think of cards in Klondike Solitaire).

>
> > I can't answer the enum question...haven't used Java enums enough yet.

>
> > But as far as adding the "face" as a property of the card, I'm not sure
> > I'd do that. Up to this point, your cards have had the very nice
> > characteristic of being immutable. They just "are", and can be members
> > of various collections, but any given card won't change. This keeps the
> > class nice and simple.

>
> > Adding a "face" property introduces mutability to the class, which may
> > open the door to other tempatations to weigh down the class with too
> > much functionality.

>
> Pete's point applies to your suggested use of ordinal(), pek.
>
> > public enum Rank {

>
> > ACE(1),TWO(2),THREE(3),FOUR(4),FIVE(5),SIX(6),SEVE N(7),EIGHT(,NINE(9),TEN(10),JACK(11),QUEEN(12),K ING(13);
> > }

>
> Since the rank of a card is a function of the game, and not the card (and
> isn't ACE usually the *highest* ranking card?), a name like "ACE" doesn't
> actually communicate Rank, at least not in the sense a Game would mean it.
>
> Relative ranking is an attribute of the game, not the card, true? An Ace
> doesn't know if it's the highest, lowest, both at once or something in between
> except for what game is under way.
>
> So why model the relative ranking as an attribute of the card, then?
>
> It is not.
>
> --
> Lew

Hmmm.. While I totally agree with that, I believe it is really
convinient to use ordinal() to do some basic calculations.. Of couse,
if you need a more complicated way (such as finding which card to
place to the top or bottom) then I would likely use an object to do
that.

What would you use for calculating this other than ordinal()? Create a
static method that would do the job maybe?

Stanimir Stamenkov
Guest
Posts: n/a

 05-31-2008
Sat, 31 May 2008 10:30:41 -0700, /Peter Duniho/:
> On Sat, 31 May 2008 07:41:38 -0700, Lew <(E-Mail Removed)>
> wrote:
>
>> public interface Game
>> {
>> public java.util.Comparator<Card> getComparator();
>> // other methods
>> }
>>
>> The Comparator is free to account for game state in its logic.

>
> Sure. But on what does the Comparator base its decision?

Unless I'm missing something here, the Comparator would base its
decision on the specific game logic, wouldn't it? Example:

class SpecificGame implements Game {

static Map<Card, Integer> cardRanks;
static {
// init cardRanks
}

private Comparator<Card> rankComparator = new Comparator<Card>() {
public int compare(Card c1, Card c2) {
// Game state could also be accounted here.
return cardRanks.get(c1) - cardRanks.get(c2);
}
};

public Comparator<Card> getComparator() {
return rankComparator;
}

}

--
Stanimir

pek
Guest
Posts: n/a

 05-31-2008
On May 31, 8:30 pm, "Peter Duniho" <(E-Mail Removed)>
wrote:
> On Sat, 31 May 2008 07:41:38 -0700, Lew <(E-Mail Removed)>
> wrote:
>
>
>
> > Lew wrote:
> >>> So why model the relative ranking as an attribute of the card, then?

>
> >>> It is not.

>
> > pek wrote:
> >> Hmmm.. While I totally agree with that, I believe it is really
> >> convinient to use ordinal() to do some basic calculations.. [...]
> >> What would you use for calculating this other than ordinal()? Create a
> >> static method that would do the job maybe?

>
> > I tend to prefer instance methods.

>
> > public interface Game
> > {
> > public java.util.Comparator<Card> getComparator();
> > // other methods
> > }

>
> > The Comparator is free to account for game state in its logic.

>
> Sure. But on what does the Comparator base its decision?
>
> We actually discussed this earlier in the thread. I believe we already
> came to the agreement that the card itself shouldn't be implementing game
> rule evaluations. This is exactly what you're arguing for, so we agree
> with you.
>
> But it's a huge convenience for the card to have _some_ numerical value
> that is representative of the usual comparison for game rules. Special
> cases can be, well...special-cased.
>
> Otherwise, you wind up having to implement each possible comparison
> explicitly. Who wants to do that?
>
> I don't think that "pek" is proposing that the game rules be embedded in
> the Card class. That's contrary to where the discussion has taken us so
> far.
>
> Pete

Of course I'm not proposing to embed rules in the card class. I had a
6d8224fb08979586/) that I implemented it. It's an easy way of adding
and currently I'm testing it even more while developing a simple
Klondike Solitaire game. I started this discussion mostly to see how
other people would design cards games with jokers, ordering and
generally any other design decissions that a card game will need.

I started a wiki for java game developing (http://treazy.com/wiki/
index.php?title=The_Definitive_Java_Game_Programmi ng_Open-Source_Book)
and I'm focusing mostly on design. Your help was excelent! I'm trying
to create an article. Any help or suggestions is welcome.

pek
Guest
Posts: n/a

 06-18-2008
OK, I know this is the wrong place to post my question, but this is
where I first wrote about it. In this discussion (Designing a Card
Game) I was wondering how to create a Joker Card because a Joker
doesn't have a Suit and the Card class does. Anyway, one of the

How about a rank of Joker and suit of null?
by Knute Johnson

At that time, I tested his suggestion and replied:
Interestingly, you cannot pass null when a method requires an
enumeration!

In which he replied:
Sure you can!
[snip]
method((X)null);
[snip]

I swear that when I first tested new Card(Rank.JOKER, null) eclipse
displayed a compile-time error. I can't remember what was the error,
but now I can't reproduce it! Now new Card(Rank.JOKER, null) doesn't
yell anything! Assuming Knute also had seen this error (since he
provided a solution instead of calling me names), what's happening?

Just in case this may help, when I first tested that code, I was under
Windows XP while now I'm using Ubuntu. Although I seriously doubt it.

So what's the big deal? Is it, or is it not a compile-time error when
passing null in a method that expects an Enum?

Roedy Green
Guest
Posts: n/a

 06-18-2008
On Wed, 18 Jun 2008 13:40:33 -0700 (PDT), pek <(E-Mail Removed)>
wrote, quoted or indirectly quoted someone who said :

>
>How about a rank of Joker and suit of null?

I would use enum Card

with rank and suit as properties (i.e getRank())
that return yet another enum, with JOKER being one of the possible
values.

Treat JOKER like HEARTS or like TWO
--

The Java Glossary
http://mindprod.com