What should be derived, and what should be set in stone?
As usual, I'll start with some code:
Card_Game.h
Code:
#include <vector>
#include "Player.h"
#include "Hand.h"
#include "Deck.h"
#include "Setting.h"
#include "Resource_Manager.h"
class Card_Game
{
public:
Card_Game(){}
~Card_Game(){}
virtual void init(){}
virtual void cleanup(){}
virtual void turn_logic(std::string player_id);
std::vector<std::string> m_vPlayer_List;
int get_setting(std::string name);
protected:
int calculate_winnings();
void new_setting(std::string name, Setting * new_setting);
void initialize_players();
// Give player id a new hand
void give_player_hand(std::string player_id);
void shuffle_deck(int deck_id);
// Draw how_many cards to player id's hand_id from deck_idntyd
void draw_card(std::string player_id, int hand_id, int deck_id, int how_many);
void place_bet(std::string player_id, int bet);
// Split player's active hand
void split_hand(std::string player_id, int hand_id);
// check if hand value > check_value
bool check_hand_value(std::string player_id, int hand_id, int check_value);
Resource_Manager< Player > m_rPlayers;
Resource_Manager< std::vector<Hand*> > m_rHands;
Resource_Manager< int* > m_rBets;
Resource_Manager< Deck* > m_rDecks;
Resource_Manager< Setting > m_rSettings;
std::vector< Deck* > m_vDeck;
};
I was able to derive a card game from this class, Blackjack :D
Code:
#include "Card_Game.h"
#include "Setting.h"
class Blackjack_Game : public Card_Game
{
public:
Blackjack_Game(
{
}
void init()
{
new_setting( "Minimum Bet", new Integer_Setting(25) );
}
virtual void cleanup(){}
virtual void turn_logic(std::string player_id)
{
using namespace std;
int m_result;
while(!(cin >> m_result))
{
cin.clear();
cin.ignore();
}
switch(m_result)
{
case 1:
draw_card(player_id, m_rPlayers.get_resource(player_id).px->m_active_hand, 0, 1);
if(check_hand_value(player_id, m_rPlayers.get_resource(player_id).px->m_active_hand, 21))
{
m_rPlayers.get_resource(player_id).px->m_winner = false;
}
break;
case 2: // stay hand
// while dealer has hand value less than 18
while(check_hand_value("Dealer", 0, 18))
{
draw_card("Dealer", 0, 0, 1); // (for dealer draw to 0 hand, from 0 deck, 1 card)
}
// if the dealer goes over 21
if (check_hand_value("Dealer", 0, 21))
{
// player wins
m_rPlayers.get_resource(player_id).px->m_winner = true;
//state_manager->change_state( Deal_State::instance(), game );
}
// if player's hand value is greater than the dealer's
else if( check_hand_value(player_id, m_rPlayers.get_resource(player_id).px->m_active_hand,
m_rHands.get_resource("Dealer").px->at(0)->point_value()))
{
// player wins
m_rPlayers.get_resource(player_id).px->m_winner = true;
//state_manager->change_state( Deal_State::instance(), game );
}
else
{
// player loses
m_rPlayers.get_resource(player_id).px->m_winner = false;
//state_manager->change_state( Deal_State::instance(), game );
}
break;
case 3: // double down?
/* THIS IS THE RULE */
if (m_rHands.get_resource(player_id).px->at(m_rPlayers.get_resource(player_id).px->m_active_hand)->get_size() == 2)
{
/* THIS IS THE ACTION TO TAKE IF CONDITIONS ARE MET */
//game->m_players[1].bet(game->m_players[1].m_bets[game->m_players[1].m_active_hand]);
draw_card(player_id, m_rPlayers.get_resource(player_id).px->m_active_hand, 0, 1);
if( check_hand_value(player_id, m_rPlayers.get_resource(player_id).px->m_active_hand,
m_rHands.get_resource("Dealer").px->at(0)->point_value()))
{
// player wins
m_rPlayers.get_resource(player_id).px->m_winner = true;
//state_manager->change_state( Deal_State::instance(), game );
}
else
{
// player loses
m_rPlayers.get_resource(player_id).px->m_winner = false;
//state_manager->change_state( Deal_State::instance(), game );
}
}
else { break; }
case 4:// split hand
// make sure we have only 2 cards
/* THIS IS THE RULE*/
if (m_rHands.get_resource(player_id).px->at(m_rPlayers.get_resource(player_id).px->m_active_hand)->get_size() == 2)
{
//if we have two cards, make sure they are the same value
if(m_rHands.get_resource(player_id).px->at(m_rPlayers.get_resource(player_id).px->m_active_hand)->get_card(0) ==
m_rHands.get_resource(player_id).px->at(m_rPlayers.get_resource(player_id).px->m_active_hand)->get_card(1) )
{
/* THIS IS THE ACTION IF CONDITIONS ARE MET */
split_hand(player_id, m_rPlayers.get_resource(player_id).px->m_active_hand);
}
}
break;
case 5: // fold
// player loses
m_rPlayers.get_resource(player_id).px->m_winner = false;
//state_manager->change_state( Deal_State::instance(), game );
break;
default:// invalid entry
std::cout << "Please enter 1 or 2.\n";
break;
}
}
};
And now I'll start listing things I'm unsure of and need some guidance in:
A: Rules, in all card game's there is a set of rules, these limit the players possible actions.
A1: The actions are combinations of simple game mechanics, see the protected items in Card_Game
A2: The turn is the only actual verb function here, where the player performs actions according to the ruleset, this is also why I think that the player should hold the turn function, or perhaps a turn object.
This way we leave the acting part to the player, but the thinking part to the game engine. In all card games a turn may not be played the same way, but the idea of a turn remains the same.
So this leaves us with two undefined, or virtual objects/functions (not sure how to implement these): The actions a player can perform, and the ruleset. This is what I need some help on.
Right now the way I have it setup, the turn is always changing depending on what card game we're playing, I disagree as that all player turns technically are just implementations of possible actions checked by a ruleset.
That is one fat concept to grasp, even for myself. Are there any suggestions to get me started?
For the rules, one concept I read about in the past comes to mind, Functors.