/*
 * Created on Oct 19, 2003
 */
package Cluedo.g6;

import java.util.*;

import java.awt.*;
import java.io.*;

import Cluedo.*;

/**
 * @author Vladislav Shchogolev
 * @author Yaniv Schiller
 * @author Miqdad Mohammed
 */
public class Group6Player0 implements IFCPlayer {

	private Cluedo mClue;
	private ClueLogic mLogic;
	private int mCards[];
	private int mRandomOrder[];
	private int mShownCounter[];
	private int mIndex;
	private int mLastRound;
	private Random rg;
	public static final boolean DEBUG = true;
	//public static PrintWriter log;
	
	public void register(Cluedo iClue) throws Exception {
		this.rg = new Random(System.currentTimeMillis());
		this.mClue = iClue;
		this.mIndex = mClue.indexOf(this);
		this.mCards = mClue.getPlayerList(mIndex, this);
		this.mRandomOrder = new int[mCards.length];
		this.mShownCounter = new int[mCards.length];

		//log = new PrintWriter(new FileOutputStream("log.txt"));
		
		for (int i = 0; i < mRandomOrder.length; i++)
			mRandomOrder[i] = i;
		for (int i = 0; i < mRandomOrder.length; i++) {
			int r = rg.nextInt(mRandomOrder.length);
			int tmp = mRandomOrder[i];
			mRandomOrder[i] = mRandomOrder[r];
			mRandomOrder[r] = tmp;
		}

		this.mLogic = new ClueLogic(mClue);
		this.mLastRound = -1;

		// assert the cards we have
		// not the most efficient...
		for (int i = 1; i <= mClue.numCards(); i++) {
			boolean found = false;
			for (int j = 0; j < mCards.length; j++) {
				if (mCards[j] == i) {
					found = true;
					break;
				}
			}
			if (found) {
				mLogic.assertHasCard(mIndex, i);
			} else {
				mLogic.assertLacksCard(mIndex, i);
			}
		}
		
	}

	/**
	 * Return a Move object to the mediator
	 *  
	 */
	public Move move() throws Exception {
		int p = mClue.numPlayers();
		int c = mClue.numCardsPerPlayer();

//		log.print("\n\n>>>>>MOVE\n\n");
		analyzeMoves();
//		log.println("--------- after AM ------------");
//		log.print(mLogic);
//		log.flush();
		
		// brute force algorithm

		// go through players in order of how little we know about the,
		int pknowledge[] = new int[p];
		int pknowledgeindexes[] = new int[p];

		int randomLocations[] = new int[p];
		for (int i = 0; i < p; i++)
			randomLocations[i] = i;

		for (int i = 0; i < p; i++) {
			int randomPosition = rg.nextInt(p);
			int tmp = randomLocations[i];
			randomLocations[i] = randomLocations[randomPosition];
			randomLocations[randomPosition] = tmp;
		}

		for (int i = 0; i < p; i++) {
			//pknowledge[i] = mLogic.numPossibleCards(randomLocations[i]);
			
			pknowledge[i] = mLogic.uncertainCards(randomLocations[i]).length;
			pknowledgeindexes[i] = randomLocations[i];
		}

		// sort... + sort indexes with it...

		for (int i = 0; i < p; i++) {
			int min = i;
			for (int j = i; j < p; j++) {
//				if (pknowledge[min] > pknowledge[j])	// favor less uncertain cards
				if (pknowledge[min] < pknowledge[j])	// favor more uncertain cards
					min = j;
			}
			int tmp = pknowledge[i];
			pknowledge[i] = pknowledge[min];
			pknowledge[min] = tmp;
			tmp = pknowledgeindexes[i];
			pknowledgeindexes[i] = pknowledgeindexes[min];
			pknowledgeindexes[min] = tmp;
		}

		for (int i = 0; i < p; i++) {
			int k = pknowledgeindexes[i];
			if (k == mIndex) //i
				continue;
			if (mLogic.numPossibleCards(k) > c) { //i
				// interrogate player i
				if (mLogic.uncertainCards(k).length > 0) //i
					return new Move(
						_CINTERROGATION,
						ClueLogic.union(
							mLogic.mostUncertainCards(k),
							mLogic.randomCertainlyNotCards(k)),
						k);
				//i,i,i
				else {
					//log.close();
					return new Move(_CGUESS, mLogic.getPossibleHiddenCards());
				}
			}
		}

		// make a guess
		return new Move(_CGUESS, mLogic.getPossibleHiddenCards());
	}

	/**
	 * Look at previous moves and make inferences based on that
	 * 
	 * @throws Exception
	 */
	private void analyzeMoves() throws Exception {
		for (int r = mLastRound + 1; r < mClue.currRound(); r++) {
			MoveResult move = mClue.history(r);
			int cards[] = move.cardlist;
			int interrogatee = move.interrogatee;
			int interrogator = move.player;

			if (move.type == _CINTERROGATION && mIndex != interrogatee) {
				if (move.response == false) {
					// This means the player did not have any of the cards in
					// the list that the interrogator gave. Great! We infer:
					mLogic.assertLacksCards(interrogatee, cards);

				} else {
					// the cards that ee was asked that we know are on his
					// maybe list
					int eesCards[] =
						ClueLogic.intersection(
							cards,
							mLogic.possibleCards(interrogatee));
					mLogic.assertClause(interrogatee, eesCards);
				}
			}
		}

		mLogic.analyzeClauses();
		mLastRound = mClue.currRound();

	}

	public int question(int interrogator, int[] cardlist) throws Exception {
		int i, j;
		int n = mShownCounter.length;

		// reorder randomOrder array so that cards that are shown more
		// often are first in the random order

		for (i = 0; i < n - 1; i++)
			for (j = i + 1; j < n; j++)
				if (mShownCounter[j] > mShownCounter[i]) {
					int x, y;
					x = mShownCounter[i];
					y = mRandomOrder[i];
					mShownCounter[i] = mShownCounter[j];
					mRandomOrder[i] = mRandomOrder[j];
					mShownCounter[j] = x;
					mRandomOrder[j] = y;
				}

		for (j = 0; j < mCards.length; j++) {
			for (i = 0; i < cardlist.length; i++) {
				if (cardlist[i] == mCards[mRandomOrder[j]]) {
					mShownCounter[j]++;
					return cardlist[i];
				}
			}
		}
		return 0;
	}

	/**
	 * Recieve a response from my interrogation
	 */
	public void answer(int interrogatee, int[] asklist, int response)
		throws Exception {
		if (response == 0) {
			mLogic.assertLacksCards(interrogatee, asklist);
		} else {
			mLogic.assertHasCard(interrogatee, response);
		}

	}

	public int[] forcedGuess() throws Exception {
		//		System.out.println(mIndex + ") Forced to guess, logic is");
		//		System.out.println(mLogic);

		int[] hidden = mLogic.getPossibleHiddenCards();
		return hidden; //TODO fixme
	}

	public void notifyPlayerExit(int iPlayerExited) throws Exception {

		int[] list = mClue.getPlayerList(iPlayerExited, null);

		//		System.out.print(mIndex + ") Notified of player exit: ");
		//		for (int i = 0; i < list.length; i++) {
		//			System.out.print(list[i] + " ");
		//		}
		//		System.out.println();
		
		int p = mClue.numPlayers();
		mLogic.assertHasCards(iPlayerExited, list);
		mLogic.analyzeClauses();
	}

	public String name() throws Exception {
		return "Wintermute";
	}

	public Color color() throws Exception {
		return new Color(1.0f, 0.5f, 1.0f);
	}

	public boolean interactive() throws Exception {
		return false;
	}

}
