BTW, this is how I want to pass game logic to the entire system:
Code:
// Main.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <time.h>
#include "Game.h"
#include "State_Manager.h"
#include "Menu_State.h"
int _tmain(int argc, _TCHAR* argv[])
{
srand ( unsigned(time(NULL)) );
Card_Game * game = new Card_Game();
game->init();
State_Manager state_manager;
state_manager.change_state( Menu_State::instance(), game );
while ( state_manager.running() )
{
state_manager.update(game);
state_manager.print(game);
state_manager.handle_events(game);
}
game->cleanup();
return 0;
}
As you see I create a pointer to the game logic, and pass it into the state manager so that all the gamestates can use the game logic. I'm thinking that the Card_Game class should hold the functions to draw cards and shuffle the deck and whatnot, and not the player/deck class. I think this because they are methods universal to all card games. I'm thinking that the deck class and player class are more so data objects than classes with actual methods.
I want to be able to go game->draw(player id, hand id, deck id, num cards);
This action would be performed in the Handle_Events functions.
Since the players, hands, and decks are all held in the Card_Game class it would look something like this:
game->draw(game->player_id, game->hand_id, game->deck_id, game->num_cards);
I think I should check if the hand is over 21 in the Update function, it could be a constant check at the end of every event (in the play_game state). I suppose I could move all my state altering checks in the update function.
The main idea of all this fancy state management and passing game logic to the state manager is exactly that, so I can instead pass logic for a holdem game instead of a blackjack game! Talk about modularity!
I'll show some more source code while I'm at it, I'd like to discuss alot of things about my work in progress.
Here is the deck:
Code:
// This header file declares the deck class and all of its functions,
// as well as the card structure.
#ifndef DECK_H
#define DECK_H
#include "Card.h"
#include <vector>
class Deck
{
public:
Deck();
void shuffle_deck();
std::vector<Card> m_cards;
};
#endif
// Deck source code
#include "stdafx.h"
#include "Deck.h"
#include <cassert>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
Deck::Deck()
{
unsigned int x = 0;
unsigned int y = 0;
unsigned int z = 0;
for (y = 0; y < 4; y++)
{
for (x = 0; x < 13; x++)
{
Card c(y,x);
m_cards.push_back(c);
}
}
assert(m_cards.size() == 52);
}
void Deck::shuffle_deck()
{
random_shuffle(m_cards.begin(), m_cards.end());
}
The deck class is pretty self explanatory, I'm thinking the deck should not be shuffling itself but that should be a method of the engine itself, This would make the deck a pure data object (which in reality it is).
And here is the player class:
Code:
#ifndef PLAYER_H
#define PLAYER_H
#include "Deck.h"
#include "Hand.h"
#include <string>
class Hand;
class Player
{
public:
Player(int p_player_id);
void new_hand();
void draw(int hand_index, Deck * deck, int number);
void split_hand(Hand * hand_to_split, Hand * new_hand);
void bet(int bet);
void clear_hand();
std::string & show_hand(int hand_index);
int m_player_id;
int m_cash;
int m_active_hand;
std::vector<int> m_bets;
std::vector<Hand> m_player_hands;
};
#endif
//Player source code
#include "stdafx.h"
#include "Player.h"
#include "Hand.h"
#include <cassert>
Player::Player(int p_player_id)
{
m_player_id = p_player_id;
m_cash = 100;
m_active_hand = 0;
}
void Player::new_hand()
{
Hand new_hand;
m_player_hands.push_back(new_hand);
}
void Player::draw(int hand_index, Deck * deck, int number)
{
for(int loop = 0; loop < number; loop++)
{
/* place card in player's hand */
m_player_hands.at(hand_index).m_card_list.push_back(deck->m_cards.back());
/* hide all dealer cards except for the first one */
if (m_player_id == 0 && loop != 0)
{
m_player_hands[0].m_card_list[loop].flip_card(false);
}
/* remove card from deck */
deck->m_cards.pop_back();
}
}
void Player::split_hand(Hand * hand_to_split, Hand * new_hand)
{
new_hand->m_card_list.push_back(hand_to_split->m_card_list.back());
hand_to_split->m_card_list.pop_back();
}
void Player::clear_hand()
{
for(unsigned int loop = 0; loop < m_player_hands.size(); loop++ )
{
m_player_hands[loop].m_card_list.clear();
}
}
std::string & Player::show_hand(int hand_index)
{
m_player_hands[hand_index].m_hand_string.erase();
if (m_player_id == 0)
{
m_player_hands[hand_index].m_hand_string.append("Dealer's Cards\n");
m_player_hands[hand_index].m_hand_string.append("--------------\n");
}
else if (m_player_id != 0)
{
m_player_hands[hand_index].m_hand_string.append("Player's Cards\n");
m_player_hands[hand_index].m_hand_string.append("--------------\n");
}
for(unsigned int loop = 0; loop < m_player_hands[m_active_hand].m_card_list.size(); loop++)
{
m_player_hands[hand_index].m_hand_string.append(m_player_hands[hand_index].m_card_list[loop].card_name());
m_player_hands[hand_index].m_hand_string.append(" ");
}
m_player_hands[hand_index].m_hand_string.append("\n");
m_player_hands[hand_index].m_hand_string.append("--------------\n\n");
return m_player_hands[hand_index].m_hand_string;
}
void Player::bet(int bet)
{
m_cash -= bet;
m_bets.push_back(bet);
}
The player class is a bit more iffy. As you see I have it containing a vector of hands that the player owns, Should that even be there? I'm thinking that maybe I should manage my hands seperately and just keep the player as a pure data object as well. I'm thinking I should move the draw function into the game engine, as well as the split hand fucntion, as well as pretty much all the functions in the player class.
The game engine could then just keep track of the players as well as their correpsonding hands (it seems that if I kept the hand in the player class that things could be a little more automated, but perhaps less flexible and modular.
Really I have an endless supply of design questions about my card game engine that i pumped out in the last 3 months.