package game.training;

import game.logic.Vector;
import game.logic.GameBoard;

public class FeatureCount {
	
	/**
	 * Count column-related features, and update the vector object accordingly.
	 * The counts will be conducted as follows:
	 * For each column we search for a sequence of top discs belong to the player.
	 * When such a sequence is found, it is added to the feature counter if there is enough room
	 * for completing a four-in-a-row (otherwise, this column is not worth much).
	 * 
	 * @param g The board representation that we want to run the counts on.
	 * @param playerState A vector holding the current state of the player.
	 * @param player The player for whom we want to count features.
	 */
	public static void countColumns(GameBoard g, Vector playerState, int player){
		int[]discsInCol = g.getDiscsPerColumn(); 
		int [][] board = g.getBoard(); 
		
		int counter = 0;
		
		int oneInCol = 0;
		int twoInCol = 0;
		int threeInCol = 0;
		int fourInCol = 0;
		
		for (int i = 0; i < GameBoard.NumOfColumns; i++){
			counter = 0;
			
			int rowPosition = discsInCol[i] - 1;
			
			while (rowPosition >= 0 && board[i][rowPosition] == player){
				counter++;
				rowPosition--;
			}
			
			switch (counter){
			case 0:
				break;
			case 1:
				if (discsInCol[i] + 3 <= GameBoard.NumOfRows){
					oneInCol++;
				}
				break;
			case 2:
				if (discsInCol[i] + 2 <= GameBoard.NumOfRows){
					twoInCol++;
				}
				break;
			case 3:
				if (discsInCol[i] + 1 <= GameBoard.NumOfRows){
					threeInCol++;
				}
				break;
			default:
				break;
			}
			
			/* Check column for a 4-in-a-column */
			for (int j = 0; j < discsInCol[i] && j < GameBoard.NumOfRows + 1 - 4; j++){
				if (board[i][j] == player && board[i][j+1] == player && board[i][j+2] == player && board[i][j+3] == player){
					if (!isLegalIndex(i, j-1)){
						fourInCol++;
					} else if (board[i][j-1] != player){
						fourInCol++;
					}
				}
			}
		}
		
		/* Add features to vector - we decided to use less features in our final
		 * implementation, but it seems like a waste to delete all the counts for the
		 * unused features. Since the performance is basically the same, we decided
		 * not to put comments on the features, count them and allow their easy insertion
		 * in the future. */
	//	playerState.addValueToIndex(GameBoardUpdated.OneInACol, oneInCol);
	//	playerState.addValueToIndex(GameBoardUpdated.TwoInACol, twoInCol);
		playerState.addValueToIndex(GameBoard.ThreeInACol, threeInCol);
	//	playerState.addValueToIndex(GameBoardUpdated.FourInARow, fourInCol);
		
		/* Set a four in a column if it is reached */
		g.setFour(player, fourInCol);
		
	}
	
	
	/**
	 * Count row-related features, and update the vector object accordingly.
	 * The counts will be conducted as follows:
	 * We traverse the board in sequences of four cells and search for each feature separately
	 * (two-in-a-row, three-in-a-row etc.).
	 * The most problematic cases are those which the disc is in an edge cell, so we cannot be sure
	 * if it is part of something else (i.e O_ _ _ could be an actual one, or could be
	 * two if one move to the left the board looks like OO_ _).
	 * So, in order to prevent duplicate counts, we simply check whether this position (left to the
	 * left edge or right to the right edge) is legal. If it is not legal, we have no problem. Otherwise,
	 * we need to make sure that it is not the player's disc. For cases in which the discs are in the middle,
	 * i.e _OO_, we have no such problem.
	 * 
	 * @param g The board representation that we want to run the counts on.
	 * @param playerState A vector holding the current state of the player.
	 * @param player The player for whom we want to count features.
	 */
	public static void countRows(GameBoard g, Vector playerState, int player){
		int[]discsInCol = g.getDiscsPerColumn(); 
		int highestDisc = g.getHighestDisc(); 
		int [][] board = g.getBoard(); 
		
		
		int oneInRow = 0;
		int allRowOnes = 0;
		int twoInRow = 0;
		int allRowTwos = 0;
		int blockedThree = 0;
		int openThree = 0;
		int allRowThrees = 0;
		int threesHole1 = 0;
		int threesHole2 = 0;
		int fourInRow = 0;
		
		for (int j = 0; j < GameBoard.NumOfRows && j < highestDisc; j++){
			
			for (int i = 0; i < GameBoard.NumOfColumns + 1 - 4; i++){
				/* Count ones */
				/*  _ _ _ _
				 * |O| | | |
				 *  - - - - */
				if (board[i][j] == player && board[i+1][j] == GameBoard.EmptyCell &&
						board[i+2][j] == GameBoard.EmptyCell &&
						board[i+3][j] == GameBoard.EmptyCell){
					if (!isLegalIndex(i-1,j)){
						allRowOnes++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility of completing 4-in-a-row (stronger) */
						if (j == discsInCol[i+1] && j == discsInCol[i+2] && j == discsInCol[i+3]){
							oneInRow++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i-1][j] != player){
						allRowOnes++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility of completing 4-in-a-row (stronger) */
						if (j == discsInCol[i+1] && j == discsInCol[i+2] && j == discsInCol[i+3]){
							oneInRow++;
						}
					}
				}
				
				/*  _ _ _ _
				 * | |O| | |
				 *  - - - - */
				if (board[i][j] == GameBoard.EmptyCell && board[i+1][j] == player &&
						board[i+2][j] == GameBoard.EmptyCell &&
						board[i+3][j] == GameBoard.EmptyCell){
					allRowOnes++; /* We have a possible option of completing it in the future */
					
					/* Immediate possibility of completing 4-in-a-row (stronger) */
					if (j == discsInCol[i] && j == discsInCol[i+2] && j == discsInCol[i+3]){
						oneInRow++;
					}
				}
				
				/*  _ _ _ _
				 * | | |O| |
				 *  - - - - */
				if (board[i][j] == GameBoard.EmptyCell &&
						board[i+1][j] == GameBoard.EmptyCell && board[i+2][j] == player &&
						board[i+3][j] == GameBoard.EmptyCell){
					allRowOnes++; /* We have a possible option of completing it in the future */
					
					/* Immediate possibility of completing 4-in-a-row (stronger) */
					if (j == discsInCol[i] && j == discsInCol[i+1] && j == discsInCol[i+3]){
						oneInRow++;
					}
				}
				
				/*  _ _ _ _
				 * | | | |O|
				 *  - - - - */
				if (board[i][j] == GameBoard.EmptyCell &&
						board[i+1][j] == GameBoard.EmptyCell &&
						board[i+2][j] == GameBoard.EmptyCell &&
						board[i+3][j] == player){
					if (!isLegalIndex(i+4,j)){
						allRowOnes++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility of completing 4-in-a-row (stronger) */
						if (j == discsInCol[i] && j == discsInCol[i+1] && j == discsInCol[i+2]){
							oneInRow++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i+4][j] != player){
						allRowOnes++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility of completing 4-in-a-row (stronger) */
						if (j == discsInCol[i] && j == discsInCol[i+1] && j == discsInCol[i+2]){
							oneInRow++;
						}
					}
				}
				
				/* Count twos */
				/*  _ _ _ _
				 * |O|O| | |
				 *  - - - - */
				if (board[i][j] == player && board[i+1][j] == player &&
						board[i+2][j] == GameBoard.EmptyCell &&
						board[i+3][j] == GameBoard.EmptyCell){
					/* If left index is not legal, we are at left edge. */
					if (!isLegalIndex(i-1, j)){
						allRowTwos++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility to complete 4-in-a-row (stronger) */
						if (j == discsInCol[i+2] && j == discsInCol[i+3]){
							twoInRow++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i-1][j] != player){
						allRowTwos++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility to complete 4-in-a-row (stronger) */
						if (j == discsInCol[i+2] && j == discsInCol[i+3]){
							twoInRow++;
						}
					}
				}
				
				/*  _ _ _ _
				 * | |O|O| |
				 *  - - - - */
				if (board[i][j] == GameBoard.EmptyCell &&
						board[i+1][j] == player && board[i+2][j] == player &&
						board[i+3][j] == GameBoard.EmptyCell){
					allRowTwos++; /* We have a possible option of completing it in the future */
					
					/* Immediate possibility to complete 4-in-a-row (stronger) */
					if (j == discsInCol[i] && j == discsInCol[i+3]){
						twoInRow++;
					}
				}
				
				/*  _ _ _ _
				 * | | |O|O|
				 *  - - - - */
				if (board[i][j] == GameBoard.EmptyCell
						&& board[i+1][j] == GameBoard.EmptyCell &&
						board[i+2][j] == player && board[i+3][j] == player){
					/* If left index is not legal, we are at left edge. */
					if (!isLegalIndex(i+4, j)){
						allRowTwos++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility to complete 4-in-a-row (stronger) */
						if (j == discsInCol[i] && j == discsInCol[i+1]){
							twoInRow++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i+4][j] != player){
						allRowTwos++; /* We have a possible option of completing it in the future */
						
						/* Immediate possibility to complete 4-in-a-row (stronger) */
						if (j == discsInCol[i] && j == discsInCol[i+1]){
							twoInRow++;
						}
					}
				}
				
				
				/* Count blocked threes */
				/* Need to count separately blocked threes and open threes
				 *  _ _ _ _
				 * |O|O|O| |
				 *  - - - -
				 */
				if (board[i][j] == player && board[i+1][j] == player && board[i+2][j] == player &&
						board[i+3][j] == GameBoard.EmptyCell){
					if (!isLegalIndex(i-1,j)){
						allRowThrees++; /* Count it first as a general three */
						
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i+3]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i+3]){
							threesHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i+3]){
							threesHole2++;
						}
					}
					/* Else, the position is legal, so we count it iff it is not our player disc */
					else if(board[i-1][j] != player){
						allRowThrees++; /* Count it first as a general three */
						
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i+3]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i+3]){
							threesHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i+3]){
							threesHole2++;
						}
					}
				}
				
				/*
				 *  _ _ _ _
				 * | |O|O|O|
				 *  - - - -
				 */
				if (board[i][j] == GameBoard.EmptyCell && board[i+1][j] == player &&
						board[i+2][j] == player && board[i+3][j] == player){
					if (!isLegalIndex(i+4,j)){
						allRowThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i]){
							threesHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i]){
							threesHole2++;
						}
					} else if (board[i+4][j] != player){
						allRowThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i]){
							threesHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i]){
							threesHole2++;
						}
					}
				}
				
				/* Count open threes.
				 * We note that this three was already counted as a general three (when
				 * counting blocked three), and that it was counted for holes1&2 on both sides.
				 * So, we only need to count it as an open three.
				 * */
				/*
				 *  _ _ _ _ _
				 * | |O|O|O| |
				 *  - - - - -
				 */
				
				if (board[i][j] == player && board[i+1][j] == player && board[i+2][j] == player){
					if (isLegalIndex(i-1,j) && isLegalIndex(i+3,j) &&
							board[i-1][j] == GameBoard.EmptyCell &&
							board[i+3][j] == GameBoard.EmptyCell){ 
						/* Immediate open three that can be completed to four, both sides. */
						if (j == discsInCol[i-1] && j == discsInCol[i+3]){
							openThree++;
						}
					}
				}
				
				/* Count fours. We search in sequences of four whether all the sequence is populated by the player's
				 * discs. If so, and in order to count OOOOO for example as one instance of four-in-a-row,
				 * we check: if index to our left is illegal, then we are at the left edge, so count the four-in-a-row.
				 * Else, the index is legal and in case the cell to our left is not ours, then we count this instance
				 * of four-in-a-row. This way we avoid counting OOOOO twice (it will be counted only once). */
				if (board[i][j] == player && board[i+1][j] == player && board[i+2][j] == player && board[i+3][j] == player){
					if (!isLegalIndex(i-1, j)){
						fourInRow++;
					} else if (board[i-1][j] != player){
						fourInRow++;
					}
				}
			
			}
			
			
		}
		
		
		/* Add features to vector - we decided to use less features in our final
		 * implementation, but it seems like a waste to delete all the counts for the
		 * unused features. Since the performance is basically the same, we decided
		 * not to put comments on the features, count them and allow their easy insertion
		 * in the future. */
	//	playerState.addValueToIndex(GameBoardUpdated.OneInARow, oneInRow);
	//	playerState.addValueToIndex(GameBoardUpdated.AllRowOnes, allRowOnes);
		playerState.addValueToIndex(GameBoard.TwoInARow, twoInRow);
	//	playerState.addValueToIndex(GameBoardUpdated.AllRowTwos, allRowTwos);
		playerState.addValueToIndex(GameBoard.OneSideThreeInARow, blockedThree);
		playerState.addValueToIndex(GameBoard.TwoSideThreeInARow, openThree);
		playerState.addValueToIndex(GameBoard.AllRowThrees, allRowThrees);
		playerState.addValueToIndex(GameBoard.ThreeInARowHole1, threesHole1);
		playerState.addValueToIndex(GameBoard.ThreeInARowHole2, threesHole2);
	//	playerState.addValueToIndex(GameBoardUpdated.FourInARow, fourInRow);
		
		/* Set a four in a row if it is reached */
		g.setFour(player, fourInRow);
	
	}
	
	/**
	 * Count diagonal-related features, and update the vector object accordingly.
	 * The counts will be conducted in a similar manner to the row-counts.
	 * The only thing we need to take into consideration is that now we count both diagonals
	 * to the right and diagonals to the left.
	 * 
	 * @param g The board representation that we want to run the counts on.
	 * @param playerState A vector holding the current state of the player.
	 * @param player The player for whom we want to count features.
	 */
	public static void countDiagonals(GameBoard g, Vector playerState, int player){
		int[]discsInCol = g.getDiscsPerColumn();
		int [][] board = g.getBoard(); 
		
		int openThree = 0;
		int blockedThree = 0;
		int allThrees = 0;
		int threeHole1 = 0;
		int threeHole2 = 0;
		int twoDiagonal = 0;
		int allTwos = 0;
		int fourInRow = 0;
		int oneMoveToWin = 0;
		int prohibitedMove = 0;
		
		for (int j = 0; j < 3; j++){
			
			/*
			 * *****************************
			 * Count diagonals to the right
			 * *****************************
			 * */
			for (int i = 0; i < GameBoard.NumOfColumns - 3; i++){
				/* Count twos */
				/*    _
				 *   _
				 *  O
				 * O
				 **/
				if (board[i][j] == player && board[i+1][j+1] == player &&
						board[i+2][j+2] == GameBoard.EmptyCell &&
						board[i+3][j+2] == GameBoard.EmptyCell){
					/* If down-left index is not legal, we are at first row. */
					if (!isLegalIndex(i-1, j-1)){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-diagonal (stronger) */
						if (j+2 == discsInCol[i+2] && j+3 == discsInCol[i+3]){
							twoDiagonal++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i-1][j-1] != player){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-diagonal (stronger) */
						if (j+2 == discsInCol[i+2] && j+3 == discsInCol[i+3]){
							twoDiagonal++;
						}
					}
				}
				
				/*    _
				 *   O
				 *  O
				 * _
				 **/
				if (board[i][j] == GameBoard.EmptyCell &&
						board[i+1][j+1] == player && board[i+2][j+2] == player &&
						board[i+3][j+3] == GameBoard.EmptyCell){
					allTwos++;
					
					/* Immediate possibility to complete 4-in-a-row. */
					if (j == discsInCol[i] && j+3 == discsInCol[i+3]){
						twoDiagonal++;
					}
				}
				
				/*    O
				 *   O
				 *  _
				 * _
				 **/
				if (board[i][j] == GameBoard.EmptyCell
						&& board[i+1][j+1] == GameBoard.EmptyCell &&
						board[i+2][j+2] == player && board[i+3][j+3] == player){
					/* If up-right index is not legal, we are at right edge. */
					if (!isLegalIndex(i+4, j+4)){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-row. */
						if (j == discsInCol[i] && j+1 == discsInCol[i+1]){
							twoDiagonal++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i+4][j+4] != player){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-row. */
						if (j == discsInCol[i] && j+1 == discsInCol[i+1]){
							twoDiagonal++;
						}
					}
				}
				
				/* Count blocked threes */
				/*    _
				 *   O
				 *  O
				 * O
				 **/
				if (board[i][j] == player && board[i+1][j+1] == player && board[i+2][j+2] == player &&
						board[i+3][j+3] == GameBoard.EmptyCell){
					if (!isLegalIndex(i-1,j-1)){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j+3 == discsInCol[i+3]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j+3-1 == discsInCol[i+3]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j+3-2 == discsInCol[i+3]){
							threeHole2++;
						}
					} else if (board[i-1][j-1] != player){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j+3 == discsInCol[i+3]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j+3-1 == discsInCol[i+3]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j+3-2 == discsInCol[i+3]){
							threeHole2++;
						}
					}
				}
				
				/*    O
				 *   O
				 *  O
				 * _
				 **/
				if (board[i][j] == GameBoard.EmptyCell && board[i+1][j+1] == player &&
						board[i+2][j+2] == player && board[i+3][j+3] == player){
					if (!isLegalIndex(i+4,j+4)){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i]){
							threeHole2++;
						}
					} else if (board[i+4][j+4] != player){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i]){
							threeHole2++;
						}
					}
				}
				
				/* Count open threes */
				/*      _
				 *    O
				 *   O
				 *  O
				 * _
				 **/
				
				if (board[i][j] == player && board[i+1][j+1] == player && board[i+2][j+2] == player){
					if (isLegalIndex(i-1,j-1) && isLegalIndex(i+3,j+3) &&
							board[i-1][j-1] == GameBoard.EmptyCell &&
							board[i+3][j+3] == GameBoard.EmptyCell){
						/* Immediate open three that can be completed to four, both sides. */
						if (j-1 == discsInCol[i-1] && j+3 == discsInCol[i+3]){
							openThree++;
						}
					}
				}
				
				/* Count fours. We search in sequences of four whether all the sequence is populated by the player's
				 * discs. If so, and in order to count OOOOO for example as one instance of four-in-a-row,
				 * we check: if index to our left is illegal, then we are at the left edge, so count the four-in-a-row.
				 * Else, the index is legal and in case the cell to our left is not ours, then we count this instance
				 * of four-in-a-row. This way we avoid counting OOOOO twice (it will be counted only once). */
				if (board[i][j] == player && board[i+1][j+1] == player && board[i+2][j+2] == player && board[i+3][j+3] == player){
					if (!isLegalIndex(i-1, j-1)){
						fourInRow++;
					} else if (board[i-1][j-1] != player){
						fourInRow++;
					}
				}
				
			}
			
			
			/*
			 ******************************* 
			 * Count diagonals to the left
			 *******************************
			 */
			for (int i = GameBoard.NumOfColumns - 1; i > 2; i--){
				/* Count twos */
				/* _
				 *  _
				 *   O
				 *    O
				 **/
				if (board[i][j] == player && board[i-1][j+1] == player &&
						board[i-2][j+2] == GameBoard.EmptyCell &&
						board[i-3][j+2] == GameBoard.EmptyCell){
					/* If down-right index is not legal, we are at first row or at the right edge. */
					if (!isLegalIndex(i+1, j-1)){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-row and a general two in a row */
						if (j+2 == discsInCol[i-2] && j+3 == discsInCol[i-3]){
							twoDiagonal++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i+1][j-1] != player){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-row. */
						if (j+2 == discsInCol[i-2] && j+3 == discsInCol[i-3]){
							twoDiagonal++;
						}
					}
				}
				
				/* _
				 *  O
				 *   O
				 *    _
				 **/
				if (board[i][j] == GameBoard.EmptyCell &&
						board[i-1][j+1] == player && board[i-2][j+2] == player &&
						board[i-3][j+3] == GameBoard.EmptyCell){
					allTwos++;
					
					/* Immediate possibility to complete 4-in-a-row. */
					if (j == discsInCol[i] && j+3 == discsInCol[i-3]){
						twoDiagonal++;
					}
				}
				
				/* O
				 *  O
				 *   _
				 *    _
				 **/
				if (board[i][j] == GameBoard.EmptyCell
						&& board[i-1][j+1] == GameBoard.EmptyCell &&
						board[i-2][j+2] == player && board[i-3][j+3] == player){
					/* If up-left index is not legal, we are at left edge. */
					if (!isLegalIndex(i-4, j+4)){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-row. */
						if (j == discsInCol[i] && j+1 == discsInCol[i-1]){
							twoDiagonal++;
						}
					}
					/* Else, index is legal. Doesn't really matter what is in that cell,
					 * as long as it is not our disc. */
					else if (board[i-4][j+4] != player){
						allTwos++;
						
						/* Immediate possibility to complete 4-in-a-row. */
						if (j == discsInCol[i] && j+1 == discsInCol[i-1]){
							twoDiagonal++;
						}
					}
				}
				
				/* Count blocked threes */
				/* _
				 *  O
				 *   O
				 *    O
				 **/
				if (board[i][j] == player && board[i-1][j+1] == player && board[i-2][j+2] == player &&
						board[i-3][j+3] == GameBoard.EmptyCell){
					if (!isLegalIndex(i+1,j-1)){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j+3 == discsInCol[i-3]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j+3-1 == discsInCol[i-3]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j+3-2 == discsInCol[i-3]){
							threeHole2++;
						}
					} else if (board[i+1][j-1] != player){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j+3 == discsInCol[i-3]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j+3-1 == discsInCol[i-3]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j+3-2 == discsInCol[i-3]){
							threeHole2++;
						}
					}
				}
				
				/* O
				 *  O
				 *   O
				 *    _
				 **/
				if (board[i][j] == GameBoard.EmptyCell && board[i-1][j+1] == player &&
						board[i-2][j+2] == player && board[i-3][j+3] == player){
					if (!isLegalIndex(i-4,j+4)){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i]){
							threeHole2++;
						}
					} else if (board[i-4][j+4] != player){
						allThrees++; /* Count it first as a general three */
						/* Immediate possibility to complete 4-in-a-row */
						if (j == discsInCol[i]){
							blockedThree++;
						}
						/* Else, we have a hole of one disc to complete 4-in-a-row */
						else if (j-1 == discsInCol[i]){
							threeHole1++;
						}
						/* Else, we have a hole of two discs to complete 4-in-a-row */
						else if (j-2 == discsInCol[i]){
							threeHole2++;
						}
					}
				}
				
				/* Count open threes */
				/* _
				 *  O
				 *   O
				 *    O
				 *      _
				 **/
				
				if (board[i][j] == player && board[i-1][j+1] == player && board[i-2][j+2] == player){
					if (isLegalIndex(i+1,j-1) && isLegalIndex(i-3,j+3) &&
							board[i+1][j-1] == GameBoard.EmptyCell &&
							board[i-3][j+3] == GameBoard.EmptyCell){ 
						/* Immediate open three that can be completed to four, both sides. */
						if (j-1 == discsInCol[i+1] && j+3 == discsInCol[i-3]){
							openThree++;
						}

					}
				}
				
				/* Count fours. We search in sequences of four whether all the sequence is populated by the player's
				 * discs. If so, and in order to count OOOOO for example as one instance of four-in-a-row,
				 * we check: if index to our left is illegal, then we are at the left edge, so count the four-in-a-row.
				 * Else, the index is legal and in case the cell to our left is not ours, then we count this instance
				 * of four-in-a-row. This way we avoid counting OOOOO twice (it will be counted only once). */
				if (board[i][j] == player && board[i-1][j+1] == player && board[i-2][j+2] == player && board[i-3][j+3] == player){
					if (!isLegalIndex(i+1, j-1)){
						fourInRow++;
					} else if (board[i+1][j-1] != player){
						fourInRow++;
					}
				}
				
			}
		}
		
		/* Add features to vector - we decided to use less features in our final
		 * implementation, but it seems like a waste to delete all the counts for the
		 * unused features. Since the performance is basically the same, we decided
		 * not to put comments on the features, count them and allow their easy insertion
		 * in the future. */
		playerState.addValueToIndex(GameBoard.TwoSideThreeInADiagonal, openThree);
		playerState.addValueToIndex(GameBoard.OneSideThreeInADiagonal, blockedThree);
		playerState.addValueToIndex(GameBoard.AllDiagonalThrees, allThrees);
		playerState.addValueToIndex(GameBoard.ThreeInADiagonalHole1, threeHole1);
		playerState.addValueToIndex(GameBoard.ThreeInADiagonalHole2, threeHole2);
		playerState.addValueToIndex(GameBoard.TwoInADiagonal, twoDiagonal);
	//	playerState.addValueToIndex(GameBoardUpdated.AllDiagonalTwos, allTwos);
	//	playerState.addValueToIndex(GameBoardUpdated.FourInARow, fourInRow);
		playerState.addValueToIndex(GameBoard.OneMoveToWin, oneMoveToWin);
		playerState.addValueToIndex(GameBoard.ProhibitedMove, prohibitedMove);
		
		/* Set a four in a row if it is reached */
		g.setFour(player, fourInRow);
		
	}
	
	/**
	 * Count special features, and update the vector object accordingly.
	 * The counts will be conducted in the following way:
	 * For the potential four feature, we use an aid matrix of the size of the board,
	 * which contains true for every cell that can be a potential four of the player.
	 * We check all the surroundings of a given empty cell, and if one of them can be used
	 * in a potential four, this feature is counted.
	 * For the win columns feature, we simply traverse the same matrix, looking for 
	 * two cells at the bottom that are both true, i.e. both can be a potential four of the player.
	 * For one-move-to-win, search for a cell in the bottom of each column which is true.
	 * For prohibited move, search for two bottom cells which the upper one is the opponent
	 * win move and the lower one is not ours nor the opponent.
	 * 
	 * @param g The board representation that we want to run the counts on.
	 * @param playerState A vector holding the current state of the player.
	 * @param player The player for whom we want to count features.
	 */
	public static void countPotentialFours(GameBoard g, Vector playerState, int player){
		int[]discsInCol = g.getDiscsPerColumn(); 
		int highestDisc = g.getHighestDisc(); 
		int [][] board = g.getBoard(); 
		
		int numPotentialFours = 0;
		int winColumns = 0;
		int prohibitedMoves = 0;
		int oneMoveToWin = 0;
		int oneMoveToWinHole = 0;
		
		int opponent = 3 - player;
		boolean[][] playerPotentialFours = new boolean[GameBoard.NumOfColumns][GameBoard.NumOfRows];
		boolean[][] opponentPotentialFours = new boolean[GameBoard.NumOfColumns][GameBoard.NumOfRows];
		
		for (int j = 0; j < GameBoard.NumOfRows; j++){
			
			for (int i = 0; i < GameBoard.NumOfColumns; i++){
				
				/* If the current row j is two rows above the row of the highest disc,
				 * then we don't need to traverse it (no potential fours there). */
				if (j > highestDisc){
					playerPotentialFours[i][j] = false;
					opponentPotentialFours[i][j] = false;
					continue;
				}
				
				/* If this is not an empty cell, then we cannot use it as a potential four. */
				if (board[i][j] != GameBoard.EmptyCell){
					playerPotentialFours[i][j] = false;
					opponentPotentialFours[i][j] = false;
					continue;
				}
				
				/* Reaching here, we know that the cell is empty. Start searching for the following
				 * potential fours:
				 * a) Potential completion of 3-in-a-row (4 cases).
				 * b) Potential completion of 3-in-a-column (1 case).
				 * c) Potential completion of 3-in-a-diagonal (4 cases * 2 sides).
				 * */
				
				
				/* For potential four-in-a-row */
				/* 
				 * OOO_
				 */
				/* Player */
				if (isLegalIndex(i-3,j) && board[i-3][j] == player &&
						board[i-2][j] == player && board[i-1][j] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i-3,j) && board[i-3][j] == opponent &&
						board[i-2][j] == opponent && board[i-1][j] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/* 
				 * OO_O
				 */
				/* Player */
				if (isLegalIndex(i-2,j) && isLegalIndex(i+1,j) &&
						board[i+1][j] == player && board[i-1][j] == player && board[i-2][j] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i-2,j) && isLegalIndex(i+1,j) &&
						board[i+1][j] == opponent && board[i-1][j] == opponent && board[i-2][j] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/* 
				 * O_OO
				 */
				/* Player */
				if (isLegalIndex(i+2,j) && isLegalIndex(i-1,j) &&
						board[i+2][j] == player && board[i+1][j] == player && board[i-1][j] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i+2,j) && isLegalIndex(i-1,j) &&
						board[i+2][j] == opponent && board[i+1][j] == opponent && board[i-1][j] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/* 
				 * _OOO
				 */
				/* Player */
				if (isLegalIndex(i+3,j) && board[i+3][j] == player &&
						board[i+2][j] == player && board[i+1][j] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i+3,j) && board[i+3][j] == opponent &&
						board[i+2][j] == opponent && board[i+1][j] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/* For potential four-in-a-column */
				/*
				 * _
				 * O
				 * O
				 * O
				 */
				/* Player */
				if (isLegalIndex(i, j-3) && board[i][j-1] == player && board[i][j-2] == player &&
						board[i][j-3] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i, j-3) && board[i][j-1] == opponent && board[i][j-2] == opponent &&
						board[i][j-3] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/* For potential four-in-a-diagonal (to the left) */
				/*
				 * _
				 *  O
				 *   O
				 *    O
				 */
				/* Player */
				if (isLegalIndex(i+3,j-3) && board[i+1][j-1] == player && board[i+2][j-2] == player
						&& board[i+3][j-3] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i+3,j-3) && board[i+1][j-1] == opponent && board[i+2][j-2] == opponent
						&& board[i+3][j-3] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/*
				 * O
				 *  _
				 *   O
				 *    O
				 */
				/* Player */
				if (isLegalIndex(i-1,j+1) && isLegalIndex(i+2, j-2) &&
						board[i-1][j+1] == player && board[i+1][j-1] == player
						&& board[i+2][j-2] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i-1,j+1) && isLegalIndex(i+2, j-2) &&
						board[i-1][j+1] == opponent && board[i+1][j-1] == opponent
						&& board[i+2][j-2] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/*
				 * O
				 *  O
				 *   _
				 *    O
				 */
				/* Player */
				if (isLegalIndex(i-2,j+2) && isLegalIndex(i+1, j-1) &&
						board[i-2][j+2] == player && board[i-1][j+1] == player
						&& board[i+1][j-1] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i-2,j+2) && isLegalIndex(i+1, j-1) &&
						board[i-2][j+2] == opponent && board[i-1][j+1] == opponent
						&& board[i+1][j-1] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/*
				 * O
				 *  O
				 *   O
				 *    _
				 */
				/* Player */
				if (isLegalIndex(i-3,j+3) && board[i-3][j+3] == player &&
						board[i-2][j+2] == player && board[i-1][j+1] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i-3,j+3) && board[i-3][j+3] == opponent &&
						board[i-2][j+2] == opponent && board[i-1][j+1] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				
				/* For potential four-in-a-diagonal (to the right) */
				/*
				 *    _
				 *   O
				 *  O
				 * O   
				 */
				/* Player */
				if (isLegalIndex(i-3,j-3) && board[i-1][j-1] == player && board[i-2][j-2] == player
						&& board[i-3][j-3] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i-3,j-3) && board[i-1][j-1] == opponent && board[i-2][j-2] == opponent
						&& board[i-3][j-3] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/*
				 *    O
				 *   _
				 *  O
				 * O
				 */
				/* Player */
				if (isLegalIndex(i+1,j+1) && isLegalIndex(i-2, j-2) &&
						board[i+1][j+1] == player && board[i-1][j-1] == player
						&& board[i-2][j-2] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i+1,j+1) && isLegalIndex(i-2, j-2) &&
						board[i+1][j+1] == opponent && board[i-1][j-1] == opponent
						&& board[i-2][j-2] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/*
				 *    O
				 *   O
				 *  _
				 * O
				 */
				/* Player */
				if (isLegalIndex(i+2,j+2) && isLegalIndex(i-1, j-1) &&
						board[i+2][j+2] == player && board[i+1][j+1] == player
						&& board[i-1][j-1] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* 	Opponent */
				if (isLegalIndex(i+2,j+2) && isLegalIndex(i-1, j-1) &&
						board[i+2][j+2] == opponent && board[i+1][j+1] == opponent
						&& board[i-1][j-1] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/*
				 *    O
				 *   O
				 *  O
				 * _
				 */
				/* Player */
				if (isLegalIndex(i+3,j+3) && board[i+3][j+3] == player &&
						board[i+2][j+2] == player && board[i+1][j+1] == player){
					playerPotentialFours[i][j] = true;
				}
				
				/* Opponent */
				if (isLegalIndex(i+3,j+3) && board[i+3][j+3] == opponent &&
						board[i+2][j+2] == opponent && board[i+1][j+1] == opponent){
					opponentPotentialFours[i][j] = true;
				}
				
				/* If some check worked, then this cell is part of a potential four. */
				if (playerPotentialFours[i][j]){
					numPotentialFours++;
				}
				
			}
		}
		
		/* Count win columns and prohibited moves */
		for (int i = 0; i < GameBoard.NumOfColumns; i++){
			/* If we can insert two discs in the column, then we might have a win column */
			if (discsInCol[i] <= GameBoard.NumOfRows - 2){
				/* Win column - we have two possibilities of completing a four-in-a-row,
				 * and our opponent can't win. */
				if (playerPotentialFours[i][discsInCol[i]] &&
						playerPotentialFours[i][discsInCol[i] + 1] &&
						!opponentPotentialFours[i][discsInCol[i]]){
					winColumns++;
				}
				
				/* Prohibited move - if we put our disc there, we will loose. */
				if (!playerPotentialFours[i][discsInCol[i]] &&
						opponentPotentialFours[i][discsInCol[i] + 1]){
					prohibitedMoves += FeatureCount.AddCoercedMove(g, i, 2, player);
				}
				
				if (!playerPotentialFours[i][discsInCol[i]] &&
						!opponentPotentialFours[i][discsInCol[i]] &&
						playerPotentialFours[i][discsInCol[i] + 1]){
					oneMoveToWinHole++;
				}
			}
			
			if (!g.isColumnFull(i) && playerPotentialFours[i][discsInCol[i]]){
				oneMoveToWin += FeatureCount.AddCoercedMove(g, i, 1, player);
			}
			
		}
		
		playerState.addValueToIndex(GameBoard.PotentialFour, numPotentialFours);
		playerState.addValueToIndex(GameBoard.WinColumns, winColumns);
		playerState.addValueToIndex(GameBoard.ProhibitedMove, prohibitedMoves);
		playerState.addValueToIndex(GameBoard.OneMoveToWin, oneMoveToWin);
		playerState.addValueToIndex(GameBoard.OneMoveToWinHole, oneMoveToWinHole);

	}
	
	/**
	 * This method counts all the relevant features of the state.
	 * The vector will be returned.
	 * 
	 * @param g The board representation that we want to run the counts on.
	 * @param player The player for whom we want to count features.
	 * 
	 * @return a vector representing the counts for the player.
	 */
	public static Vector CountFeatures(GameBoard g, int player){
		Vector v = new Vector(GameBoard.PlayerVectorSize);
		
		if (player == GameBoard.RedPlayer){
			g.Player1ForcedWin.clear();
			g.Player1ProhibitedMoves.clear();
		} else {
			g.Player2ForcedWin.clear();
			g.Player2ProhibitedMoves.clear();
		}
		
		/* Count Columns */
		countColumns(g, v, player);
		
		/* Count Rows */
		countRows(g, v, player);
		
		/* Count Diagonals */
		countDiagonals(g, v, player);
		
		/* Count Special Features */
		countPotentialFours(g, v, player);
		
		return v;
	}
	
	/**
	 * This procedure checks whether a given pair of indices meets the criteria of the board.
	 * @param column the column index.
	 * @param row the row index.
	 * 
	 * @return true iff the indices are a legal position in the board.
	 */
	public static boolean isLegalIndex(int column, int row){
		boolean legalColumn = column >= 0 && column < GameBoard.NumOfColumns;
		boolean legalRow = row >= 0 && row < GameBoard.NumOfRows;
		
		return legalColumn && legalRow;
	}
	
	/**
	 * Add a coerced move to the right list - either a move that assures a win to the
	 * player, or a move that will cost the player the game.
	 * 
	 * @param move the column we want to make our move in.
	 * @param moveType 1 for win move and 2 for lose move.
	 * @param player the player for which we check that features.
	 * 
	 * @return 1 if this move should be counted (was not counted before), 0 otherwise.
	 */
	public static int AddCoercedMove(GameBoard g, int move, int moveType, int player){
		int count = 0;
		if (player == GameBoard.RedPlayer){
			if (moveType == 1 && !g.Player1ForcedWin.contains(move)){
				g.Player1ForcedWin.add(move);
				count++;
			} else if (moveType == 2 && !g.Player1ProhibitedMoves.contains(move)){
				g.Player1ProhibitedMoves.add(move);
				count++;
			}
		} else {
			if (moveType == 1 && !g.Player2ForcedWin.contains(move)){
				g.Player2ForcedWin.add(move);
				count++;
			} else if (moveType == 2 && !g.Player2ProhibitedMoves.contains(move)){
				g.Player2ProhibitedMoves.add(move);
				count++;
			}
		}
		
		return count;
	}
	
}

