# Dominion card game - how can I take advantage of interfaces?

I'm writing a card game (Dominion) as a pet project. I'm new to C++ but not programming.

A player has a deck, containing the hand and cards in play (tableau). Outside the player, there are piles of cards to buy from (supply piles). I want to display these objects (the hand, tableau and supply piles) on the screen. I had chosen to represent the hand and tableau using std::vector<Card> and the supply piles as std::vector<SupplyPile>. Card and SupplyPile implement an interface for displaying contents to the screen

class IInfo {
public:
virtual std::string Info() const = 0;
virtual std::string ToString() const = 0;
};


I have a class I'm calling View that will take on displaying things to the screen.

class View {
public:
View(const std::vector<IInfo*>& items, int window_starty, int window_startx);
virtual ~View() { }

const IInfo& CurrentItem() const;
const int CurrentIndex() const;
bool IsEmpty() const;
void ItemDown();
void ItemUp();
void SetActive();
void SetInactive();
virtual void Update();
protected:
virtual WINDOW* InitializeWindow(int lines,
int cols,
int starty,
int startx);

private:
// Some constants

const std::vector<IInfo*>& items_;

WINDOW *window_;
};


I now know that C++ doesn't support covariance in templates, so I can't create instances of View with the supply pile, hand, and tableau. How can I redesign the system to maximize DRY? The View class operates on its container member in a very simple way, ripe for abstraction.

## Examples of things I want to do

std::vector<Card> hand = player.hand();
std::vector<Card> tableau = player.tableau();
std::vector<SupplyPile> supply_piles = game.supply_piles();

View hand_view = new View(hand, starty, startx);
View tableau_view = new View(tableau, starty, startx);
View supply_piles_view = new View(supply_piles, starty, startx);


One answer suggested making View into a template, and it almost worked until I remembered that I want to track which View is active at a given time:

View active_ = hand_view;
// Later
active_ = supply_piles_view;


I can't do this with View<Card> and View<SupplyPile>.

## Other code

class Card : public IInfo {
public:
Card(std::string name,
int cost,
int initial_supply,
std::string text,
std::string type);
~Card();

void Play();
std::string Info() const;
std::string ToString() const;

int cost() const;
int initial_supply() const;
std::string name() const;
std::string text() const;
private:
int cost_;
int initial_supply_;

std::string name_;
std::string text_;
std::string type_;

std::string set_;
};

class SupplyPile : public IInfo {

public:
SupplyPile(const Card& card, int initial_count);
SupplyPile(const SupplyPile& other);
virtual ~SupplyPile();
virtual bool operator==(const SupplyPile& other) const;

std::string Info() const;
std::string ToString() const;

const Card& card() const;
int count() const;
std::string name() const;
private:
const Card& card_;

int count_;
};

-
Your question isn't fully clear to me. If you create a std::vector<IInfo*> x; then you can do push_back(new Card(...), push_back(new SupplyPile(...)). Templates aren't covariant, no, so if you have template <typename T> class Foo then Foo<A> and Foo<B> are totally separate types for any A and B (even if B derives from A), but I don't see where that's an issue in any of your code. –  Yuushi Feb 9 '13 at 4:56
Updated with a snippet of code I wanted to write but can't. –  phasetwenty Feb 11 '13 at 19:39

Is there any reason why View itself can't be a template?

template <typename T> class View {
public:
View(const std::vector<T>& items, int window_starty, int window_startx);
virtual ~View() { }

const T& CurrentItem() const;
// ...
const std::vector<T>& items_;
// ...
};

View<Card> hand_view = new View<Card>(hand, starty, startx);

-
This had occurred to me, but I'm not sure if it will work. There is one method that needs to call ToString() on an element of items_. If I can do that, then I should be able to convert to a template. Perhaps a cast is in order? –  phasetwenty Feb 12 '13 at 2:19
Not a problem. items_[0].ToString() etc will work fine. –  Glenn Rogers Feb 12 '13 at 9:26
Still not there. I edited the original question to explain the new problem: I want to be able to track which View is active at a given moment. –  phasetwenty Feb 12 '13 at 20:01
You could derive View<T> from a base class/ interface, so you could maintain a reference to that instead. Or even just have an enumerated constant to represent it. At this point though, you're straying even further from the site remit... –  Glenn Rogers Feb 13 '13 at 11:22

I ended up doing something I don't much like, but it works.

I redesigned View to work with disposable copies of a new interface, IViewable. IViewable will be the link between the UI and the core logic. Every time a UI update is needed, copies of the items to display will be passed as std::vector<IViewable*>.

The new View ctor is:

  View(std::vector<IViewable*> *initial_items, int window_starty, int window_startx)


Updates need a new set of items to display each time, rather than using a reference to the originals like I wanted:

  void Update(std::vector<IViewable*> *items);

-