Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (475)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (530)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Question about structure  (Read 1060 times)
0 Members and 1 Guest are viewing this topic.
Offline crazybear

Senior Newbie





« Posted 2011-12-23 07:00:37 »

Hello All,  I had a quick question about the structure of my program.  I am making a card game where the cards can have many different actions.  I need to implement a method to play the card that would add the results of those actions to the players attributes such as number or cards and so on.  Sorry for the long intro to my question,  but here it finally is:

Should I make the play card method in the card or the player class?  If in the card class, how do I make sure the actions alter the player variables?
Offline crazybear

Senior Newbie





« Reply #1 - Posted 2011-12-23 07:31:39 »

Just thought I would give a little more info.  I currently have the playcard method in the player class, and it just gets all the attributes that the card has and adjusts the players stats accordingly.  I just wanted to make sure this was the best possible way to handle it.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #2 - Posted 2011-12-23 08:46:41 »

If I was going to do this I would use a somewhat functional programming approach and design it this way...

1  
2  
3  
4  
5  
6  
7  
8  
9  
class Player {
    String name;
    int hp;
    ...
}

abstract class Card {
    Player apply(Player p);
}


Then for each card that you have, it extends Card and implements apply.  The apply method could be purely functional in that it takes an instance of Player and returns a brand-new instance of Player that is changed.  Both could be considered immutable when viewed from outside of Card's implementation.

For example:
1  
2  
3  
4  
5  
6  
7  
class PlusTwoCard extends Card {
    Player apply(Player p) {
        Player changed = new Player(p);  // copy constructor
       changed.hp = p.hp + 2;
        return changed;
    }
}
 

Since the behaviour of each Card is very different but the application is uniform I would design my Card hierarchy in the above way.  The functional aspect makes it much easier to unit-test each Card's behaviour.

If this functional approach seems too weird then you could change PlusTwoCard.apply to mutate Player directly:
1  
2  
3  
void apply(Player p) {
    p.hp = p.hp + 2;
}


However with mutated state it's harder to unit-test and it's harder to track temporary effects (e.g. an enchant card that lasts for 3 rounds and increases your armour.  How do you know what to return the player back to when it wears off?).
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #3 - Posted 2011-12-23 09:14:08 »

Now with the above you can do your magic.

Perhaps player 1 has a hand with 3 cards.  You need to calculate the modifications of these 3 cards to the player 2:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
Player p1;
Player p2;

List<Card> p1Hand;

p1Hand.clear();
p1Hand.add(new EnchantArmourCard());
p1Hand.add(new ExtraSpeedCard());
p1Hand.add(new ToughnessCard());

Player p2Calc = p2;
for (Card card : p1Hand) {
    p2Calc = card.apply(p2Calc);    
}

// keeping Player immutable and p2 holds the stats before the cards
// were applied and p2Calc holds the modified status.


If the application of a card is permanent, then assign the result of apply back to the player e.g.

1  
p2 = new WitherCard().apply(p2)
Offline philfrei
« Reply #4 - Posted 2011-12-23 09:38:22 »

A different way of looking at it: the method doesn't have to be in either the Card or the Player, but can be on or called by some sort of "turn" controller.

It seems to me, a given Card never changes state, but a Player does have state changes. So, I'd me more inclined to read values from the immutable object (card) and apply them to the mutable object (player's state) according to a set of interpretation rules (a third object to consider, separating out the game rules from the tokens being used).

Four objects, the fourth being a "turn": consists of the cycle of getting the next card on the card queue, and getting the next player on the player queue, and applying set of interpretation rules that are consulted.

Maybe this has some relationship to a "strategy" method (the rule interpretation part)? I have trouble remembering which pattern is which.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline crazybear

Senior Newbie





« Reply #5 - Posted 2011-12-23 17:02:09 »

Thanks both of you for the ideas.  I think I will use your idea loom_weaver, it makes a lot of sense to me and I like it better than what I am currently doing.  I think it will work well since I also will need to possibly affect all the other players as well.

I guess in that case, I would put the class that my cards would extend in my main method so that it can call on the players array.  Or would there be a better way to do it?
Offline crazybear

Senior Newbie





« Reply #6 - Posted 2011-12-23 17:40:46 »

Or, I guess what I could do instead is have it pass the player and the the array of players so that it can apply the positive effects to the player, and any negative effects the other players at the table in the case of global effects to the opponents.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #7 - Posted 2011-12-23 21:47:39 »

Or, I guess what I could do instead is have it pass the player and the the array of players so that it can apply the positive effects to the player, and any negative effects the other players at the table in the case of global effects to the opponents.

Yup you have the right idea.  The signature for Card.apply would stay the same and you just call it for each Player that should be affected.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #8 - Posted 2011-12-23 22:19:51 »

It seems to me, a given Card never changes state, but a Player does have state changes. So, I'd me more inclined to read values from the immutable object (card) and apply them to the mutable object (player's state) according to a set of interpretation rules (a third object to consider, separating out the game rules from the tokens being used).

Correct, a Card doesn't change state because it doesn't have any.  Card's methods could be static.

If the OP is creating a Magic The Gathering style of game then I would recommend that the Player class should be immutable as well.  Treat it as a Map of data.

It is necessary to keep an instance of the base-Player i.e. without any "spell effects applied".  Then calculate resulting values by applying all the affecting Cards.  The main benefit is that it's easy to re-calculate what the Player should be when spell effects wear off.  Just re-apply all the Cards still in effect to the base-Player.

The only thing that would mutate is the collection of Player variables that are participating in the Game (rather than the contents of the Player class itself).
Offline crazybear

Senior Newbie





« Reply #9 - Posted 2011-12-24 00:29:18 »

Correct, a Card doesn't change state because it doesn't have any.  Card's methods could be static.

If the OP is creating a Magic The Gathering style of game then I would recommend that the Player class should be immutable as well.  Treat it as a Map of data.

It is necessary to keep an instance of the base-Player i.e. without any "spell effects applied".  Then calculate resulting values by applying all the affecting Cards.  The main benefit is that it's easy to re-calculate what the Player should be when spell effects wear off.  Just re-apply all the Cards still in effect to the base-Player.

The only thing that would mutate is the collection of Player variables that are participating in the Game (rather than the contents of the Player class itself).

Well, its not a MTG type game, though I wouldn't mind making one like this, but it is going to be one similar to Dominion.  I think that would be much easier than MTG to implement. 

My player class though will be changing, why do you recommend keeping it immutable?  I am maintaining the state data in the player, see a short bit of my code below.  Would you recommend something different?  By the way, thank you for all the help.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
public class Player 
{
   //global variables
  Deck deck = new Deck();
   ArrayList<Card> CardList = new ArrayList<Card>();
   Hand playersHand;//need to set to new deck after the deck has been initialized
  int numActions;
   int numBuys;
   int Money;
   int numCards; //cards to draw
  Pile DiscardPile = new Pile();
   
   //TODO finish Player class
 
   
   //constructor
  public Player()
   {
      //create a deck of cards
     deck.initializeDeck();
      playersHand = new Hand(deck);
     
   }//end constructor
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #10 - Posted 2011-12-25 00:46:40 »

I don't know anything about Dominion so I don't really have any specific suggestions.

After seeing your Player class I think you're off to a good start.  I was thinking something else for MtG and so you don't need to make Player immutable.

The deck, CardList, and DiscardPile should probably go somewhere else rather than Player.  Perhaps in a global Game instance.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

ctomni231 (37 views)
2014-07-18 06:55:21

Zero Volt (35 views)
2014-07-17 23:47:54

danieldean (28 views)
2014-07-17 23:41:23

MustardPeter (31 views)
2014-07-16 23:30:00

Cero (46 views)
2014-07-16 00:42:17

Riven (47 views)
2014-07-14 18:02:53

OpenGLShaders (36 views)
2014-07-14 16:23:47

Riven (36 views)
2014-07-14 11:51:35

quew8 (32 views)
2014-07-13 13:57:52

SHC (68 views)
2014-07-12 17:50:04
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!