  // written by: Mike Puntolillo
  // debugged by: Justin Phalon


package minoritygame;

/**
 *
 * @author PuntolMi
 */
public class Sherlock
{

    public int col=(int)Math.pow(2,Math.pow(2,gameParameters.M));
    public double [][] strategyScores=new double [gameParameters.NUMAGENTS][col];
    public int [][] strategyUsage=new int [gameParameters.NUMAGENTS][col];
    public short [] prediction= new short[gameParameters.NUMAGENTS];
    public short guess=0;
    public int score=0;
    private Strategy [] strategies =  new Strategy[col];
    public Sherlock()
    {
        guess=0;
        score=0;

        for (int x = 0; x<col; x++)
        {
            strategies[x]=new Strategy(x);
        }
    }

    public int getScore()
    {
        return score;
    }

    public void updateUsage(int agentNumber, char[] mem, int decision)
    {
        for (int x=0; x<col; x++)
        {
            if (strategies[x].decision(mem)==decision && strategyUsage[agentNumber][x]>=0)
            {
                strategyUsage[agentNumber][x]++;
            }
        }
    }

    public void updateScores(Agent [] a, int r)
    {
        if (r==guess)
            score++;

        for (int x=0; x<gameParameters.NUMAGENTS;x++)
        {
            char [] mem = a[x].getMem();
            for (int y=0; y<col; y++)
            {
                strategyScores[x][y]=strategyScores[x][y]*gameParameters.ALPHA;
                if (strategies[y].decision(mem)==r && strategyScores[x][y]>=0)
                {
                    strategyScores[x][y]++;
                }
            }
        }

        if(gameParameters.ALPHA==1)
        {
            for (int x=0; x<gameParameters.NUMAGENTS;x++)
            {
                for (int y=0; y<col; y++)
                {
                    if(strategyUsage[x][y]>0 &&(double)strategyScores[x][y]/strategyUsage[x][y]>2 && score >10)
                    {
                        strategyScores[x][y]=-1;
                        strategyUsage[x][y]=-1;
                    }
                }
            }
        }
    }

    public void clear()
    {
        for(int x=0; x<gameParameters.NUMAGENTS;x++)
        {
            prediction[x]=0;
        }
    }

    public int predict(Agent [] a)
    {
        int sum=0;
       for(int x=0; x<gameParameters.NUMAGENTS;x++)
       {
            double highestUsage=-1;
            double highestScore=-1;
            int strategyNumber=0;

            for (int y=0; y<col;y++)
            {
                if (strategyUsage[x][y]>highestUsage)
                {
                    strategyNumber=y;
                    highestScore=strategyScores[x][y];
                    highestUsage=strategyUsage[x][y];
                }
                else if (strategyUsage[x][y]==highestUsage &&strategyUsage[x][y]>-1 && strategyScores[x][y]>highestScore)
                {
                    strategyNumber=y;
                    highestScore=strategyScores[x][y];
                    highestUsage=strategyUsage[x][y];
                }

            }


            prediction[x] = (short)strategies[strategyNumber].decision(a[x].getMem());
            sum = sum + prediction[x];
       }

        if (sum>0)
            guess=-1;
        else
            guess=1;

        return guess;


    }

    public void printUsage()
    {
        for(int x=0; x<gameParameters.NUMAGENTS;x++)
        {
            for(int y=0; y<col; y++)
            {
                System.out.print(strategyUsage[x][y]+" ");
            }
            System.out.println();
        }
    }


    public void printStats()
    {
        System.out.println("Sherlock's SCORE: "+score);
        System.out.println("Sherlock's HIT RATE: "+((double)score)/((double)gameParameters.ROUNDS));
    }

    public String statsToString()
    {
        StringBuffer s= new StringBuffer();

        s.append("Sherlock's Score: "+score);
        s.append("\nSherlock's Hit Rate: "+GameSim.round(((double)score)/((double)gameParameters.ROUNDS))+"\n");

        return s.toString();
    }

}
