#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <string>
using namespace std;

const int NUM_DECKS = 6;
const int SHUFFLE_LOW_WATER = 79;

#define foreach(type, it, container) \
  for (type::iterator it = (container).begin(); it != (container).end(); ++it)

/***** Cards in Blackjack *****/

int card_value(int card_nr) {
	int num = min(((card_nr - 1) % 13) + 1, 10);
	return num == 1 ? 11 : num;
}
struct player_info_t { // All per-player info
	multiset<int> cards;
	union {
		int hidden_card;
		int bet;
	};
	bool blackjack, burst;
	player_info_t(int bet): bet(bet) { blackjack = burst = false; }
	int hand_value() {
		int total = 0, num_aces = 0;
		foreach(multiset<int>, it, cards) {
			int num = card_value(*it);
			if (num == 11)
				++num_aces;
			total += num;
		}
		while (total > 21 && num_aces > 0) {
			--num_aces;
			total -= 10;
		}
		return total;
	}
};
vector<player_info_t> players;

struct card { // An I/O manipulator for printing cards
	card(unsigned int card_nr): card_nr(card_nr) {}
	unsigned int card_nr;
};
const string
card_suits[] = { "Spade", "Heart", "Diamond", "Club", },
card_nums[] = { "A", "2", "3", "4", "5", "6", "7", "8",
		"9", "10", "J", "Q", "K", };
ostream& operator<<(ostream & oss, const card c) {
	if (c.card_nr == 0) {
		oss << "[Face-down]";
	} else if (c.card_nr > 52) {
		oss << "[Unknown]";
	} else {
		int suit = (c.card_nr - 1) / 13;
		int num = (c.card_nr - 1) % 13;
		oss << card_suits[suit] << ' ' << card_nums[num];
	}
	return oss;
}

vector<int> decks;
void reshuffle() {
	decks.clear();
	for (int i = 1; i <= 52; ++i)
		for (int j = 0; j < NUM_DECKS; ++j)
			decks.push_back(i);
	random_shuffle(decks.begin(), decks.end());
}

/***** Blackjack discipline *****/

void get_bets() {
	int bet;
	cout << "Bet? ";
	for (;;) {
		cin >> bet;
		if (cin && bet > 0 && bet <= 200 && bet % 2 == 0)
			break;
		cout << "Invalid bet.  Bet? ";
		cin.clear();
		cin.ignore(1024, '\n');
	}
	players.push_back(player_info_t(bet));
}

void give_initial_cards() {
	cout << "---Game starts---" << endl;
	for (int i = 0; i < 2; ++i)
		for (int p = 0; p < 2; ++p) {
			int c = decks.back();
			decks.pop_back();
			if (p == 0 && i == 0) {
				players[0].hidden_card = c;
				cout << "I get " << card(0) << endl;
			} else {
				players[p].cards.insert(c);
				if (p == 0)
					cout << "I get " << card(c) << endl;
				else
					cout << "You get " << card(c) << endl;
			}
		}
	if (players[0].hand_value()+card_value(players[0].hidden_card) == 21) {
		players[0].blackjack = true;
		cout << "My face down card was "
		     << card(players[0].hidden_card) << endl
		     << "I get Blackjack" << endl;
	}
	for (int p = 1; p < 2; ++p)
		if (players[p].hand_value() == 21) {
			players[p].blackjack = true;
			cout << "You get Blackjack" << endl;
		}
}

void deal_player_cards(int p) {
	while (players[p].hand_value() < 21) {
		cout << "You currently has";
		bool first = true;
		foreach (multiset<int>, it, players[p].cards) {
			cout << (first ? ':' : ',') << ' ' << card(*it);
			first = false;
		}
		cout << endl;
		cout << "Your choice [hit/stand]? ";
		string choice;
		cin >> choice;
		while (choice != "hit" && choice != "stand") {
			cout << "Invalid, please retry: " << endl;
			cin >> choice;
		}
		if (choice == "stand")
			break;
		int c = decks.back();
		decks.pop_back();
		players[p].cards.insert(c);
		cout << "You get " << card(c) << endl;
	}
	int hand_value = players[p].hand_value();
	if (hand_value > 21) {
		players[p].burst = true;
		cout << "You burst" << endl;
	} else {
		cout << "Your hand value is " << players[p].hand_value()
		     << endl;
	}
}

void deal_my_cards() {
	cout << "My face down card was "
	     << card(players[0].hidden_card) << endl;
	players[0].cards.insert(players[0].hidden_card);
	while (players[0].hand_value() <= 16) {
		int c = decks.back();
		decks.pop_back();
		players[0].cards.insert(c);
		cout << "I get " << card(c) << endl;
	}
	if (players[0].hand_value() > 21) {
		players[0].burst = true;
		cout << "I burst" << endl;
	} else {
		cout << "My hand value is " << players[0].hand_value()
		     << endl;
	}
}

void show_results() {
	if (players[0].blackjack) {
		for (int p = 1; p < 2; ++p)
			if (players[p].blackjack)
				cout << "Draw" << endl;
			else
				cout << "You lose " << players[p].bet << endl;
	} else {
		int my_value = players[0].hand_value();
		for (int p = 1; p < 2; ++p)
			if (players[p].blackjack)
				cout << "You win "
				     << (players[p].bet * 3 / 2) << endl;
			else if (players[p].burst)
				cout << "You lose " << players[p].bet << endl;
			else if (players[0].burst)
				cout << "You win " << players[p].bet << endl;
			else {
				int your_value = players[p].hand_value();
				if (my_value > your_value)
					cout << "You lose "
					     << players[p].bet << endl;
				else if (my_value == your_value)
					cout << "Draw" << endl;
				else
					cout << "You win "
					     << players[p].bet << endl;
			}
	}
}

int main() {
	reshuffle();
	for (;;) {
		players.clear();
		players.push_back(player_info_t(0));
		get_bets();
		give_initial_cards();
		if (!players[0].blackjack) {
			for (int p = 1; p < 2; ++p)
				if (!players[p].blackjack)
					deal_player_cards(p);
			for (int p = 1; p < 2; ++p)
				if (!players[p].blackjack
				    && !players[p].burst) {
					deal_my_cards();
					break;
				}
		}
		show_results();
		if (decks.size() < SHUFFLE_LOW_WATER) {
			reshuffle();
			cout << "Note: I've shuffled the cards.\n";
		}
	}
}

