/*  johnchess.m
 *
 *  John Mirandas chess program
 */
 
#import <stdio.h>
#import <time.h>
#import <stdlib.h>
#import <string.h>

int flipBoard();  
int whiteInCheck();
int findComputerMove();
int checkOutKnight();
int checkOutRook();
int checkOutBishop();
int checkOutPawn();
int examineMove();
int copyEvalBoard();


// Global Variables
int moveHistory [400][6]; // History for x1,y1,x2,y2,piece,piece taken if any.
int moveCount = 0;
int board [9][9][9];    //Represents the boards at various plys.  ply[0] is the current board.
int ply = 0;   //During analysis represents the ply that is currently being examined.
int evalScore;  //Maintains returned value from evaluation function.
int positionValue [7] [9] [9];  //Holds strategic board piece values for evaluation function.
int pieceValue [7] = {0,300,350,500,900,13000,100};
char pieceLetter [14] = {'.', 'p', 'k', 'q', 'r', 'b', 'n' ,'.','N', 'B', 'R', 'Q', 'K', 'P' }  ;
char *pieceName[7] = {" ","Knight","Bishop","Rook","Queen","King","Pawn"};
char columnLetter[9] = {' ','a','b','c','d','e','f','g','h'};
int canCastle = 1;  //While 1 signifies the user can still casle.
int fromx, fromy, tox, toy;  //Stores the possible ply 1 move being investigated.
int bestfromx, bestfromy, besttox, besttoy;  //Stores best move found so far.
int verbose= 2;  // Controls how much search status to print during play.
int gameIsOn = 1;  // When switched to zero, application exits.
int maxPly = 5;  //Stores maximum search depth.  This is user configurable during play.  
int pruneIt = 0;  //Is set to 1 during the evaluation function if an alpha beta cut off is reached.
long nodesSearched;  //Statistic to return to user during play.
int applyPruning = 1;  //Determines if alpha beta pruning is used.  This is user configurable during play.
int pruningRange = 19999;
int applyRandom = 1;  //Adds variety to game when enabled.  User configurable during play.
int randomValue = 0;  //Random factor applied each move.
int aspirationWindow = 1;  //Minor variable to slighly narrow alpha beta cut offs.
time_t starttime, endtime;  //Used to time computer moves.
int alphabeta [10];  //Maintains alpha beta cut offs for each ply, maximum of ten plys.
long  nodesPruned [10];  //Maintains tree cut off count at each ply, statistic for user.
int counter;  //General counter.
int validx1, validx2, validy1, validy2, validMove;
int enforceValidMoves = 1;  // Switch on weather to enforce piece movement


// This function calculates the strategic location and piece values for a provided chess board.	
int calcBoardValue ()
{
int score = 0;
int pieceScore = 0;
int boardScore = 0;
int x,y;

	// Compute score.
	for (y = 1; y < 9; y++) 
	{
		for (x = 1; x < 9; x++) 
		{
			//The next conditionals count pieces and sum their values as well as their location value.
			if (board[ply][x][y] < 0) 
			{
				pieceScore = pieceScore + pieceValue[ abs ( board[ply][x][y] ) ];
				boardScore = boardScore + positionValue [abs (board[ply] [x][y])] [x] [9-y];		
			}
			if (board[ply][x][y] > 0)
			{
				pieceScore = pieceScore - pieceValue[ board[ply][x][y]  ];
				boardScore = boardScore - positionValue [ board[ply] [x][y] ] [x] [y];		
			}
		}
	}
	
	// The following enables a bit of randomness into the game provided applyRandom is set to 1.
	randomValue = ((random() % 30 )- 15 ) * applyRandom;
	
	score =  pieceScore + boardScore  + randomValue ;

	return score;
} 	

// This routine sets up the piece location strategic values.	
void initializeStrategy (void)
{
	int x, y;
	int corePiecePosition [9] [9] =  { 
		{0,0,0,0,0,0,0,0,0},
		{0,-10,-33,-20,-10,-10,-20,-33,-10}, 		
		{0,-10,0,0,0,0,0,0,-10}	,
		{0,-10,0,5,5,5,5,0,-10}	,
		{0,-10,0,5,10,10,5,0,-10} ,
		{0,-10,0,5,10,10,5,0,-10} ,
		{0,-10,0,5,5,5,5,0,-10}	,
		{0,-10,0,0,0,0,0,0,-10}	,
		{0,-10,-10,-10,-10,-10,-10,-10,-10} };
	
	int kingPiecePosition [9] [9] =  { 
		{0,0,0,0,0,0,0,0,0},
		{0,0,20,40,-20,0,-20,40,20},	
		{0,-40,-40,-40,-40,-40,-40,-40,-40},
		{0,-40,-40,-40,-40,-40,-40,-40,-40},
		{0,-40,-40,-40,-40,-40,-40,-40,-40},
		{0,-40,-40,-40,-40,-40,-40,-40,-40},
		{0,-40,-40,-40,-40,-40,-40,-40,-40},
		{0,-40,-40,-40,-40,-40,-40,-40,-40},
		{0,-40,-40,-40,-40,-40,-40,-40,-40} };

	int pawnPiecePosition [9] [9] =  { 
		{0,0,0,0,0,0,0,0,0},
		{0,0,0,0,0,0,0,0,0},	
		{0,0,0,0,-31,-31,0,0,0},
		{0,1,2,3,-5,-5,3,2,1},
		{0,2,4,6,8,8,6,4,2},
		{0,3,6,9,12,12,9,6,3},
		{0,4,8,12,16,16,12,8,4},
		{0,20,20,20,20,20,20,20,20},
		{0,90,90,90,90,90,90,90,90} };
										
	printf("Initializing Strategy. \n");
	
	for  (y = 0; y  < 9 ; y++)
	{
		for  (x=0; x < 9; x++)
		{
			// Set up knight, bishop, rook, and queen board values
			positionValue [1] [x] [y] = corePiecePosition [y] [x];
			positionValue [2] [x] [y] = corePiecePosition [y] [x];
			positionValue [3] [x] [y] = corePiecePosition [y] [x];
			positionValue [4] [x] [y] = corePiecePosition [y] [x];
			
			// Set up king board values
			positionValue [5] [x] [y] = kingPiecePosition [y] [x];
								
			// Set up pawn board values
			positionValue [6] [x] [y] = pawnPiecePosition [y] [x];								
		}
	}	
}	

// This routine sets up the chess pieces at the start of a game.	
void initializeBoard(void)
{
	int x, y;
	
	canCastle = 1;
	
	printf("Initializing Board. \n");
	for  (x = 0; x  <  9 ; x++)
		for  (y=0; y < 9; y++)
			board [ply] [x] [y] = 0;
		
	board [ply] [1][1] = 3;
	board [ply] [2][1] = 1;
	board [ply] [3][1] = 2;
	board [ply] [4][1] = 4;
	board [ply] [5][1] = 5;
	board [ply] [6][1] = 2;
	board [ply] [7][1] = 1;
	board [ply] [8][1] = 3;
	
	for (x=1; x < 9; x++)
	{
		board [ply][x][8] = board [ply][x][1] * -1;
		board [ply][x] [2] = 6;
		board [ply] [x] [7] = -6;
	}	
}

// This routine prints the current chess board.
void printBoard()
{
	int x,y;
	
	printf("\n         a    b    c    d    e    f    g    h \n\n");		
	for (y = 8; y > 0; y--)
	{
		printf("    %d", y);
		for (x=1; x < 9; x++)
			printf("    %c",pieceLetter [  7 + board  [ply][x][y] ] );
		printf("\n\n");
	}				
}

int parseMove(char *s)
{
	int	x = 0;
	int	valid = 0;
	int	tempPieceTaken, tempMaxPly, tempVerbose;

	// Make sure inputs are within range.
	if (s[0] < 'a' || s[0] > 'h' || s[1] < '0' || s[1] > '8'  ) 
			valid = -1;		
	if (s[2] < 'a' || s[2] > 'h' || s[3] < '0' || s[3] > '8'  ) 
			valid = -1;

	if (valid == 0 )
	{	
		validx1 = s[0] - 'a' + 1;
		validy1 = s[1] - '0';
		validx2 = s[2] - 'a' + 1;
		validy2 = s[3] - '0';		
		
		//The next set of commands validates if a user piece move is valid for all moves except castling and En Passant.
		// Prepare variables to call the findcomputermove function to see if our move is in generated list of moves.
		alphabeta[1] = pruningRange * -1;	
		flipBoard();
		validMove = 0;
		ply = 0;
		tempMaxPly = maxPly;
		tempVerbose = verbose;
		maxPly = 1;
		verbose = 0;
		findComputerMove();
		// Restore settings now that we have checked out the moves
		maxPly = tempMaxPly;
		verbose = tempVerbose;
		flipBoard();
		ply = 0;
		
		//Handle En Passant
		//Are we moving a pawn from fifth to the sixth row, diagonally, to a blank spot
		if (validy1 == 5 && validy2 == 6 &&  abs (validx2-validx1) == 1 && moveHistory [moveCount] [5] == 0 )
			validMove = 1;
		
		//Handle castling to the right
		if  (board [ply] [validx1][validy1] == 5 && validx1 == 5 && validy1 == 1 &&  validx2 == 7 && validy2 == 1 && 
			board [ply] [6][1] == 0 && board [ply] [7][1] == 0 && board [ply] [8][1] == 3 && canCastle == 1 )
			validMove = 1;
	
		//Handle castling to the left
		if  (board [ply] [validx1][validy1] == 5 && validx1 == 5 && validy1 == 1 &&  validx2 == 3 && validy2 == 1 && 
			board [ply] [4][1] == 0 && board [ply] [3][1] == 0 && board [ply] [2][1] == 0 &&  board [ply] [1][1] == 3 &&  canCastle == 1 )
			validMove = 1;
			
		//If this isn't a valid move then set valid to a return value of -1.
		if (validMove == 0  && enforceValidMoves == 1)
			valid = -1;
		
		//Set up board, then undo changes, to see if this would put the King in Check
		tempPieceTaken = board  [ply] [validx2][validy2] ;
		board  [ply] [validx2][validy2] = board [ply] [validx1][validy1];
		board  [ply] [validx1][validy1] = 0;
		if (whiteInCheck() == 1  && enforceValidMoves == 1)
		{
			printf("\nThis move puts you in Check!\n");		
			valid = -1;
		}
		board  [ply] [validx1][validy1] = board  [ply] [validx2][validy2];
		board  [ply] [validx2][validy2] = tempPieceTaken;
	}	
	return valid;
}

int whiteInCheck()
{
int	tempVerbose, tempMaxPly;
int	check = 0;
	
	// Prepare variables to call the findcomputermove function to see if the white king can be attacked.
	alphabeta[1] = pruningRange * -1;	
	alphabeta[2] = pruningRange;	
	ply = 0;
	tempMaxPly = maxPly;
	tempVerbose = verbose;
	maxPly = 2;
	verbose = 0;
	
	findComputerMove();
	
	// Restore settings now that we have checked out the moves
	maxPly = tempMaxPly;
	verbose = tempVerbose;

	// If the piece destination is a King then White is in check.
	if  ( board[0][besttox][besttoy] == 5 )
		check = 1;
	
	return check;	
}

void movePiece(char *s)
{
	int x1,x2,y1,y2;

	x1 = s[0] - 'a' + 1;
	y1 = s[1] - '0';
	x2 = s[2] - 'a' + 1;
	y2 = s[3] - '0';

	moveCount = moveCount + 1;
	if (moveCount == 395)
	{
		printf("\nMove history limit reached as we approach 400 moves.");
		printf("\nYou can continue playing, but move history is being reset.\n");
		moveCount = 1;		
	}
		
	//Store piece taken if any.
	moveHistory [moveCount] [5] = board  [ply] [x2][y2] ;
	
	//Update the board with the move.
	board  [ply] [x2][y2] = board [ply] [x1][y1];
	board  [ply] [x1][y1] = 0;
	
	//Promote pawn to queen
	if (board [ply] [x2] [y2] == 6 && y2 == 8)
	{
		printf("\nPromoting White pawn to queen.\n");
		board [ply] [x2] [y2] = 4;
	}
	
	//Handle En Passant
	//Are we moving a pawn from fifth to the sixth row, diagonally, to a blank spot
	if (y1 == 5 && y2 == 6 &&  abs (x2-x1) == 1 && moveHistory [moveCount] [5] == 0 )
	{
		printf("\nRecognizing En passant.\n");
		board [ply][x2][y1] = 0;
	}
	
	//Handle castling to the right
	if  (board [ply] [x2][y2] == 5 && x2 == 7 && y2 == 1 &&  x1 == 5 && y2 == 1 && canCastle == 1 )
	{
		printf("\nCastling King.\n");
		board [ply][6][1] = board[ply][8][1];
		 board[ply][8][1] = 0;
	}
	
	//Handle castling to the left
	if  (board [ply] [x2][y2] == 5 && x2 == 3 && y2 == 1 &&  x1 == 5 && y2 == 1 && canCastle == 1 )
	{
		printf("\nCastling King.\n");
		board [ply][4][1] = board[ply][1][1];
		 board[ply][1][1] = 0;
	}		
	
	// Once the king is moved, you can no longer castle.
	if ( board [ply] [x2][y2] == 5 )
		canCastle = 0;
		
	// Save move history
	moveHistory [moveCount] [0] = x1;
	moveHistory [moveCount] [1] = y1;
	moveHistory [moveCount] [2] = x2;
	moveHistory [moveCount] [3] = y2;
	moveHistory [moveCount] [4] = board [ply] [x2] [y2] ;	
}

int findComputerMove()
{
int	x,y;
	
	//Enter the next ply down.
	ply = ply + 1;
	// Set up evaluation board.
	copyEvalBoard();
	
	for (y = 1;  y  < 9; y++)
	{
		for (x = 1; x < 9; x++)
		{
			if  (board [ply][x][y] == -1 && pruneIt == 0)  checkOutKnight(x,y);
			if  (board [ply][x][y] == -3  && pruneIt == 0 )  checkOutRook(x,y);
			if  (board [ply][x][y] == -2  && pruneIt == 0 )  checkOutBishop(x,y);
			if  (board [ply][x][y] == -6 && pruneIt == 0 )  checkOutPawn(x,y);			
			if  ( (board [ply][x][y] == -4 || board [ply][x][y] == -5) && pruneIt == 0 )
			{
				//If its a queen or king treat it like a combo of rook and bishop.
				//The functions below will limit travel to one square if its the king.
				checkOutBishop(x,y);
				checkOutRook(x,y);	
			}
			
			//If we have reached an alpha beta cut off then exit the evaluation loop for this ply.
			if (pruneIt == 1)
			{
				x = 9;
				y = 9;
				pruneIt = 0;
			}
		}
	}	
	ply = ply - 1;	
}

int examineMove (int x, int y, int dx, int dy)
{
	nodesSearched = nodesSearched + 1;
	
	if (verbose > ply)
	{
		printf("\n");
		for (counter = 1; counter <= ply; counter++)
			printf("   ");
			
		if (ply%2 == 1)
		{
			printf("Ply %d black %s %c%d",ply,pieceName[ abs ( board [ply] [x] [y] ) ], columnLetter[x],y);
			printf(":%c%d-%c%d",columnLetter[x], y, columnLetter[dx],dy);
		}
		else
		{
			printf("Ply %d white %s %c%d",ply,pieceName[ abs ( board [ply] [x] [y] ) ], columnLetter[x],9-y);
			printf(":%c%d-%c%d",columnLetter[x], 9-y, columnLetter[dx],9-dy);
		}
	}
	
	//store the proposed move.
	if (ply == 1)
	{
		fromx = x;
		fromy = y;
		tox = dx;
		toy = dy;
		//This conditional is used to help parse if a user entered move is valid.
		if (validx1 == x && validx2 == dx && validy1 == 9-y && validy2 == 9-dy)
			validMove = 1;
	}			

	//Set up proposed move to calculate score.	
	copyEvalBoard();
	board [ply] [dx] [dy] = board [ply] [x] [y] ;
	
	//If pawn reaches the 8th file then promote to queen.
	if (board [ply] [dx] [dy] == -6 && dy == 1)
		board [ply] [dx] [dy] = -4;
	
	board [ply] [x] [y] = 0;
	
	if (ply < maxPly)
		findComputerMove();

	if (ply == maxPly)		
		evalScore = calcBoardValue();

	//reset the board for next evaluation		
	copyEvalBoard();

	if (ply > 1 && ply % 2  == 1)
	// Manage odd plys
	{
		if (ply == maxPly  && evalScore > alphabeta[ply]  )
			alphabeta[ply] = evalScore;
		if (maxPly > ply && alphabeta[ply+1] > alphabeta[ply] )
			alphabeta[ply] = alphabeta [ply +1];
		
		// apply pruning
		if (applyPruning == 1 && (alphabeta[ply] + aspirationWindow ) > alphabeta[ply-1] )
		{
			pruneIt = 1;
			nodesPruned[ply-1] = nodesPruned[ply-1] + 1;
		}		
		alphabeta[ply+1] = pruningRange;	
	}		
	
	if (ply > 1 && ply % 2  ==  0)
	//Manage even plys
	{
		//Flip the score as we are in an even ply layer.
		evalScore = evalScore * -1;
		if (ply == maxPly && evalScore < alphabeta[ply] )
			alphabeta[ply] = evalScore;
		if (maxPly > ply && alphabeta[ply+1] < alphabeta[ply] )
			alphabeta [ply] = alphabeta [ply + 1];
			
		//apply pruning
		if (applyPruning == 1 && alphabeta[ply] < ( alphabeta [ply-1] + aspirationWindow ) )
		{
			pruneIt = 1;
			nodesPruned[ply-1] = nodesPruned[ply-1] + 1;
		}
		alphabeta[ply+1] = pruningRange * -1;		
	}
	
	if (ply == 1)
	{
		if (maxPly == 1 && evalScore > alphabeta[ply] )
			{
			alphabeta[ply] = evalScore;
			bestfromx = fromx;
			bestfromy = fromy;
			besttox = tox;
			besttoy = toy;	
			if (verbose > ply)
				printf("  New alpha score. %d", alphabeta[ply]);			
			}
			
		if (alphabeta[ply + 1] > alphabeta[ply] && maxPly > 1)
			{
			alphabeta[ply] = alphabeta[ply + 1];
			bestfromx = fromx;
			bestfromy = fromy;
			besttox = tox;
			besttoy = toy;	
			if (verbose > ply)
				printf("  New alpha score: %d ", alphabeta[ply]  );
			}
		alphabeta[ply + 1] = pruningRange;	
	}	
}

int makeComputerMove ()
{
int x;

	//Analysis is complete, return results.
	
	//Save piece taken, if any
	moveCount = moveCount + 1;
	moveHistory [moveCount] [5] = board [0][besttox][besttoy] ;	
	
	printf("\n\nSearched %d nodes.", (int) nodesSearched);
	for (x = 1; x < maxPly; x++)
		printf("\nNodes pruned at Ply %d: %d", x, (int) nodesPruned[x] );
	
	printf ("\n\nMoving %s %c%d to %c%d ", pieceName[  abs( board[0][bestfromx][bestfromy]  ) ] ,
		columnLetter[bestfromx],bestfromy,columnLetter[besttox],besttoy);
	if (board [0][besttox][besttoy] > 0)
		printf("and taking %s.", pieceName[ board[0][besttox][besttoy] ] );
		
	if (board [0][besttox][besttoy] == 5)
	{		
		printf("\n\nCheckmate!\n\n");
		printf("\n\nThank you for the game.\n\n");
	}
	
	board [0][besttox][besttoy] = board [0][bestfromx][bestfromy];
	board [0][bestfromx][bestfromy] = 0;
		
	if ( board [0][besttox][besttoy] == -6 && besttoy == 1)
	{
		printf("Promoting Pawn to Queen.\n");
		board [0][besttox][besttoy] = -4;
	}
	printf("\n");
	
	// Save move history
	moveHistory [moveCount] [0] = bestfromx;
	moveHistory [moveCount] [1] = bestfromy;
	moveHistory [moveCount] [2] = besttox;
	moveHistory [moveCount] [3] = besttoy;
	moveHistory [moveCount] [4] = board [0][besttox][besttoy] ;	
}

int checkOutBishop(int x, int y)
{
int travel, dx, dy;
	
	// Bishop travel Northwest first.	
	dx=x-1;
	dy=y+1;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{
		// If we landed on a friendly stop travel.
		if (board [ply] [dx] [dy] < 0)
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
			examineMove (x, y, dx, dy);
		}
		dy=dy+1;
		dx=dx-1;
	}
	// Bishop travel Northeast second.
	dx=x+1;
	dy=y+1;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{	
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0)
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
			examineMove (x, y, dx, dy);
		}
		dy=dy+1;
		dx=dx+1;
	}	
	// Bishop travel Southeast third
	dx=x+1;
	dy=y-1;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{	
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0)
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
			examineMove (x, y, dx, dy);
		}
		dx=dx+1;
		dy=dy-1;
	}	
	// Bishop travel Southwest.
	dx=x-1;
	dy=y-1;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{	
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0 )
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
 			examineMove (x, y, dx, dy);	
		}
		dx=dx-1;
		dy=dy-1;
	}	
}

int checkOutRook(int x, int y)
{
int travel, dx, dy;

	// Travel North first.
	dx=x;
	dy=y+1;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{		
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0 )
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
 			examineMove (x, y, dx, dy);	
		}
		dy=dy+1;
	}
	// Travel South second.
	dx=x;
	dy=y-1;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{	
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0 )
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
 			examineMove (x, y, dx, dy);			
		}
		dy=dy-1;
	}	
	// Rook travel left third
	dx=x-1;
	dy=y;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{	
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0 )
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
 			examineMove (x, y, dx, dy);		
		}
		dx=dx-1;
	}	
	// Rook travel right finally.
	dx=x+1;
	dy=y;
	travel = 1;
	while (dx > 0 && dx < 9 && dy > 0 && dy < 9 && travel == 1)
	{	
		// If we landed on a friendly piece stop travel.
		if (board [ply] [dx] [dy] < 0)
			travel = 0;
		else
		{
			// If we landed on an opponent or its the king, set travel to zero to limit reach.
			if (board [ply] [dx] [dy] > 0 || board [ply] [x] [y] == -5)
				travel = 0;
				
 			examineMove (x, y, dx, dy);			
		}
		dx=dx+1;
	}	
}

int checkOutKnight(int x, int y)
{
int z, dx, dy;

	for (z = 1; z < 9; z++)
	{
	switch (z)
		{	
		case 1: 
			{
			dx = x -1;
			dy = y -2;
			break;
			}		
		case 2: 
			{
			dx = x +1;
			dy = y -2;
			break;
			}	
		case 3: 
			{
			dx = x-2;
			dy = y+1;
			break;
			}		
		case 4: 
			{
			dx = x-2;
			dy = y-1;
			break;
			}
		case 5: 
			{
			dx = x+2;
			dy = y+1;
			break;
			}		
		case 6: 
			{
			dx = x+2;
			dy =  y-1;
			break;
			}	
		case 7: 
			{
			dx = x-1;
			dy = y+2;
			break;
			}
		case 8: 
			{
			dx = x+1;
			dy = y+2;
			break;
			}					
		}
		if (dx <9 && dx>0 && dy<9 && dy>0 && board [ply] [dx] [dy] > -1)
		 	examineMove (x, y, dx, dy);
	}
}

int checkOutPawn(int x, int y)
{
int dx, dy;

	// Pawn advances to rows forward.
	dx=x; 
	dy = y-2;		
	if (y == 7 && board [ply][x][y-1] == 0 && board [ply][x][y-2] == 0 )
		 examineMove (x, y, dx, dy);
	
	// Move pawn one file.			
	dx=x; 
	dy = y-1;
	if (y > 1 && board [ply][x][y-1] == 0  )
		 examineMove (x, y, dx, dy);
	
	// Pawn takes piece to the left
	dx = x-1; 
	dy = y-1;
	if (y > 1 && x > 1 && board [ply][x-1][y-1] > 0  )
		 examineMove (x, y, dx, dy);
	
	// Pawn takes piece to the right.	
	dx = x+1; 
	dy = y-1;	
	if (y > 1 && x < 8 && board [ply][x+1][y-1] > 0  )
		 examineMove (x, y, dx, dy);
}

int copyEvalBoard(void)
{

int x,y;

	// If its ply one just duplicate the board otherwise flip the board from one ply to the next.
	if (ply == 1)
	{
		for (x = 1; x < 9; x++)
			for (y = 1; y < 9; y++)
				board [ply][x][y] = board [ply-1][x][y];		
	}
	else
	{
		for (x = 1; x < 9; x++)
			for (y = 1; y < 9; y++)
				board [ply][x][y] = board [ply-1][x][9-y]  * -1 ;   		
	}
}

int flipBoard(void)
{

int x,y;

	// This routine flips the board and is used to help parse use moves.
	for (x = 1; x < 9; x++)
		for (y = 1; y < 9; y++)
			board [1][x][y] = board [0][x][y];
					
	for (x = 1; x < 9; x++)
		for (y = 1; y < 9; y++)
			board [0][x][y] = board [1][x][9-y]  * -1 ;   		

}

void showMoveHistory()
{

int x;

	printf("\nMove History\n");
	
	for (x = 1; x  <= moveCount; x++)
	{
		printf("\n%d: ",x);
		printf ("Moved %s %c%d to %c%d ", pieceName[  abs(  moveHistory[x][4]  ) ] ,
				columnLetter[  moveHistory[x][0] ],moveHistory[x][1],columnLetter[ moveHistory[x][2] ],moveHistory [x][3]);
		if  (moveHistory[x][5]  != 0)
		printf("and taking %s.", pieceName[ abs ( moveHistory[x][5]    )  ] );
	}
	printf("\n");
}


void newGame()
{
	printf("\nWelcome to John Miranda's Chess Game.\n");
	printf("Enter quit to exit or help for assistance\n\n");
	
	initializeBoard();
	initializeStrategy();	
	moveCount = 0;
}

int main()
{
	char yourMove[10];
	int score = 0;
	int command = 0;
	int x = 0;
	int	tempPieceTaken, tempMaxPly, tempVerbose;
	
	
	newGame();
	
	while (gameIsOn == 1)
	{
		score = calcBoardValue() ;
		printf("\nYour Score: %d \n", (score - randomValue) * -1);
	
		printBoard();
		command = 0;
	
		printf("\nEnter your move (eg: d2d4): ");
		scanf("%s", yourMove);
	
		if (!strcmp(yourMove, "quit") ||  !strcmp(yourMove, "q")  || !strcmp(yourMove, "bye")  )
		{
			printf("\nThank you for the game.\n\n");
			gameIsOn = 0;
			break;
		}
			
		if (!strcmp(yourMove, "new") ||  !strcmp(yourMove, "n")  )
		{
			command = 1;
			newGame();
		}
		
		if (!strcmp(yourMove, "moves")  )
		{
			command = 1;
			showMoveHistory();
		}
		
		if (!strcmp(yourMove, "maxply1") ||  !strcmp(yourMove, "m1")  )
		{
			command = 1;
			maxPly = 1;
			printf("\nMaximum search ply set to 1.\n\n");
		}
			
		if (!strcmp(yourMove, "maxply2") ||  !strcmp(yourMove, "m2")  )
		{
			command = 1;
			maxPly = 2;
			printf("\nMaximum search ply set to  2.\n\n");
		}			
			
		if (!strcmp(yourMove, "maxply3") ||  !strcmp(yourMove, "m3")  )
		{
			command = 1;
			maxPly = 3;
			printf("\nMaximum search ply set to 3.\n\n");
		}		

		if (!strcmp(yourMove, "maxply4") ||  !strcmp(yourMove, "m4")  )
		{
			command = 1;
			maxPly = 4;
			printf("\nMaximum search ply set to 4.\n\n");
		}

		if (!strcmp(yourMove, "maxply5") ||  !strcmp(yourMove, "m5")  )
		{
			command = 1;
			maxPly = 5;
			printf("\nMaximum search ply set to 5.\n\n");
		}

		if (!strcmp(yourMove, "maxply6") ||  !strcmp(yourMove, "m6")  )
		{
			command = 1;
			maxPly = 6;
			printf("\nMaximum search ply set to 6.\n\n");
		}

		if (!strcmp(yourMove, "maxply7") ||  !strcmp(yourMove, "m7")  )
		{
			command = 1;
			maxPly = 7;
			printf("\nMaximum search ply set to 7.\n\n");
		}
		
		if (!strcmp(yourMove, "maxply8") ||  !strcmp(yourMove, "m8")  )
		{
			command = 1;
			maxPly = 8;
			printf("\nMaximum search ply set to 8.\n\n");
		}
					
		if (!strcmp(yourMove, "verbose0") ||  !strcmp(yourMove, "v0")  )
		{
			command = 1;
			verbose = 0;
			printf("\nSkipping search messages.\n\n");
		}
			
		if (!strcmp(yourMove, "verbose1") ||  !strcmp(yourMove, "v1")  )
		{
			command = 1;
			verbose = 2;
			printf("\nVerbose to ply 1 set.\n\n");
		}
			
		if (!strcmp(yourMove, "verbose2") ||  !strcmp(yourMove, "v2")  )
		{
			command = 1;
			verbose = 3;
			printf("\nVerbose to ply 2 set.\n\n");
		}

		if (!strcmp(yourMove, "verbose3") ||  !strcmp(yourMove, "v3")  )
		{
			command = 1;
			verbose = 4;
			printf("\nVerbose to ply 3 set.\n\n");
		}
			
		if (!strcmp(yourMove, "pruning")  )
		{
			command = 1;
			applyPruning = 1;
			printf("\nAlpha Beta pruning enabled.\n\n");
		}
		
		if (!strcmp(yourMove, "nopruning")  )
		{
			command = 1;
			applyPruning = 0;
			printf("\nAlpha Beta cutoff pruning disabled.\n\n");
		}
		
		if (!strcmp(yourMove, "random")  )
		{
			command = 1;
			applyRandom = 1;
			printf("\nRandom factoring enabled.\n\n");
		}	
				
		if (!strcmp(yourMove, "norandom")  )
		{
			command = 1;
			applyRandom = 0;
			printf("\nRandom factoring disabled.\n\n");
		}	
					
		if (!strcmp(yourMove, "valid")  )
		{
			command = 1;
			enforceValidMoves = 1;
			printf("\nEnforcing piece movement.\n\n");
		}	
			
		if (!strcmp(yourMove, "novalid")  )
		{
			command = 1;
			enforceValidMoves = 0;
			printf("\nDisabling piece movement validation.\n\n");
		}				
		
		if (!strcmp(yourMove, "help")  )
		{
			printf("\nHelp:\n\n");
			printf("	maxplyn or 'mn' - Sets max search ply to value n [1-7].\n");
			printf("	verbosen or 'vn' - Prints search data through ply n [0-3] .\n");
			printf("	pruning - Enables Alpha-Beta cutoff pruning.\n");
			printf("	nopruning - Disables Alpha-Beta cutoff pruning.\n");
			printf("	random - Enables randomization factor.\n");
			printf("	norandom - Disables random factor and makes play deterministic.\n");
			printf("	moves - Displays move history.\n");
			printf("	valid - Enforces piece movement.\n");			
			printf("	novalid - Allows moving a piece pretty much anywhere.\n");			
			printf("	new or 'n' - New game.\n");
			printf("	quit or bye - Exits game.\n");
			printf("	d2d4 - Moves piece from d2 to d4.\n\n");							
			command = 1;							
		}
			
		if (command == 0)
		{
			// No command was recognized, lets assume this is a valid move.	
			if (parseMove(yourMove) == -1)
				printf("\nIllegal Move.\n");
			else
			{
				// make the move
				starttime = time(NULL);
				ply = 0;
				pruneIt = 0;
				nodesSearched =0;
				
				//Set up initial alpha beta cut off values.				
				alphabeta[0] = pruningRange;
				for (x = 1; x <= maxPly; x++)
				{
					alphabeta [x] = alphabeta [x-1] * -1;
					nodesPruned [x] = 0;
				}
				
				movePiece(yourMove);
				printBoard();
				findComputerMove();
				makeComputerMove();
				ply = 0;
				endtime =  time(NULL);
				printf("\nTime elapsed: %d seconds",  (int)  (endtime - starttime ) );
				if (endtime > starttime)
					printf("\nNodes per second: %d\n", (int) ( nodesSearched /  (endtime - starttime) ) );
					
				if (whiteInCheck() == 1)
				{
					printf("\nYou are in check!\n");
					canCastle = 0;
										
					//The next set of code does a 2 ply search to see if this is checkmate.
					alphabeta[1] = pruningRange * -1;	
					alphabeta[2] = pruningRange;	
					flipBoard();
					validMove = 0;
					ply = 0;
					tempMaxPly = maxPly;
					tempVerbose = verbose;
					maxPly = 2;
					verbose = 0;
					findComputerMove();
					// Restore settings now that we have checked out the moves
					maxPly = tempMaxPly;
					verbose = tempVerbose;
					flipBoard();
					ply = 0;
					if ( alphabeta[1] < -6000 )
						printf("\n Checkmate!\n"  );
				}
			}
		}
	}		
	return (0);
}


