//calculate the heuristic value of a game state with respect to a specific player
		int GameHeuristic( const GameState& game, int forwhom, const int* heuristic ) const 
		{
			int result;
			result = ChangeHeuristic(game.GetPlayerChange( forwhom ), heuristic );

			int best = std::numeric_limits<int>::min();
			for(int i=0;i!=game.GetPlayerCount();++i){
				if (i!=forwhom){
					int score = ChangeHeuristic( game.GetPlayerChange( i ), heuristic );
					if (score>best){
						best = score;
					}
				}
			}			

			return result - best;
		}
		//Get Best Move - 
		//recursive min/max algorithm explores game states and 
		//returns a move and its score, for a specific player
		MoveScore GetBestMove( const GameState& theGame, const int player_index, int abPrune, const int recursive=1)
		{
			const Change& player_change = theGame.GetPlayerChange( theGame.GetCurrentPlayer() );
			const Change& pool = theGame.GetGameChange(); 

			int bestScore = (player_index == theGame.GetCurrentPlayer())?
							std::numeric_limits<int>::min()
							:
							std::numeric_limits<int>::max();

			Coin bestCoin;
			Change bestChange;

			Change::List* someChange;
			if (recycledChangeLists.empty()){
				someChange = new Change::List;
			}
			else{
				someChange = recycledChangeLists.back();
				recycledChangeLists.pop_back();
			}

			//for each coin that can be played
			for (const Coin *ci=&COINLIST[0];ci!=&COINLIST[COIN_COUNT];++ci){				
				if (player_change.GetCount(*ci) > 0){
					
					//get all possible sets of change into array
					GetAllPossibleChange(
						pool,
						*ci, 
						*someChange);

					//for each possible set of change
					//(reversed iteration improves AB prune by as much as 70%)
					const Change::List::reverse_iterator end = someChange->rend();
					for(Change::List::reverse_iterator i = someChange->rbegin();i!=end;++i){
				
						//create "move" from coin to give, and change to take
						const Move myMove(*ci,*i);
						
						//create gamestate once the move has been played
						GameState newGame = theGame.PlayMove( myMove );

						//get "score" for this move
						int score;
						if (recursive>0 && newGame.GetActivePlayers()>1){
							
							//recursivly examine move, get its score
							score = GetBestMove( newGame, player_index, bestScore, recursive-1).score;						
						}
						else{

							//leaf node - just get heuristic value
							score = GameHeuristic( newGame, player_index, myHeuristic );							
						}
					
						//Min/Max search
						if ((player_index == theGame.GetCurrentPlayer() && score > bestScore) ||
							(player_index != theGame.GetCurrentPlayer() && score < bestScore))
						{
							bestScore  = score;
							bestCoin = *ci;
							bestChange = *i;

							//Alpha/Beta pruning
							if ((player_index == theGame.GetCurrentPlayer() && score > abPrune) ||
								(player_index != theGame.GetCurrentPlayer() && score < abPrune)){

								goto exit;

							}

						}
					}
				}
			}

exit:
			recycledChangeLists.push_back( someChange );						
			return MoveScore( Move( bestCoin, bestChange ), bestScore );
		}