tags:

views:

43

answers:

4

I am making a card game where the cards are represented as JLabels, having names and some other attributes which are changed during the game. I want to define equality as simply comparing the full names (represented by a field fullName) of two cards. However, this gives me the problem that I can't add the same card twice (because I have other fields in the Card class which might differ).

Apparently the JPanel does some checking about equals in the background. I then add a unique id field to each card and in the class i keep track of how many cards of a kind I created with

    private static Map<AbstractCard, Integer> idCount = new HashMap<AbstractCard, Integer>();

and then each time the constructor of a certain card is invoked I increase the value in idCount. But then, if I add the check for id as well as the original name, not only the Map will break but it still doesn't add more than one card if the names are equal. This is what the method looks like now:

/**
 * Compares this card to the specified object. The result is true if and only if 
 * the argument is not null and is a Card object that represents the same full name
 * as this card.
 * @return true if the cards are equal, otherwise false
 */
@Override
public boolean equals(Object o)
{
    if (!(o instanceof AbstractCard))
        return false;
    else
    {
        AbstractCard c = (AbstractCard)o;
        return this.fullName.equals(c.fullName) && this.id == c.id;
    }
}

Any thoughts on how to solve this?

EDIT: My hashCode returns fullName.hashCode() and in the current version I add id.

+1  A: 

EDIT

I did the following test and it worked fine:

private class MyLabel extends JLabel {
    public MyLabel(String text) {
        super(text);
    }
    public boolean equals(Object obj) {
        return true;
    }
};


public MyPanel() {
    getContentPane().setLayout(new GridLayout());
    getContentPane().add(new MyLabel("Label 1"));
    getContentPane().add(new MyLabel("Label 2"));
    getContentPane().add(new MyLabel("Label 3"));
}

What problems are you facing?

BTW: This will not solve your problem, but JavaDoc for equals says

Note that it is generally necessary to override the hashCode method whenever this method is overridden


If a card extends a JLabel, and you create an instance for every card you have, you should not have to override equals at all. Make sure not to add the same card to two containers (or to one container twice). This would not work for real cards either.

It might be a better approach to split the card class from their visualization. Have you considered not extending your card from a swing class?

You could just override toString and display them in a JList.

Peter Lang
What I mean is that I can create two instances which both share the same name, but differ in other attributes. These two are not the same card but since they have the same name, I want to be able to consider them "equal".I tried using composition instead of inheritance (in fact my current version uses composition) but still the bug (feature?) is there - can't add more than two with the same name.
pg-robban
I forgot to mention about the hashCode, it's been added into the question. What's strange is that when I did something similar to your example, it does work as intended, but when I do it in the real code, with 2 of the "equal" cards plus two different (4 components), I get 3 from getComponentCount?
pg-robban
Sounds like you have some other problem then. You could try to remove things from your program as long as you are able to reproduce the problem, and see what causes this behavior.
Peter Lang
+1  A: 

HashMaps depend on hashcode to find the correct "bucket", and then pick the correct element via equality tests. If you are not overriding hashCode(), HashMap may fail to retrieve the item even if it is there. Generally speaking, always override equals() and hashCode() together.

I would, however, urge you to rethink your design. This sort of reference counting is not a good idea. In addition, you are mixing too much logic and model elements into your GUI code. You should think about adopting more of a Model-View-Controller to problem. Have the game modeled completely, then have the UI represent the model.

Uri
A: 

I am terribly sorry about this, it appears to have been my own fault all along. After lots of debugging and printing, I found out that I had a reference in the panel that was part of another panel, and so I somehow only "really" had 3 cards. After I removed the reference and made a new Card instead, it finally showed up and getComponentCount returned 4.

Once again, I'm sorry for wasting your time.

pg-robban
Guess I've been right with `Sounds like you have some other problem then.` :)
Peter Lang
A: 

As an aside, you might enjoy reading the source of this simple game. It's not a card game at all, but the GameButton class might suggest a way to use Unicode glyphs to symbolize a card's rank and suit.

trashgod