2

I'm working on a Monopoly based game with properties, money, cards, etc. I recently ran into a problem when working on the chance card aspect of the game...

I have an array of Strings that say things, ex,"Tax refund; collect $25" or "You lose money due to stocks; -$100". Each card does something different, not all of them just deal with money. My question: how can i store these cards to each hold a string with its description but also any action that is involved. For example, card1 has a String and an int value (-25), but on the other hand another card, card2 has a String, an int value(+10) and a property. Sorry if the question is really vague but I don't know how else to describe it.

Just to clarify:

A card could contain simply the description and a money value. While another card might contain a description, money value and move certain spaces.

Thanks to everyone who gave out awesome ideas so quickly!

mbreen
  • 558
  • 3
  • 9
  • 20
  • 2
    Create a class for Card, use the [Command Pattern](http://en.wikipedia.org/wiki/Command_pattern) design pattern so each card can have a different type of action if need be. So it will hold a String field, text, an int field, value, and another field that is for an interface that represents your action. – Hovercraft Full Of Eels Jan 31 '12 at 03:28
  • 1
    @HovercraftFullOfEels You should add that as an answer. – Timothy Jones Jan 31 '12 at 03:31
  • What possible actions can a card have? – Dawood Jan 31 '12 at 03:32
  • As an aside, [`RotateText`](http://stackoverflow.com/a/6238908/230513) may be of use going forward. – trashgod Jan 31 '12 at 04:50

6 Answers6

5

If your range of actions is very limited (say, 2 or 3 actions involving money, move squares, etc) then I might use the following class:

class Card {
    // It would be a good practice to not make the following fields
    // public and use getters/setters instead but I've made them this
    // way just for illustration purposes

    public String text;
    public String action;
    public int value;

    Card(String text, String action, int value) {
        this.text = text;
        this.action = action;
        this.value = value;
    }
}

This way (as already pointed out by some other answers), you can use an array of Cards instead of array of Strings. You can then have text in one field, the action in a separate field, and the value associated with that action in a third field. For example, you could have the following cards:

Card lose25 = new Card("You lose $25", "money", -25);
Card move5squares = new Card("Move 5 squares ahead!", "move", 5);

When you're 'processing' the cards, you can do so in the following manner:

...
if (card.action.equals("money") {
    // Update user's money with card.value
} else if (card.action.equals("move") {
    // Update user's position with card.value
} else if (card.action.equals("...") {
    // and so on...
}
...

EDIT:
If the cards can hold more than one action, you can use a HashMap to store actions for that card:

class Card {

    public String text;
    public HashMap<String, Integer> actions;

    Card(String text) {
        this.text = text;
        actions = new HashMap<String, Integer>();
    }

    addAction(String action, int value) {
        actions.put(action, value);
    }
}

A HashMap is a collection that can store key-value pairs. So for a card that has 2 actions, you can use the above code as:

Card aCard = new Card("Lose $25 and move back 3 spaces!");
aCard.addAction("money", -25);
aCard.addAction("move", -3);

Now, when you're actually processing the cards, you need to check the HashMap for all actions stored in this card. One way to iterate through the HashMap is to do the following:

Card processCard = ...;

for (Map.Entry<String, Integer> entry : processCard.actions.entrySet()) {
    // This loop will get each 'action' and 'value' that you added to
    // the HashSet for this card and process it.

    String action = entry.getKey();
    int value = entry.getValue();

    // Add the earlier 'card processing' code here...

    if (action.equals("money") {
        // Update user's money with value
    } else if (action.equals("move") {
        // Update user's position with value
    } else if (action.equals("...") {
        // and so on...
    }
}
Dawood
  • 5,106
  • 4
  • 23
  • 27
  • Could I have multiple actions in one card? Such as "Lose $25, and move back 3 spaces" – mbreen Jan 31 '12 at 04:00
  • So in your new example, what would be the method for declaring a new card with 2 actions? – mbreen Jan 31 '12 at 04:02
  • Wow, great solution. Thank you so much for the great idea and walkthrough. I can't wait to dive right in creating tons of cool card ideas. – mbreen Jan 31 '12 at 04:07
  • I've tried to illustrate the basics... hope it helped. Basically, using this approach you can store as many actions as you want in a card.. or even no actions at all. If the different _types_ of actions is limited, then the `if` block inside the loop should not be too large. – Dawood Jan 31 '12 at 04:12
  • @mbreen: I posted a solution that allows you to have several actions per card in a new answer. – nbarraille Jan 31 '12 at 05:20
  • @Dawood: I believe it would be cleaner to have an enum type for Action, as the number of correct values is small. This would be an added security against typos. – nbarraille Jan 31 '12 at 05:22
  • @nbarraille: Good point... I was just trying to illustrate a very basic working solution but thanks for pointing that out. – Dawood Jan 31 '12 at 05:45
4

Create a class for Card, use the Command Pattern design pattern so each card can have a different type of action if need be. So it will hold a String field, text, an int field, value, and another field that is for an interface that represents your action.

The key field will be the "action" field that holds a reference to an interface type, say called CardAction:

interface CardAction {
   execute();
}

Or you could use use a Runnable or a Future if you want to use a ready made interface. This way you can inject objects of this class with different actions for different types of cards. This will prevent you from having to create multiple different Card classes.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 2
    I've voted this up because it's the right way to go about things but not sure if this is the level of complexity OP would be comfortable with. I don't mean to sound indelicate but something more beginner-ish might be appropriate. For example, if the range of actions is very limited (2 or 3 actions), then another string can store the action and an int used to store the value associated for that action. – Dawood Jan 31 '12 at 03:37
  • Not very familiar with Command Patterns, but I'll look into it. Thanks! I'm always looking for new techniques – mbreen Jan 31 '12 at 03:50
1

This is a solution that allows each card to have several actions.

The ActionType is an interface, as it only has several correct values.

All the fields are made final as once the cards have been created, they shouldn't be allowed to change.

The getActions() method returns a copy of the array as we don't want the game to be able to modify the actions of the card after creation.

enum ActionType {
    MONEY, MOVE, ...
}

class Action {
    private final String description;
    private final ActionType type;
    private final int value;

    public Action(String desc, ActionType type, int value) {
        this.description = desc;
        this.type = type;
        this.value = value;
    }

    public String getDescription() {
        return description;
    }

    public ActionType getType() {
        return type;
    }

    public int getValue() {
        return value;
    }

}

class Card {
    private final Action[] actions; // If you want to be able to modify the list of actions after creation, use a non-final List<>, otherwise an array

    public Card(Action... actions) {
        this.actions = actions;
    }

    public Action[] getActions() {
        Action[] copy = new Action[actions.length];
        System.arraycopy(actions, 0, copy, 0, actions.length);
    }
}
nbarraille
  • 9,926
  • 14
  • 65
  • 92
0

Make a Card class, with a string called text or something, and a method called onAction() or something. Then, make lots of other classes - one for each card - extending the Card class. Give the string the text you want and in the method you can then put exactly what you want to happen. You can create a class called Deck containing instances of all of these Cards and an array/list, and a draw() method or whatever you've done already. On drawing a Card from the Deck, get it to print that Card's text and call its onAction() method.

Hope this helps.

SamBrev
  • 11
  • 5
0

Make a Card Class, it should contain the description (String) and a value (int) (+10,-25, 0 ect...). You then would have a array of Cards instead of array of strings.

Robert Peters
  • 3,814
  • 1
  • 17
  • 9
0

Have a Card class with description and value.

Card
{
String description;
int value;

    Card(String desc, int value)
    {
    this.description = desc;
    this.value = value;
    }

    getters..
    setters...
    }

Create objects like

Card c = new Card("You may loose 25$...", -25);

Note that, these cards with int value can accept values between -2,147,483,648 to 2,147,483,647. If you want some higher values, you can change int to long or something else.

kosa
  • 65,990
  • 13
  • 130
  • 167
  • 2
    "Note that, these cards with int value can accept values between -128 to 127" - not true. They can store values from -2,147,483,648 to 2,147,483,647 (32bit integers). – Dawood Jan 31 '12 at 03:33
  • 1
    @Dawood,You are correct, I am doing 2s compliment class work and under same impression. Updated my answer – kosa Jan 31 '12 at 03:36
  • Great. Although I doubt OP would have monopoly cards involving more than $2.15 billion in transactions :) – Dawood Jan 31 '12 at 03:39
  • @Dawood, dont know, got couple of down votes answering without those notes (for other question), just a caution. – kosa Jan 31 '12 at 03:45
  • Yes, no need to worry about integer bounds haha. But I like this simple solution, and I was implementing it already when I ran into the problem of what if one card has ("description",-25) but another card has ("description",+100,-1 property). Some cards hold more than 1 "action" – mbreen Jan 31 '12 at 03:47
  • ("description+100",-1) is that what you are asking for (or) ("description+100",-1, anotherAction)? – kosa Jan 31 '12 at 03:51
  • @mbreen: I am not good at cards game, it took awhile for me too understand. Look at Dawood answer, that is what you need to do. – kosa Jan 31 '12 at 03:56