#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <cstdio>
#include <vector>
#define DECK_NO 1

// Type , Const , Global definition 
using namespace std;
const int _TCARD=DECK_NO*52;


typedef struct DECK{
        int list[_TCARD];
		bool used[_TCARD];
		int left[13];
		int total;
		} DECK;


typedef struct HAND{
        int card[5];
        int n;
		bool bust;     // Indicate whether this hand exceeds 21
		int mval,no_a;
        } HAND;

int money=100,bet=0, play=1;  // Initially, the player play 1 hand.
HAND hand[5]; // At most 5 hands per round if the player get 4 equal cards and split them.
DECK deck; // deck for this game

int known[13],try_card[5]; // Use for AI

//functions

        void initialize();
        void init2();
        void AI_DRAW_DECK(HAND&);
        void give_card(HAND&,int n);    // give cards to player's i-th hand
		void call_dealer(); // let the dealer to draw cards 
		void get_amount(int&);
        void show(HAND&,int);       // Display a given hand with a bool representing a player or a computer
		bool chk_split(HAND& k) {return k.card[0]/4==k.card[1]/4;}
        string card_name(int i);
        int value(int i){ int k=(i/4+1); return (k<10)?k:10;}
        void swap(int& x,int &y) {
             x^=y;
             y^=x;
             x^=y;
             return ;
             }
        bool chk_letter(string k, int n=2){
             string LETTER[4]={"Y","y","N","n"};
             int i;
             for (i=0;i<2*n;++i) if (k==LETTER[i]) return true;
             if (n==0) for (i=2;i<4;++i) if (k==LETTER[i]) return true;
             return false;
             }
        
        
        // draw a card from a given DECK d
           
          int draw(DECK& d){
              int t=d.list[d.total];
              d.used[t]=true;
              --d.left[t/4];
              ++d.total;
              return t;
                            }		

// main        
        int main(){
            string c;
            int i,j,k;
        initialize();
      
        do{									  // start of do-while , the main loop for each round
			init2();
			i=j=0;
			cout<<"Player :$"<<money<<endl;
			cout<<"Pay for this round? (1-"<<money<<"): $";
			get_amount(bet);
			money-=bet;
            
			for (i=0;i<2;++i) // give 1 card for each hand and then give the second card for each hand
			for (j=0;j<2;++j) {
                	hand[j].card[i]=draw(deck);
                    ++hand[j].n;
                    }
            for (i=0;i<2;++i) show(hand[i],i);
                       
         
            for (i=1;i<=play;++i)
            for (j=1;j<=i;++j)
            if (bet<=money && chk_split(hand[j])){
                  cout<<"Split? (Y/N) :"; 
                  while (cin>>c && !chk_letter(c)) cout<<"Re-enter : Split? (Y/N) :";
                  if(chk_letter(c,1)) {
                    ++play;
                    money-=bet;
                    for(k=0;k<2;++k) {hand[play].card[k]=draw(deck);++hand[play].n;}
                    swap(hand[play].card[0],hand[j].card[1]);
                    cout<<endl;
                    for(k=0;k<=play;++k) show(hand[k],k);
                    
                                       }
                  else goto OUT;
                           }
            
            OUT:

            for(i=0;i<=play;++i){
            for(j=0;j<hand[i].n;++j) {
            hand[i].mval+=value(hand[i].card[j]);
            if (hand[i].card[j]<4) ++hand[i].no_a;
            }
//            cout<<hand[i].mval<<":"<<hand[i].no_a<<endl;
            }

            for(i=1;i<=play;++i) give_card(hand[i],i);


//          To maximize deck value with A's
            for(i=1;i<=play;++i) 
            if (hand[i].no_a>0 && hand[i].mval<=11)  hand[i].mval+=10;
            
            AI_DRAW_DECK(hand[0]);
			if (hand[0].no_a>0 && hand[0].mval<=11)  hand[0].mval+=10;
            
            cout << "Final Result :"<<endl;
            cout << "Dealer :";
            for (j=0;j<hand[0].n;++j) cout<<" "<<card_name(hand[0].card[j]);
            cout <<" = "<<hand[0].mval;
            if (hand[0].bust) cout<<" Busted !";
            cout<<endl;
                                                       
            for (i=1;i<=play;++i) 
                {
                cout<<"Player's deck "<<i<<" :";
                for (j=0;j<hand[i].n;++j) cout<<" "<<card_name(hand[i].card[j]);
                if (hand[i].bust) cout<<" Busted!"<<endl;
                else {
                     cout<<" = "<<hand[i].mval<<endl;
                     if (hand[i].mval>hand[0].mval || hand[0].bust)
                     { cout<<" Win!"<<endl;
                       money+=2*bet;
                     }
                     else cout<<" Lost..."<<endl;
                     }
                }      // end of for loop
                
            if (money) {
                       cout<<"Again? (Y/N):";
                       while (cin>>c && !chk_letter(c)) cout<<"Re-enter : Again? (Y/N) :";
                       
                       }
			cout<<endl;
		}
		while (money && chk_letter(c,1));   // end of do-while
        cout<<"You have $"<<money<<" left."<<endl;
        cin.get();
//        cin.get();
        return 0;
        }    
// end of main


        
        void init2(){
             int i,j;
             i=0;
             play=1;
             deck.total=0;
             for (i=0;i<13;++i) deck.left[i]=4;
			 for (i=0;i<_TCARD;++i) deck.used[i]=false;
             for (i=0;i<5;++i) {
             for (j=0;j<5;++j)hand[i].card[j]=0;
             hand[i].n=0;
             hand[i].mval=0;
             hand[i].no_a=0;
             hand[i].bust=false;
             }
             
             for (i=0;i<_TCARD;++i) deck.list[i]=i;
             /*deck.list[0]=4;
             deck.list[2]=5;
             deck.list[4]=0;
             deck.list[5]=2;
             */
             for (i=0;i<_TCARD;++i)
             for (j=0;j<_TCARD-1-i;++j)
                  if (rand()%100>=25) swap(deck.list[j],deck.list[j+1]);
                 
                 
             /*for (i=0;i<_TCARD;++i) {
                 cout<<card_name(deck.list[i]);
                 if (i%5==4) cout<<endl; else cout<<",";
                 }
             cout<<endl;             
			 */
             }
             
             
             
        void initialize() {
                srand(time(0));  // initialize random number generator
//				init2();             

             }
        
       
		void get_amount(int& i){
			do {cin>>bet; cin.get();            
				if (bet>money || bet<1) {
					cout<<"Wrong Amount!"<<endl;
					cout<<"Re-enter (1-"<<money<<") :";
				    }
				    
                }
			while (bet>money || bet<1);
			
      		}

        void show(HAND& h,int z) {
             int i,j;
             i=j=0;
               
               if (!z) cout<<"Dealer : * ";
               else cout<<"Player Hand("<<z<<") : "<<card_name(h.card[0]);
             for(i=1;i<h.n;++i) cout<<" "<<card_name(h.card[i]);
//             for(i=0;i<h.no_a;++i) if (mval<=11)
             if (h.bust) cout<<" Busted!";
             cout<<endl;
             return ;
             }
        
        string card_name(int n){
              const string S("A23456789_JQK");
              const string ICON("DCHS");
              string c;
              int no=n/4,face=n%4;
              if (no!=9) c+=S[no]; else c+="10";
              c+=ICON[face];
              return c;
              }

        void give_card(HAND& d, int z){
             int i=0,j=0,&n=d.n;
             string s;
             int &sum=d.mval;
             while (!d.bust && n<5){
                   cout<<"Draw for Hand("<<z<<")? (Y/N) : ";
                   do {cin>>s;} while (!chk_letter(s));
                   cout<<endl;
                   if (chk_letter(s,0)) break;
                   d.card[n]=draw(deck);
                   //sum+=1+value(d.card[n]);
				   sum+=value(d.card[n]);
                   if(d.card[n++]<4) ++d.no_a;
                   if (sum>21) d.bust=true; 
                   cout<<endl;
                   for (i=0;i<=play;++i) show(hand[i],i);
                         
                   }
                        
             
             }


             // The function chk_win Return Absolute winning number as the tenth digit and Possible winning number as the unit digit
             // As we can't know the first card of each hand unless it was already busted.
             // But the minimum value of a card is 1 so it is natural to assume the card is A.
			 // However, if the value is far too small, which a smart or nomarl player will definitely lose
			 // We assume the value to be 18, the most common value occured in BlackJack.
			 // Also we may determine the hidden card with the given known card.


        int chk_win(int VAL){
            int z=0,test;
//			int temp[13];
//			for(int k=0;k<13;++k) temp[k]=known[k];

            for(int i=1;i<=play;++i) {
					test=value(try_card[i])+hand[i].mval-value(hand[i].card[0]);
			        if (test<16) test=18;
				z+=(VAL>=test);
			}
           
			return z;
            }             

             
        void AI_DRAW_DECK(HAND& h){
             int NOW[2];
             int &n=h.n;
             bool ACE;                          
             int i,j;
			 int visual[5];
			 vector <int> gseq;
             bool draw_again;
             int won=0;

			 
			 for (i=0;i<5;++i) try_card[i]=0;
             for (i=0;i<13;++i) known[i]=4;
             // Count for the known drawn card , So start counting from the second card.
             for (i=1;i<=play;++i) 
				{
				 if (hand[i].bust) ++won;
				 for (j=1-hand[i].bust;j<hand[i].n;++j) --known[hand[i].card[j]/4];
				}

			 for (i=1;i<=play;++i) visual[i]=hand[i].mval-value(hand[i].card[0]);


             cout<<"Dealer's Turn:"<<endl;
			 if (won==play){
				 cout<<"Dealer already won."<<endl;
				 return ;
			 }

             cout<<"Guesting your hidden cards..."<<endl;


			 //Find the maximum visible value first
			 for (i=0;i<52;++i) 
				 for (j=1;j<=play;++j)
				 if (visual[j]==i) gseq.push_back(j);
			 
			 //Guest the hidden card of each hand starting from the max. hand first
			 for(i=0;i<play;++i){ 
				 if (hand[gseq[i]].bust) continue;
			 for(j=0;j<13;++j) 
				 if (known[gseq[i]])
					 if (visual[gseq[i]]+value(j*4)>=18 && visual[gseq[i]]+value(j*4)<=21)
					 {try_card[gseq[i]]=value(j*4);
					  --known[j];
					 }
			 }

			 cout<<"Finish guesting your cards"<<endl;
			 cout<<endl;
             do {

                 NOW[0]=h.mval;
                 ACE=h.no_a!=0;   
				 if (ACE && NOW[0]<=11) NOW[1]=NOW[0]+10;                       
				 else NOW[1]=NOW[0];

                 //Decision rules (1): Dealer must draw until the hand >=17
                 //Decision rules (2): Draw cards if dealer can't win any hands.
                 //                    As it is the same as the case that the dealer bust
				 //Decision rules (3): If there is not net lose then stop drawing


                 if (NOW[1]<17) draw_again=true; 
					else if (chk_win(NOW[1])==0) draw_again=true; 
					else if (2*won>=play) draw_again=false;   
					else
					draw_again=false;

				 
                 
                 
				 if (NOW[0]==21 || NOW[1]==21) draw_again=false;                 
                 if (draw_again) {
								 cout<<"Dealer Draw Card..."<<endl;
								 cout<<endl;
                                 h.card[n]=draw(deck);
                                 --known[h.card[n]/4];
								 if (h.card[n]/4==0) ++h.no_a;
                                 h.mval+=value(h.card[n++]);
								 }
                 h.bust=h.mval>21;
                 }
             while (n<5 && !h.bust && draw_again);
             
             
             }



