/******************************************************************************
 *                                                                            *
 * Group2PlayerAR5.java                                                       *
 * Adam M. Rosenzweig                                                         *
 * 10/29/03                                                                   *
 * Fifth Attempt at a Good Player for Generalized Clue                        *
 *   Key Concepts Here:                                                       *
 *     - SIGMA (prob (cards)) == C for each player                            *
 *     - Possible Worlds Approach (simplified/weakened):  The probabilistic   *
 *       logic mechanism is based on the ratio of possible worlds (card       *
 *       configurations) containing the specified card to the total number of *
 *       possible worlds that satisfy the constraints we know.                *
 *     - Storing Probabilities as int / int rather than double                *
 *     - Realization of exactly how little data is inferred in most cases     *
 *         * When most queries contain nearly the entire set of n cards,      *
 *           there is very little information to be gained unless we already  *
 *           know a great deal about what cards the interrogatee has.         *
 *         * If we know the interrogatee has one of the cards in the query,   *
 *           we have no idea if any new information is being transmitted -    *
 *           (b) satisfies (a v b v c v d v e v f v etc etc etc).             *
 *         * So only attempt to infer from other player's queries the cards   *
 *           of the interrogatee if:  1) there are no cards in the query that *
 *           we already know the interrogatee has, and 2) the number of cards *
 *           remaining in the query after we prune out the cards which we     *
 *           know the interrogatee does not have is no more than the number   *
 *           of card slots we have not filled for the interrogatee.           *
 *     - Realization that by scanning over the entire history each time, we   *
 *       can find queries that were too broad in scope to be useful earlier   *
 *       to be of use now, thanks to more recently acquired information.      *
 *****************************************************************************/

package Cluedo.g2;

import Cluedo.*;
import java.awt. *;
import java.util. *;

public class Group2PlayerAR5 implements IFCPlayer {

    private Cluedo gameEngine;
    private int numCards;
    private int numPlayerCards;
    private int numPlayers;
    private int numHidden;
    private double chanceHidden [];
    private int cardsHeld [] [] []; /* 3D Array:  given up on storing
				       other player's knowledge, but now
				       storing data as explicit
				       fractions, so order is:
				       [player] [card] 
				       [numerator/denominator]. */

    private int playerIndex;
    private int round;
    private MoveResult lastMove;
    private Random randomGenerator;
    private int timesGiven [];  /* Used to store how many times each card has
				   been given by us in response to a query.
				   This is used to minimize information given
				   on a query of us. */
    private int slotsFree [];  /* Stores how many card slots we still don't
				  have filled for each player (max C). */
    private int cardsFree [];  /* Stores how many cards we're still unsure of
				  for each player (max N-C). */
    private boolean inferredFrom [];  /* Used to make sure we don't overuse 
					 inferences and screw things up. */

    private int timesAsked [];  /* Stores a histogram of how many times each
				   card has been asked in a query. */
    private boolean histogramRound [];  /* Stores whether or not this round of
					   the history has been added to the
					   histogram. */

    private double GUESS_THRESHOLD;
    private double HISTOGRAM_THRESHOLD;

    private static final int PROBABILITY = 0;
    private static final int HISTOGRAM = 1;
    
    /* Trivial IFCPlayer functions */
    public String name () throws Exception {
	return "It is... Green";
    }
    
    public Color color () throws Exception {
	return new Color (0.0f, 0.85f, 0.0f);
    }

    public boolean interactive () throws Exception {
	return false;
    }

    /* Register function, called by game engine at beginning of a game. */
    public void register (Cluedo __noclue) throws Exception {

	int i;
	int j;
	int k;
	int cardList [];
	int num;
	int denom;
	double temp;

	/* Copy over game values */
	gameEngine = __noclue;
	numCards = gameEngine.numCards ();
	numPlayerCards = gameEngine.numCardsPerPlayer ();
	numPlayers = gameEngine.numPlayers ();
	numHidden = gameEngine.numHiddenCards ();
	playerIndex = gameEngine.indexOf (this);

	/* Initialize arrays */
	chanceHidden = new double [numCards + 1];
	cardsHeld = new int [numPlayers] [numCards + 1] [2];
	timesGiven = new int [numCards + 1];
	slotsFree = new int [numPlayers];
	cardsFree = new int [numPlayers];
	inferredFrom = new boolean [gameEngine.maxRounds () + numPlayers];
	timesAsked = new int [numCards + 1];
	histogramRound = new boolean [gameEngine.maxRounds () + numPlayers];

	/* Calculate the initial values for numerator and denominator
	   probabilities. */
	denom = combination (numCards, numPlayerCards);
	num = combination (numCards - 1, numPlayerCards - 1);

	/* Initialize the array values */
	for (i = 0; i < numPlayers; i++) {
	    slotsFree [i] = numPlayerCards;
	    cardsFree [i] = numCards;
	    for (j = 1; j <= numCards; j++) {
		cardsHeld [i] [j] [0] = num;
		cardsHeld [i] [j] [1] = denom;
	    }
	}

	for (i = 0; i < inferredFrom.length; i++) {
	    inferredFrom [i] = false;
	    histogramRound [i] = false;
	}
	
	timesGiven [0] = Integer.MIN_VALUE;
	timesAsked [0] = 0;
	for (j = 1; j <= numCards; j++) {
	    timesGiven [j] = 0;
	    timesAsked [j] = 0;
	}

	/* Get our cardlist and store the data properly. */
	cardList = gameEngine.getPlayerList (playerIndex, this);
	for (i = 0; i < cardList.length; i++) {
	    setToOne (playerIndex, cardList [i]);
	}

	calculateChanceHidden ();
	randomGenerator = new Random ();

    }

    /* Move function, called by the game engine when it's our turn. */
    public Move move () throws Exception {
	
	int i;
	int count;
	int interrogatee;
	int count2;
	
	/* Update all our data. */
	count2 = 0;
	if (numPlayers > 2) {
	    inferFromHistory ();
	    for (i = 1; i <= numCards; i++) {
		if (timesAsked [i] > HISTOGRAM_THRESHOLD) {
		    count2 += 1;
		}
	    }
	}
     	calculateChanceHidden ();

	/* Determine how many cards we don't know are not hidden - if it's
	   small enough (numHidden), then we should guess now.  If it's not,
	   then we should query another player because we don't have enough
	   information to guarantee a correct guess just yet. */	       
	count = 0;
	for (i = 1; i <= numCards; i++) {
	    if (chanceHidden [i] > GUESS_THRESHOLD) {
		count += 1;
	    }
	}
	
	if ((numPlayers > 2) && (count2 == numHidden)) {
	    return makeGuess (HISTOGRAM);
	}

	else if (count == numHidden) {
	    return makeGuess (PROBABILITY);
	}

	else {
	    interrogatee = selectInterrogatee ();
	    return selectQuery (interrogatee);
	}
	
    }

    /* Question function, called by the game engine when somebody asks us
       a question and we have to answer it.  If we have any of the cards in
       the query we must return one of them, but we can choose which one.  Our
       method for choosing is to keep track of how many times we've returned
       each card in answer to a question and try to return the ones that we've
       given the most already.  If we don't have any of the cards, we return
       0. */
    public int question (int interrogator, int [] cardlist) throws Exception {

	int i;
	boolean canGive [];
	int mostGiven;

	canGive = new boolean [numCards + 1];
	for (i = 1; i <= numCards; i++) {
	    canGive [i] = false;
	}

	/* If we both have a card, AND the interrogator asked about the card,
	   then set canGive [that card] to true. */
	for (i = 0; i < cardlist.length; i++) {
	    if ((cardsHeld [playerIndex] [cardlist [i]] [0] == 0) &&
		(cardsHeld [playerIndex] [cardlist [i]] [1] == 1)) {
		canGive [cardlist [i]] = true;
	    }
	}

	/* Find out if there are any cards we can give, and if so, select the
	   one that we have previously given the most times. */
	mostGiven = 0;
	for (i = 1; i <= numCards; i++) {
	    if (canGive [i] && (timesGiven [i]  >= timesGiven [mostGiven])) {
		mostGiven = i;
	    }
	    else if (canGive [i] && 
		     (timesGiven [i] == timesGiven [mostGiven]) &&
		     (randomGenerator.nextInt (2) == 1)) {
		mostGiven = i;
	    }
	}
	/* If we did find one, increment the number of times we (are about to)
	   have given that card in response.  In fact, we can increment even
	   if we didn't find a card, because we set timesGiven [0] to
	   Integer.MIN_VALUE, and there is no way a game will run long enough
	   for us to give negative responses that many times. */
	/* Return the card, which will be 0 if we didn't find any */
	return mostGiven;
	
    }

    /* Answer function, called by the game engine when somebody responds to
       our query.  If the answer is 0, we can mark down that the interrogatee
       does not have the cards.  If the answer is a card, we mark down that
       the interrogatee has the card and that nobody else has it.  We also
       appropriately adjust the probabilities that each player has other cards
       based on the data we did gain. */
    public void answer (int interrogatee, int [] mycardlist, int response) throws Exception {

	int i;

	if (response == 0) {
	    for (i = 0; i < mycardlist.length; i++) {
		if (cardsHeld [interrogatee] [mycardlist [i]] [0] != 0) {
		    setToZero (interrogatee, mycardlist [i]);
		}
	    }
	}

	else {
	    setToOne (interrogatee, response);
	}
	
    }

    /* Function called by the game engine when we have no choice but to guess -
       if the time limit has run out or there is nobody left in the game but
       us. */
    public int [] forcedGuess () throws Exception {

	int cardList [];
	int i;
	int j;

	/* For now, we'll fill up our forcedGuess with the first k cards that
	   we don't know are hidden.  Hopefully we'll only be forced to guess
	   in situations where by then we have full knowledge from other
	   players having been forced to guess before us.  Really we should
	   be filling it in the the highest probability of being hidden cards,
	   but this is simpler and we hope to avoid this situation entirely. */
	calculateChanceHidden ();

	cardList = new int [numHidden];

	j = 0;
	for (i = 1; i <= numCards; i++) {
	    if (chanceHidden [i] != 0.0) {
		cardList [j] = i;
		j += 1;
		if (j == numHidden) {
		    break;
		}
	    }
	}

	return cardList;

    }

    /* Function called by the game engine when a player leaves the game, either
       due to guessing or due to being booted for an invalid move (such as
       giving an incorrect response to a query about his cards).  Allows us
       access to all of his cards. */
    public void notifyPlayerExit (int playerexited) throws Exception {

	int i;
	int cardList [];

	cardList = gameEngine.getPlayerList (playerexited, null);
	for (i = 0; i < cardList.length; i++) {
	    setToOne (playerexited, cardList [i]);
	}

    }
    
    /* End of IFCPlayer functions, beginning of private functions. */

    /* Function called when we discover that a player definitely HAS this one
       card.  Sets the probability of that card to 1, sets the probability of
       other players having that card to 0, and propagates the relevant
       changes in probabilities.  Also checks if we know C cards that are
       possessed by that player, and if so, makes sure that we have all other
       probabilities for that player set to 0. */
    private void setToOne (int player, int card) throws Exception {

	int i;
	int oldnum;
	int overlap;

	oldnum = cardsHeld [player] [card] [0];
	if (slotsFree [player] == 1) {
	    oldnum = 0;
	}
	
	for (i = 1; i <= numCards; i++) {
	    if ((i != card) && (cardsHeld [player] [i] [0] != 0)) {
		/* What to set the numerator to?  Needs to be set to the 
		   number of card configurations that contain both it and
		   the confirmed card.  How to calculate this overlap? */
		overlap = calculateOverlap (player, card, i);
		cardsHeld [player] [i] [0] = overlap;
		cardsHeld [player] [i] [1] = oldnum;
	    }
	}
	
    	slotsFree [player] -= 1;
	cardsFree [player] -= 1;
	if (slotsFree [player] == 0) {
	    cardsFree [player] = 0;
	}

	cardsHeld [player] [card] [0] = 0;
	cardsHeld [player] [card] [1] = 1;
	
	for (i = 0; i < numPlayers; i++) {
	    if (i != player) {
		setToZero (i, card);
	    }
	}

	timesAsked [card] = 0;
	    
    }

    /* Function called when we discover that a player definitely does NOT
       have a particular card.  Sets the probability of that card to 0, and
       propagates the change in probability across the player's card list. */
    private void setToZero (int player, int card) throws Exception {

	if ((cardsHeld [player] [card] [0] == 0) &&
	    (cardsHeld [player] [card] [1] == 0)) {
	    return;
	}

	int i;
	int oldnum;
	int overlap;
	
	oldnum = cardsHeld [player] [card] [0];
	
	for (i = 1; i <= numCards; i++) {
	    if ((i != card) && (cardsHeld [player] [i] [0] != 0)) {
		/* What to set the numerator to?  Needs to be decreased by the
		   number of card configurations that contain both it and the
		   eliminated card.  But how to calculate this overlap? */
		overlap = calculateOverlap (player, card, i);
		cardsHeld [player] [i] [0] -= overlap;
		cardsHeld [player] [i] [1] -= oldnum;
	    }
	}

	cardsHeld [player] [card] [0] = 0;
	cardsHeld [player] [card] [1] = 0;

	cardsFree [player] -= 1;

	if (cardsFree [player] == slotsFree [player]) {
	    for (i = 1; i <= numCards; i++) {
		if ((cardsHeld [player] [i] [0] != 0) &&
		    ((cardsHeld [player] [i] [1] != 1) && 
		     (cardsHeld [player] [i] [1] != 0))) {
		    setToOne (player, i);
		}
	    }
	}

    }

    /* Calculates the chance that each card is hidden, by summing up the
       total probability that each player has each card, and subtracting that
       from 1.0. */
    private void calculateChanceHidden () throws Exception {

	int i;
	int j;
	double temp;
	
	temp = 0;
	for (i = 1; i <= numCards; i++) {
	    chanceHidden [i] = 1.0;
	    for (j = 0; j < numPlayers; j++) {
		if (cardsHeld [j] [i] [0] == 0) {
		    chanceHidden [i] -= (double) cardsHeld [j] [i] [1];
		}
		else {
		    chanceHidden [i] -= (double) cardsHeld [j] [i] [0] /
			(double) cardsHeld [j] [i] [1];
		}
	    }
	    temp += chanceHidden [i];
	}
	GUESS_THRESHOLD = temp / (1.5 * numCards);

    }

    /* Function used to gather all the information we can from the queries of
       other players.  Currently relies on gathering information that can be
       considered highly useful.  Thus, any negative response is considered
       a valid one to gather, because the information is guaranteed.
       However, in the case of a positive response, it is not worth recording
       unless there are actually very few items that could have been the
       actual response. */
    private void inferFromHistory () throws Exception {

	int index;
	int i;
	int j;
	int a;
	int overlap;
	MoveResult history;
	boolean worthIt;
	boolean divide;

	round = gameEngine.currRound ();
	
	/* Iterate through each round since our last move. */
	for (index = 1; index < round; index++) {
	    history = gameEngine.history (index);
	    if (!histogramRound [index] && (history.type == _CINTERROGATION) &&
		(history.player!= playerIndex)) {
		for (i = 0; i < history.cardlist.length; i++) {
		    if (timesAsked [history.cardlist [i]] != 0) {
		    timesAsked [history.cardlist [i]] += 1;
		    }
		}
		histogramRound [index] = true;
	    }
	    /* We only care about interrogations, and we only care about
	       them if they didn't involve us at all, because we handled when
	       we asked the question, and we already have full knowledge of our
	       own hand. */
	    if ((history.player != playerIndex) && 
		(history.type == _CINTERROGATION) && 
		(history.interrogatee != playerIndex)) {
		/* If the response was to show a card... Determine how much we
		   can actually gain from this interrogation:  if there are
		   any cards in the ask list that WE ALREADY KNOW that the
		   interrogatee has, we really gain no information.  Depending
		   on how much of the ask list we know the interrogatee does
		   NOT have, it may be worth making an inference. */
		if (history.response == true) {
		    worthIt = true;
		    a = history.cardlist.length;
		    for (i = 0; i < history.cardlist.length; i++) {
			if ((cardsHeld [history.interrogatee]
			    [history.cardlist [i]] [0] == 0) &&
			    (cardsHeld [history.interrogatee]
			     [history.cardlist [i]] [1] == 1)) {
			    worthIt = false;
			    break;
			}
			else if ((cardsHeld [history.interrogatee]
				  [history.cardlist [i]] [0] == 0) &&
				 (cardsHeld [history.interrogatee]
				  [history.cardlist [i]] [1] == 0)) {
			    a -= 1;
			}
		    }
		    /* For now, only take inferences we can narrow down to
		       one card and one card alone. */
		    if (worthIt && (a == 1)) {
			for (i = 0; i < history.cardlist.length; i++) {
			    if (cardsHeld [history.interrogatee]
				[history.cardlist [i]] [0] != 0) {
				setToOne (history.interrogatee, 
					  history.cardlist [i]);
				break;
			    }
			}
			inferredFrom [index] = true;
		    }
		    /* So, now that we've found a (hopefully) adequate
		       approximation of the exact math of the possible worlds
		       theory, we can infer on larger sets than when we can
		       determine exactly which card.  But still, a sufficiently
		       small set of cards leftover after we exclude all the
		       cards that we know they don't have is useful for an
		       inference.  As a threshold, we choose the size of the
		       culled list to be the number of card slots we haven't
		       already filled up for that player. */
		    else if (worthIt && 
			     (a <= 4 * slotsFree [history.interrogatee]) && 
			     (a > 0) && 
			     (!inferredFrom [index])) {
			overlap = 0;
			for (i = 0; i < history.cardlist.length; i++) {
			    for (j = i + 1; j < history.cardlist.length; j++) {
				if ((cardsHeld [history.interrogatee]
				     [history.cardlist [i]] [0] != 0) &&
				    (cardsHeld [history.interrogatee]
				     [history.cardlist [j]] [0] != 0)) {
				    overlap += calculateOverlap 
					(history.interrogatee,
					 history.cardlist [i],
					 history.cardlist [j]);
				}
			    }
			}
			/* Subtract off the overlap of the overlaps.  This
			   is most likely a relatively poor approximation. */
			overlap -= slotsFree [history.interrogatee] + a - 5;
			for (i = 1; i <= numCards; i++) {
			    divide = true;
			    for (j = 0; j < history.cardlist.length; j++) {
				if (cardsHeld [history.interrogatee] 
				    [history.cardlist [j]] [0] != 0) {
				    divide = false;
				    break;
				}
			    }
			    if (cardsHeld [history.interrogatee] [i] 
				[0] != 0) {
				cardsHeld [history.interrogatee] [i] 
				    [1] = overlap;
				if (divide) {
				    cardsHeld [history.interrogatee] [i] 
					[0] /= slotsFree 
					[history.interrogatee];
				}
			    }
			}
			inferredFrom [index] = true;
		    } 
		}
		/* Otherwise, we know the interrogatee didn't have the cards */
		else {
		    /* For each card in the ask list, invoke the setToZero
		       function to record the fact that he does not have those
		       cards. */
		    if (!inferredFrom [index]) {
			for (i = 0; i < history.cardlist.length; i++) {
			    setToZero (history.interrogatee, 
				       history.cardlist [i]);
			}
			inferredFrom [index] = true;
		    }
		}
	    }
	}
	
	HISTOGRAM_THRESHOLD = 0.0;
	for (i = 1; i <= numCards; i++) {
	    HISTOGRAM_THRESHOLD += timesAsked [i];
	}
	HISTOGRAM_THRESHOLD /= (0.5 * numCards);
	
    }
    
    /* Calculates Combination of the two parameters. */
    private int combination (int n, int r) {
	int i;
	int a;
	int c;
	a = n - r;
	c = 1;
	for (i = a + 1; i <= n; i++) {
	    c *= i;
	}
	for (i = 2; i <= r; i++) {
	    c /= i;
	}
	return c;
    }

    /* Calculates the amount by which the set of possible card configurations
       for player that contain card1 overlaps with the set of possible card
       configurations for player that contain card2. */
    private int calculateOverlap (int player, int card1, int card2) throws Exception {
	/* Not in any way perfect, but adequate for now - should correctly
	   model for all deterministic cases, still need to handle the math
	   for the cases where we've made inferences such as p1:  (4 v 5), and
	   not all probabilities are 0, 1, or the same value. */
	if (slotsFree [player] <= 1) {
	    return 0;
	}
	int i;
	int overlap;
	/*overlap = 1;
	for (i = 2; i < slotsFree [player]; i++) {
	    overlap *= cardsFree [player] - i;
	    if (i > 2) {
		overlap /= i - 2;
	    }
	    }*/
	overlap = combination (cardsFree [player] - 2, slotsFree [player] - 2);
	if (overlap > cardsHeld [player] [card1] [0]) {
	    overlap = cardsHeld [player] [card1] [0];
	}
	if (overlap > cardsHeld [player] [card2] [0]) {
	    overlap = cardsHeld [player] [card2] [0];
	}
	return overlap;
    }

    /* This function determines the cards we are going to guess.  Fortunately
       for coding this, it will only be called when we only have K cards left
       that we haven't found out are definitely not hidden (i.e. haven't found
       out who they belong to).  This makes the function trivially easy. */
    private Move makeGuess (int type) throws Exception {
	
	int i;
	int j;
	int cardList [];
	Move theMove;

	cardList = new int [numHidden];
	j = 0;
	for (i = 1; i <= numCards; i++) {
	    if (((type == PROBABILITY) && 
		(chanceHidden [i] > GUESS_THRESHOLD)) ||
		((type == HISTOGRAM) && 
		 (timesAsked [i] > HISTOGRAM_THRESHOLD))) {
		cardList [j] = i;
		j += 1;
	    }
	}

	theMove = new Move (_CGUESS, cardList);
	return theMove;
	
    }

    /* This function is used to determine who we should interrogate about what
       cards they are holding.  For now it functions by selecting the player
       about whom we have the smallest amount of certain information.  In the
       case of multiple players about whom we have the same amount of 
       information, we select the last one of them in the list. */
    private int selectInterrogatee () throws Exception {
	
	int i;
	int j;
	int count;
	int bestCount;
	int bestIndex;
	int bonus;
	int bestBonus;
	
	bestIndex = 0;
	bestBonus = 0;
	for (i = 1; i < numPlayers; i++) {
	    bonus = 0;
	    if ((i > playerIndex) && (slotsFree [i] + cardsFree [i]) > 0) {
		bonus = 1;
	    }
	    if (slotsFree [i] + cardsFree [i] + bonus > slotsFree [bestIndex] +
		cardsFree [bestIndex] + bestBonus) {
		bestIndex = i;
	    }
	    else if ((slotsFree [i] + cardsFree [i] + bonus == 
		      slotsFree [bestIndex] + cardsFree [bestIndex] + 
		      bestBonus) && (randomGenerator.nextInt (2) == 1)) {
		bestIndex = i;
		bestBonus = bonus;
	    }
	}

	return bestIndex;
	
    }

    /* This function selects the cards that we will be asking the interrogatee
       which it has been provided about.  It asks a large list of cards, making
       sure to eliminate those cards which we already know that player has, 
       and in addition, also eliminating a set of random cards. */
    private Move selectQuery (int interrogatee) throws Exception {

	int i;
	int j;
	int k;
	int card;
	int omitList [];
	int cardList [];
	Move theMove;
	boolean good;
	int count;
	int count2;
	double temp;

	if (numPlayerCards == 1) {
	    cardList = new int [numCards];
	    for (i = 0; i < numCards; i++) {
		cardList [i] = i + 1;
	    }
	    theMove = new Move (_CINTERROGATION, cardList, interrogatee);
	    return theMove;
	}

	temp = 0;
	for (i = 1; i <= numCards; i++) {
	    if (cardsHeld [interrogatee] [i] [0] == 0) {
		temp += (double) cardsHeld [interrogatee] [i] [1];
	    }
	    else {
		temp += (double) cardsHeld [interrogatee] [i] [0] /
		    (double) cardsHeld [interrogatee] [i] [1];
	    }
	}
	temp /= (1.5 * numCards);

	count = 0;
	for (i = 1; i <= numCards; i++) {
	    if (((cardsHeld [interrogatee] [i] [0] == 0) &&
		(cardsHeld [interrogatee] [i] [1] == 1)) ||
		((cardsHeld [interrogatee] [i] [0] != 0) &&
		 ((double) cardsHeld [interrogatee] [i] [0] / 
		 (double) cardsHeld [interrogatee] [i] [1] >
		 temp))) {
		count += 1;
	    }
	}

	/*count2 = 0;
	for (i = 1; i <= numCards; i++) {
	    if  (((cardsHeld [interrogatee] [i] [0] == 0) && 
		  (cardsHeld [interrogatee] [i] [1] == 0)) ||
		 ((double) cardsHeld [interrogatee] [i] [0] /
		  (double) cardsHeld [interrogatee] [i] [1] <=
		  temp)) {
		count2 += 1;
	    }
	    }*/
	count2 = numCards - count;

	omitList = new int [count + slotsFree [interrogatee] - 1];

	j = 0;
	for (i = 1; i <= numCards; i++) {
	    if (((cardsHeld [interrogatee] [i] [0] == 0) &&
		(cardsHeld [interrogatee] [i] [1] == 1)) ||
		(/*(randomGenerator.nextInt (2) == 0) && */
		 (cardsHeld [interrogatee] [i] [0] != 0) &&
		 ((double) cardsHeld [interrogatee] [i] [0] / 
		 (double) cardsHeld [interrogatee] [i] [1] > 
		 temp))) {
		omitList [j] = i;
		j += 1;
	    }
	}

	for (; j < omitList.length;) {
	    card = randomGenerator.nextInt (numCards) + 1;
	    good = true;
	    for (k = 0; k < j; k++) {
		if (omitList [k] == card) {
		    good = false;
		    break;
		}
	    }
	    if (good /*&& (((cardsHeld [interrogatee] [card] [0] == 0) && 
			  (cardsHeld [interrogatee] [card] [1] == 0)) ||
			 ((double) cardsHeld [interrogatee] [card] [0] /
			  (double) cardsHeld [interrogatee] [card] [1] <=
			  temp))*/) {
		omitList [j] = card;
		j += 1;
	    }
	}

	Arrays.sort (omitList);

	cardList = new int [numCards - omitList.length];
	j = 0;
	for (i = 1; i <= numCards; i++) {
	    good = true;
	    for (k = 0; k < omitList.length; k++) {
		if (omitList [k] == i) {
		    good = false;
		    break;
		}
	    }
	    if (good) {
		cardList [j] = i;
		j += 1;
	    }
	}

	theMove = new Move (_CINTERROGATION, cardList, interrogatee);
	
	return theMove;
	
    }

}
