//***********************************************************
//*
//* File:           Player.java
//* Author:         Lyubov Golub, Edan, Andy
//* Contact:        lg532@columbia.edu
//* Update:         10.19.2003
//*
//* Description:    A case file for a player in the game
//*
//***********************************************************

package Cluedo.g4;

import Cluedo.*;
import Cluedo.g4.IntegerList;
import ui.*;
import java.util.*;
import java.io.*;
import java.awt.Color;

public class Player
{	
    //information about this player's cards
    double []cards;  //probabilities for each card
    public Vector disjunctions; //disjunctions known about him
    private Vector questions; //all of his questions - question[i] refers to question asked on ith turn
    
    //general game information
    private int numPlayers;
    private int numCards;
    private int numHiddenCards;
    private int numCardsPerPlayer; 
    int playerNumber;
    
    int myIndex;
    int numCardsKnown;

    boolean solved = false;
    int changedthispass = 0;

    //information about what this player knows
    
    public Player(Cluedo clue, int index)
    {
	try 
	    {
		numPlayers = clue.numPlayers();
		numCards = clue.numCards();
		numHiddenCards = clue.numHiddenCards();
		numCardsPerPlayer = clue.numCardsPerPlayer();
		
		myIndex = index; 
		playerNumber=index;
		disjunctions = new Vector(10);
		questions = new Vector(10);
		cards = new double[numCards + 1];
		for(int i = 0; i <= numCards; i++)
		    {
			cards[i] = Constants.UN_CARD;
		    }
		numCardsKnown = 0;
	    }
	catch(Exception e)
	    {
		//		System.out.println(e.toString());
	    }
    }

    public void reset() {
	changedthispass=0;
    }

    public void showCards() {
        //System.out.println("Hidden Cards:");
	for (int i=1; i<=numCards; i++) {
	    {
		if (cards[i] == Constants.MINE) {
		    //    System.out.println ("Should Hold: "+i);
		}
		else if (cards[i] == Constants.NOT_MINE) {
		    //System.out.println ("Should Not Hold: "+i);
		}
	    }
	}
    }

    public void showAllCards() {
	//System.out.print("EH> Player "+playerNumber+" ");
	for (int i=1; i<=numCards; i++) {
	    {
		if (cards[i] == Constants.MINE) {
		    //    System.out.print (i+" O ");
		}
		else if (cards[i] == Constants.NOT_MINE) {
		    //System.out.print (i+" X ");
		}
		//else System.out.print (i+" ? ");
	    }
	}
	//System.out.print("\n");
    }

    public void addDisjunction(int []cards)
    {
	CardGroup cardGroup = new CardGroup(cards);
	//System.out.println("Adding disjunction ");
	//cardGroup.print();
	
	disjunctions.add(cardGroup);
	
    }
    
    public void addDisjunction(IntegerList cards)
    {
	CardGroup cardGroup = new CardGroup(cards);
	//System.out.println("Adding disjunction ");
	//cardGroup.print();
	
	disjunctions.add(cardGroup);
	
    }
	
    public void addHasCards(int []inCards, Card[] cardArray, Player[] players)
    {		
	for(int i = 0; i < inCards.length; i++)
	    {
		if(inCards[i] != -1)
		    {
			cards[inCards[i]] = Constants.MINE;
			
		    }
	    }
    }
	
    public int numCardsLeftToFind() 
    {
	int sumOfCards=0;;
	for (int i=1; i<cards.length; i++) {
	    if (!((cards[i]==0)||(cards[i]==1))) {
		sumOfCards++;
	    }
	}
	return sumOfCards;
    }



    public void addHasCard(int inCard, Card[] cardArray, Player[] players)
    {
	//System.out.println("in addHasCard");
	// System.err.println("has card " + inCard + " length " + cards.length);
	if (cards[inCard]==Constants.NOT_MINE) {
	    //System.out.println("Error Player.1");
	}
	else if (!(cards[inCard]==Constants.MINE)) {
	    cards[inCard] = Constants.MINE;
	    changedthispass=1;
	    if (playerNumber==numPlayers) {
		//	System.out.println("Hidden does have "+inCard);
	    }
	    //   System.out.println ("CARD "+inCard+" Does have player "+playerNumber);
	    cardArray[inCard].addHasPlayer(playerNumber, cardArray, players);
	    numCardsKnown++;
	    for (int i = 0; i < players.length; i++) {
		if (!(i==playerNumber)) {
		    players[i].addDoesNotHave(inCard, cardArray, players);
		}
	    }
	}
	/*	if (!(cardArray[inCard].hasPlayer(playerNumber))) {
	    cardArray[inCard].addHasPlayer(playerNumber, cardArray, players);
	    }*/
    }
    
    
    public void addQuestion(int []cards)
    {
	CardGroup cardGroup = new CardGroup(cards);
	//System.out.println("Adding opponent questions ");
	//cardGroup.print();		
	questions.add(cardGroup);	
    }
    
    public void addDoesNotHave(int inCard, Card[] cardsArray, Player[] players)
    {
	//System.out.println("in addDoesNotHave");
	/* need to check that we haven't already set them, constants, playenumber, [] into all*/
	if (cards[inCard] == Constants.MINE) {
	    // System.out.println("Error Player.2");
	}
	else if (!(cards[inCard] == 0)) {
	    cards[inCard] = Constants.NOT_MINE;
	    changedthispass=1;
	    if (playerNumber==numPlayers) {
		//System.out.println("Hidden should not have"+inCard);
	    }
	    cardsArray[inCard].addDoesNotHave(playerNumber, cardsArray, players);
	}
    }
    
    public void addDoesNotHave(int []inCards)
    {		
	for(int i = 0; i < inCards.length; i++)
	    {
		if(inCards[i] != -1)
		    {
			cards[inCards[i]] = Constants.NOT_MINE;
			
		    }
	    }
    }
    

    public void figureOutByX (Card[] cardsArray, Player[] players) {
	int countX=0;
	int[] unknown;
	if (solved == false) {
	for (int i=1; i < cards.length; i++) {
	    if (cards[i] == Constants.NOT_MINE) {
		countX++;
	    }
	}
	if (((countX > (numCards - numCardsPerPlayer)) &&
	     (playerNumber < numPlayers)) || ((playerNumber == numPlayers) &&
	     (countX > (numCards - numHiddenCards)))) {
	    //System.out.println("Error Player.3"); 
	}
	else if (((countX == (numCards - numCardsPerPlayer)) &&
	   (playerNumber < numPlayers)) || ((playerNumber == numPlayers) &&
	       (countX == (numCards - numHiddenCards)))) {
	    solved=true;
	    for(int i=1; i<cards.length; i++) {
		if (!(cards[i] == Constants.NOT_MINE)) {
		    addHasCard(i, cardsArray, players);
		}
	    }
	}
	}
    }


    public void figureOutByO (Card[] cardsArray, Player[] players) {
	int countO=0;
	int CountY=0;
	if (solved==false) 
	{
	for (int i=1; i<cards.length; i++) {
	    if (cards[i] == Constants.MINE) {
		countO++;
	    }
	}
	if (((playerNumber < numPlayers) && (countO > numCardsPerPlayer)) ||
	   ((playerNumber == numPlayers) && (countO > numHiddenCards))){
	    //System.out.println("Error Player.4"); 
	}
	else if (((playerNumber < numPlayers)&&(countO == numCardsPerPlayer)) 
	   || ((playerNumber == numPlayers) && (countO == numHiddenCards))){
	    for (int i=1; i<cards.length; i++) {
		solved=true;
		if (!(cards[i] == Constants.MINE)) {
		    addDoesNotHave(i, cardsArray, players);
		}
	    }
	}
	}
    }
    public boolean solved() {
	return solved;
    }

    public int deduce (Card[] cardsArray, Player[] players) {
	reset();
	//System.out.println("In deduction");
	figureOutByX(cardsArray, players);
	figureOutByO(cardsArray, players);
	//System.out.println("Out of Deduction");
	return changedthispass;
    }

	
    public boolean doesNotHaveCard(int inCard)
    {
	if(cards[inCard] == Constants.NOT_MINE)
	    return true;
	else 
	    return false;
    }
    
    public boolean hasCard(int inCard)
    {
	if(cards[inCard] == Constants.MINE)
	    return true;
	else
	    return false;
    }
    
	//returns all indices in cardGroups where card is found
    public IntegerList searchForCard(Vector cardGroups, int card)
    {
	IntegerList indices = new IntegerList(10);
	for (int i = 0; i < cardGroups.size(); i++)
	    {
		CardGroup cardGroup = (CardGroup)cardGroups.get(i);
		int cards[] = cardGroup.getCards();
		boolean cardPresent = false;
		for(int j = 0; j < cards.length; j++)
			{
			    if(cards[j] == card)
				cardPresent = true;
			}
		if(cardPresent)
		    {
				indices.addInteger(i);	//where in the cardgroup the card is located
		    }
	    }
	
		return indices;
    }
    
    //does card exist in cardGroups?
    public boolean findCard(Vector cardGroups, int card)
    {
	for(int i = 0; i < cardGroups.size(); i++)
	    {
		CardGroup cardGroup = (CardGroup)cardGroups.get(i);
		int cards[] = cardGroup.getCards();
		for(int j = 0; j < cards.length; j++)
		    {
			if(cards[j] == card)
			    return true;
		    }
	    }
	
	return false;
    }

    public int[] cardsIKnowAbout() {
	int []myCards;
	int arrayCounter=0;
	int arrayLength=0;
	for (int i = 1; i < cards.length; i++) {
	    if (cards[i] == 1) {
		arrayLength++;
	    }
	}
	myCards = new int[arrayLength];
	for (int i = 1; i < cards.length; i++) {
	    if (cards[i] == 1) {
		myCards[arrayCounter] = i;
		arrayCounter++;
	    }
	}
	return myCards;
    }

    //returns true if this group is found in disjunctions
    public boolean findDisjunction(CardGroup group)
    {
	for(int i = 0; i < disjunctions.size(); i++)
	    {
		if(((CardGroup)disjunctions.get(i)).equals(group))
		    return true;
	    }
	return false;
    }
    /*public boolean makeInferences(Card[] cardArray, Player[] players)
        {
                int newCardsFound = 0;
                boolean changes = true;
                while(changes)                //while new cards are added
                {
                        changes = false;
                        for(int i = 0; i < disjunctions.size(); i++)
                        {
                                CardGroup cardGroup = (CardGroup)disjunctions.get(i);        
                                for(int j = 0; j < cardGroup.size(); j++)
                                {
                                        if(cards[cardGroup.getCard(j)] == Constants.NOT_MINE)
                                        {
                                                cardGroup.remove(j);
                                                if(cardGroup.size() <= 1)
                                                {
                                                        addHasCard(cardGroup.getCard(0), cardArray, players);
                                                        disjunctions.remove(i);
                                                        changes = true;
                                                        newCardsFound++;
                                                        //System.out.println("Player " + myIndex + " has card " + cardGroup.getCard(0) + " from disjunctions.");
                                                }
                                        }
                                }                        
                        }
                }
                
                if(newCardsFound > 0)
                        return true;
                else return false;
		}*/

public boolean makeInferences(Card[] cardArray, Player[] players)
        {
                int newCardsFound = 0;
                boolean changes = true;
                while(changes)                //while new cards are added
                {
                        changes = false;
			boolean []toRemoveDisj = new boolean[disjunctions.size()];
			for(int i = 0; i < toRemoveDisj.length; i++)
			    {
				toRemoveDisj[i] = false;
			    }
                        for(int i = 0; i < disjunctions.size(); i++)
                        {
                                CardGroup cardGroup = (CardGroup)disjunctions.get(i);        
				boolean[] toRemoveCG = new boolean[cardGroup.size()];
				for(int j = 0; j < toRemoveCG.length; j++)
				    {
					toRemoveCG[j] = false;
				    }
				for(int j = 0; j < cardGroup.size(); j++)
                                {
                                        if(cards[cardGroup.getCard(j)] == Constants.NOT_MINE)
                                        {
					    //cardGroup.remove(j);
						toRemoveCG[j] = true;
                                                if(cardGroup.size() <= 1)
                                                {
                                                        addHasCard(cardGroup.getCard(0), cardArray, players);
                                                        //disjunctions.remove(i);
							toRemoveDisj[i] = true;
                                                        changes = true;
                                                        newCardsFound++;
                                                        //System.out.println("Player " + myIndex + " has card " + cardGroup.getCard(0) + " from disjunctions.");
                                                }
						
                                        }
                                }                        
				//copy over to new CardGroup
				CardGroup newCG = new CardGroup(1);
				for(int j = 0; j < toRemoveCG.length; j++)
				    {
					if(!toRemoveCG[j])
					    newCG.add(cardGroup.getCard(j));
				    }
				cardGroup = newCG;
                        }
			//copy over to new Disjunctions
			Vector newDisj = new Vector(1);
			for(int i = 0; i < toRemoveDisj.length; i++)
			    {
				if(!toRemoveDisj[i])
				    newDisj.add(disjunctions.get(i));
			    }
			disjunctions = newDisj;
                }
                
                if(newCardsFound > 0)
                        return true;
                else return false;
        }
}

class CardGroup 
{
    private IntegerList cards;  
    private int turn;    //the turn this group of cards pertains to 
    
    public CardGroup(int numCards)
    {
	cards = new IntegerList(numCards);		
    }
    
    public CardGroup(IntegerList inCards)
    {
	cards = inCards;
    }
    
    public CardGroup(int []inCards)
    {
	cards = new IntegerList(inCards.length);
	for(int i = 0; i < inCards.length; i++)
	    {
		if(inCards[i] != -1)
		    cards.addInteger(inCards[i]);
	    }
    }
	
    public void remove(int card)
    {
	for(int i = 0; i < cards.size(); i++)
	    {
		if(cards.getInteger(i) == card)
		    cards.remove(i);
	    }
    }

    public void add(int card)
    {
	cards.addInteger(card);
    }
    
    
    public int[] getCards()
    {
	return cards.toIntegers();	
    }
    
    public int getTurn()
    {
	return turn;
    }
    
    public int size()
    {
	return cards.size();
    }
    
    public int getCard(int i)
    {
	return cards.getInteger(i);
    }
    
    public void print()
    {
	for(int i = 0; i < cards.size(); i++)
	    {
		//System.out.print(cards.getInteger(i) + " ");
	    }
	//System.out.println("");
    }

    public boolean equals(CardGroup group)
    {
	if(size() != group.size())
	    return false;
	for(int i = 0; i < group.size(); i++)
	    {
		int card = group.getCard(i);
		boolean found = false;
		for(int j = 0; j < size(); j++)
		    {
			if(card == getCard(j))
			    found = true;
		    }
		if(!found)
		    return false;
	    }
	return true;

    }

  //is this CardGroup a superset of group? 
    public boolean isSuperSet(CardGroup group)
    {
	for(int i = 0; i < group.size(); i++)
	    {
		int card = group.getCard(i);
		boolean found = false;
		for(int j = 0; j < size(); j++)
		    {
			if(card == getCard(j))
			    found = true;
		    }
		if(!found)
		    return false;
	    }
	return true;	
    }

}
