/* Extended by Lenny Volchok */

import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.net.*;
import java.io.*;
import java.util.*;

public class OthelloNoisyEdgar extends OthelloPlayer
{
    
    static final int WHITE = 1;
    
    // This is the "learning" that was done and will be used
    // to decide what to do in a particular situation
    
    double DecisionsValue[][][] = new double[60][8][8];
    double DecisionsValueNumber[][][] = new double[60][8][8];
    double DecisionsValueWeight[][][] = new double[60][8][8];
    double DecisionsFlipWeight[][][] = new double[60][8][8];
    
    int CornerPenalty;
    
    OthelloNoisyEdgar()
    {
	super(WHITE);
	
	//		if (FirstTime)
	//{
	/* ------------- Read in FinalWeights ---------------- */
	try {
	    //URL myURL = new URL(getDocumentBase(),"FinalWeights");
	    FileInputStream myStream = new FileInputStream("FinalWeights");
	    StreamTokenizer myTok = new StreamTokenizer(myStream);
	    
	    myTok.parseNumbers();
	    
	    int counter = 0;
	    do 
		{
		    myTok.nextToken();
		    if (myTok.ttype == myTok.TT_NUMBER) 
			{
			    double thisNum = myTok.nval;
			    switch (counter % 5)
				{
				case 0:
				    break;
				case 1:
				    DecisionsValue[counter/(8*8*5)]
					[(counter/(5*8)) % 8]
					[(counter/5) % 8] = thisNum;
				    break;
				case 2:
				    DecisionsValueNumber[counter/(8*8*5)]
					[(counter/(5*8)) % 8]
					[(counter/5) % 8] = thisNum;
				    break;
				case 3:
				    DecisionsValueWeight[counter/(8*8*5)]
					[(counter/(5*8)) % 8]
					[(counter/5) % 8] = thisNum;
				    break;
				case 4:
				    DecisionsFlipWeight[counter/(8*8*5)]
					[(counter/(5*8)) % 8]
					[(counter/5) % 8] = thisNum;
				    break;
				}
			    counter++;
			}
		    else 
			{
			    /* System.out.println("Read a string: " + myTok.sval +
			       "at counter " + counter);
			    */
			}
		}
	    while (myTok.ttype != myTok.TT_EOF);
	} catch (Exception e)
	    {System.out.println("An Error Occured Reading the data file.");}
	
	/* ------------- Print out FinalWeights ---------------- */
	
	CornerPenalty = ((int) DecisionsValue[0][0][0]);
	/* System.out.println("Corner Penalty is " + CornerPenalty); */
    }
    
    public double evalMove(OthelloBoard board, Move move) {
	return (double)rankLEARNEDMove(WHITE, move.col(), move.row(), board);
    }
    
    /* Add randomness to this method */
    public Move bestMove(OthelloBoard board) {
	
	Vector rankedMoves = rankMoves(board);
	int n = rankedMoves.size();
	Move bestMove = (Move)rankedMoves.elementAt(n-1);  
	
	if(n > 1){
	    int total = 0;
	    int i;
	    for(i=1; i<=n; i++){
		total += i;
	    }
	    
	    /* Get a random integer in the range 0 - total */
	    Random random = new Random();
	    int pos = random.nextInt();
	    if(pos < 0) pos = -pos;
	    pos = pos % total;
	    
	    /* Add a bit more to the total, so the best move has
	       a better probability */
	    // total = total*2;
	    
	    for(i=1; i<=n; i++){
		total -= i;
		if(pos >= total){
		    bestMove = (Move)rankedMoves.elementAt(i-1);
		    break;
		}
	    }
	}
	
	return bestMove;
    }
    
    /* --------------------------------------------------*/
    boolean SetUpForCorner(int color, int col, int row, OthelloBoard board)
    {
	int scoretemp[] = new int[3];
	int boardtemp[][] = new int[9][9];
	int opponent = OthelloBoard.BLACK + OthelloBoard.WHITE - color;
	boolean toreturn;
	
	scoretemp[OthelloBoard.BLACK] = board.score[OthelloBoard.BLACK];
	scoretemp[OthelloBoard.WHITE] = board.score[OthelloBoard.WHITE];
	
	for(int i = 0;i<9;i++)
	    for(int j = 0;j<9;j++)
		boardtemp[i][j] = board.board[i][j];
	
	board.FakemakeMove(color, col, row);
	
	if ((board.isLegalMove(opponent,1,1)) ||
	    (board.isLegalMove(opponent,1,8)) ||
	    (board.isLegalMove(opponent,8,1)) ||
	    (board.isLegalMove(opponent,8,8)))
	    toreturn = true;
	else
	    toreturn = false;
	
	board.score[OthelloBoard.BLACK] = scoretemp[OthelloBoard.BLACK];
	board.score[OthelloBoard.WHITE] = scoretemp[OthelloBoard.WHITE];
	
	for(int i = 0;i<9;i++)
	    for(int j = 0;j<9;j++)
		board.board[i][j] = boardtemp[i][j];
	
	return toreturn;
    }
    
    /* --------------------------------------------------*/
    int rankLEARNEDMove (int color, int col, int row, OthelloBoard board)
    {
	int count = 0;
	int rowinc,colinc;
	double Value;
	double Flip;
	
	/* somebody's piece is already in this location */
	if ((board.board[col][row] != OthelloBoard.EMPTY) && (board.board[col][row] != OthelloBoard.OKMOVE))
	    return 0;
	
	for (colinc = -1; colinc < 2; colinc++) 
	    for (rowinc = -1; rowinc < 2; rowinc++) 
		count += board.flipRow(color, col, row, colinc, rowinc, false,
				       false);
	
	if (count == 0) 
	    return count;
	
	Flip  = 
	    ((double)count)*(DecisionsFlipWeight[board.GameTime][col-1][row-1]);
	
	Value = (DecisionsValue[board.GameTime][col-1][row-1])*
	    (DecisionsValueWeight[board.GameTime][col-1][row-1]);
	
	Value = (Value + Flip);
	
	if (SetUpForCorner(color,col,row, board))
	    count = ((int)(Value * 10)) - CornerPenalty;
	else
	    count = ((int)(Value * 200.0));
	
	if (count == 0)
	    count = 1;
	
	//System.out.println("Game Time = " + board.GameTime + " Column = " + col + " Row = " + row + " Value = " + count); 
	
	return count;
    } 
    /* --------------------------------------------------*/
    
}
