/* '='='=' '@' '='='='='='='='='=' '@' '='='='='='='='='=' '@' '='='='| */
/* ='='=' '@'@' '='='='='='='='=' '@'@' '='='='='='='='=' '@'@' '='='=| */
/* '='=' '@':'@' '='='='='='='=' '@':'@' '='='='='='='=' '@':'@' '='='| */
/* ='=' '@':':'@' '='='='='='=' '@':':'@' '='='='='='=' '@':':'@' '='=| */
/* '=' '@':':':'@' '='='='='=' '@':':':'@' '='='='='=' '@':':':'@' '='| */
/* =' '@':':':':'@' '='='='=' '@':':':':'@' '='='='=' '@':':':':'@' '=| */
/* ' '@':'                                                       '@' '| */
/*  '@'         3rd Year Project - ROY SCHESTOWITZ - 2002          @' | */
/* '@                                                               @'| */
/* @':':':':':':':':'@' ' '@':':':':':':':':'@' ' '@':':':':':':':':'@| */
/* ':':':':':':':':':'@' '@':':':':':':':':':'@' '@':':':':':':':':':'| */
/* :':':':':':':':':':'@'@':':':':':':':':':':'@'@':':':':':':':':':':| */
/* ':':':': : :':':':':'@':':':':': : :':':':':'@':':':':': : :':':':'| */
/*  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/*              Name:           misc.c                                  */
/*              Version:        0.6.6                                   */
/*              Date:           12/2/2003                               */
/*                                                                      */
/*              Misc. basic game procedures                             */
/*                                                                      */
/*  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */

#include "misc.h"



/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* reducible - determines whether a move/placement is legal for a given      */
/* colour/side in an i,j coordinate on the board                              */
/* inputs: color of the player whose turn it is; the i and j board            */
/* coordinates which are virtually the X,Y position of the board at which     */
/* the stone is to be put (progressing left to right, top to bottom;          */
/* the board to be dealt with                                                 */
/* returns: boolean indicating is the placement is legal or not               */
/*                                                                            */
/*                                                                            */


int
reducible ( int i, int j, int color, board_map board )
{
  int moved;			/* indicates if the board pointer has moved */

  if ( board.slot[i][j] == NONE )
    {
      int temp = i + 1;		/* temporary position value             */
      int temp2;		/* second temporary position value      */
      int player_color = RED;	/* the color of the object just put     */
      int opponent_color = BLACK;	/* the color of the opponent */

      if ( color == BLACK )	/* initialise the 2 above values */
	{
	  player_color = BLACK;
	  opponent_color = RED;
	}
      if ( color == RED )
	{
	  opponent_color = BLACK;
	  player_color = RED;
	}

      moved = FALSE;		/* set pointer movement to false */
      while ( board.slot[temp][j] == opponent_color )
	/* while position to bottom is occupied by opponent */
	{
	  temp++;		/* step downwards */
	  moved = TRUE;		/* and indicate board pointer move */
	}
      if ( board.slot[temp][j] == player_color && moved == TRUE )
	return TRUE;
      /* if the pointer has been moved and the current player's colour is */
      /* pointed at, return true to indicate 'reduceability'              */

      /* see the above for explanation */
      temp = i - 1;
      moved = FALSE;

      while ( board.slot[temp][j] == opponent_color )
	{
	  temp--;
	  moved = TRUE;
	}
      if ( board.slot[temp][j] == player_color && moved == TRUE )
	return TRUE;

      /* see the above for explanation */
      temp = j - 1;
      moved = FALSE;

      while ( board.slot[i][temp] == opponent_color )
	{
	  temp--;
	  moved = TRUE;
	}
      if ( board.slot[i][temp] == player_color && moved == TRUE )
	return TRUE;

      /* see the above for explanation */
      temp = j + 1;
      moved = FALSE;

      while ( board.slot[i][temp] == opponent_color )
	{
	  temp++;
	  moved = TRUE;
	}
      if ( board.slot[i][temp] == player_color && moved == TRUE )
	return TRUE;


      /****************************************/
      /* diagonal reductions                  */

      temp = j + 1;		/* step right                      */
      temp2 = i + 1;		/* step down                       */
      moved = FALSE;		/* board pointer has not moved yet */

      while ( board.slot[temp2][temp] == opponent_color )
	/* while opponent's colour is pointed at */
	{
	  temp++;		/* step further to the right      */
	  temp2++;		/* step further to the bottom     */
	  moved = TRUE;		/* indicate board pointer move */
	}
      if ( board.slot[temp2][temp] == player_color && moved == TRUE )
	return TRUE;
      /* if pointer has moved and reached current player's          */
      /* color return true to indicate that a reduction is possible */


      /* see the above - different diagonal directions here */

      temp = j - 1;
      temp2 = i + 1;
      moved = FALSE;
      while ( board.slot[temp2][temp] == opponent_color )
	{
	  temp--;
	  temp2++;
	  moved = TRUE;
	}
      if ( board.slot[temp2][temp] == player_color && moved == TRUE )
	return TRUE;

      /* see the above - different diagonal directions here */

      temp = j - 1;
      temp2 = i - 1;
      moved = FALSE;

      while ( board.slot[temp2][temp] == opponent_color )
	{
	  temp--;
	  temp2--;
	  moved = TRUE;
	}
      if ( board.slot[temp2][temp] == player_color && moved == TRUE )
	return TRUE;

      /* see the above - different diagonal directions here */

      temp = j + 1;
      temp2 = i - 1;
      moved = FALSE;

      while ( board.slot[temp2][temp] == opponent_color )
	{
	  temp++;
	  temp2--;
	  moved = TRUE;
	}
      if ( board.slot[temp2][temp] == player_color && moved == TRUE )
	return TRUE;

    }
  return FALSE;
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/




/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* calculatescore - calculates the current score for red and black            */
/*                                                                            */
/*                                                                            */


void
calculatescore ( void )
{
  int i,
    j;				/* indices                    */

  redscore = 0;			/* initisalise the score to 0 */
  blackscore = 0;		/* initisalise the score to 0 */
  for ( i = 1; i < 9; i++ )
    for ( j = 1; j < 9; j++ )
      {
	if ( board.slot[i][j] == BLACK )	/* if slot is occupied by BLACK */
	  blackscore++;		/* increment the score of BLACK */
	if ( board.slot[i][j] == RED )	/* if slot is occupied by RED   */
	  redscore++;		/* increment the score of RED   */
      }
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/





/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* reduce - a function used to do all the Othello-wise reductions and         */
/* substitutions in colours of the objects.                                   */
/* inputs - the coordinates of the last stone put, according to which         */
/* the correct reductions can be carried out;                                 */
/* the board to be dealt with                                                 */
/* outputs - the new layout of the board                                      */
/*                                                                            */
/*                                                                            */


board_map
reduce ( int i, int j, board_map board )
{
  int temp = i + 1;		/* temporary board pointer              */
  int temp2;			/* and another for diagonal check       */
  int player_color = RED;	/* the color of the object just put     */
  int opponent_color = BLACK;	/* the color of the opponent            */

  if ( board.slot[i][j] == BLACK )	/* initialise the above values  */
    {
      player_color = BLACK;	/* extracting the player's colour   */
      opponent_color = RED;	/* extracting the opponent's colour */
    }
  if ( board.slot[i][j] == RED )	/* and same for RED */
    {
      opponent_color = BLACK;
      player_color = RED;
    }


  while ( board.slot[temp][j] == opponent_color )
    /* progress while pointing at opponent's colour */
    temp++;
  if ( board.slot[temp][j] == player_color )
    /* if reached current player's stone i.e. reduction possible */
    {
      temp = i + 1;		/* go back to initial position */
      while ( board.slot[temp][j] == opponent_color )
	/* while pointing at opponent's stone */
	{
	  board.slot[temp][j] = player_color;	/* flip stone */
	  temp++;		/* and step to next stone */
	}
    }

  temp = i - 1;			/* see the above */

  while ( board.slot[temp][j] == opponent_color )
    temp--;
  if ( board.slot[temp][j] == player_color )
    {
      temp = i - 1;
      while ( board.slot[temp][j] == opponent_color )
	{
	  board.slot[temp][j] = player_color;
	  temp--;
	}
    }

  temp = j - 1;			/* see the above */

  while ( board.slot[i][temp] == opponent_color )
    temp--;
  if ( board.slot[i][temp] == player_color )
    {
      temp = j - 1;
      while ( board.slot[i][temp] == opponent_color )
	{
	  board.slot[i][temp] = player_color;
	  temp--;
	}
    }

  temp = j + 1;			/* see the above */

  while ( board.slot[i][temp] == opponent_color )
    temp++;
  if ( board.slot[i][temp] == player_color )
    {
      temp = j + 1;
      while ( board.slot[i][temp] == opponent_color )
	{
	  board.slot[i][temp] = player_color;
	  temp++;
	}
    }

  /*********************************/
  /* diagonal reductions           */

  temp = j + 1;			/* step to the right  */
  temp2 = i + 1;		/* step downwards     */

  while ( board.slot[temp2][temp] == opponent_color )
    /* while pointing at opponent's colour */
    {
      temp++;			/* move pointer in same direction as above */
      temp2++;
    }
  if ( board.slot[temp2][temp] == player_color )
    /* if reached current player's stone and reduction should take place */
    {
      temp = j + 1;
      temp2 = i + 1;		/* revert to initial position */
      while ( board.slot[temp2][temp] == opponent_color )
	/* while pointing at opponent's stone */
	{
	  board.slot[temp2][temp] = player_color;	/* flip it */
	  temp++;		/* and move pointer in same direction  */
	  temp2++;
	}
    }

  temp = j - 1;			/* see the above for explanation */
  temp2 = i + 1;

  while ( board.slot[temp2][temp] == opponent_color )
    {
      temp--;
      temp2++;
    }
  if ( board.slot[temp2][temp] == player_color )
    {
      temp = j - 1;
      temp2 = i + 1;
      while ( board.slot[temp2][temp] == opponent_color )
	{
	  board.slot[temp2][temp] = player_color;
	  temp--;
	  temp2++;
	}
    }

  temp = j - 1;			/* see the above for explanation */
  temp2 = i - 1;

  while ( board.slot[temp2][temp] == opponent_color )
    {
      temp--;
      temp2--;
    }
  if ( board.slot[temp2][temp] == player_color )
    {
      temp = j - 1;
      temp2 = i - 1;
      while ( board.slot[temp2][temp] == opponent_color )
	{
	  board.slot[temp2][temp] = player_color;
	  temp--;
	  temp2--;
	}
    }

  temp = j + 1;			/* see the above for explanation */
  temp2 = i - 1;

  while ( board.slot[temp2][temp] == opponent_color )
    {
      temp++;
      temp2--;
    }
  if ( board.slot[temp2][temp] == player_color )
    {
      temp = j + 1;
      temp2 = i - 1;
      while ( board.slot[temp2][temp] == opponent_color )
	{
	  board.slot[temp2][temp] = player_color;
	  temp++;
	  temp2--;
	}
    }
  return board;			/* return the board in its new state */
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/





/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* calculate_mobility - calculates mobility of both sides                     */
/*                                                                            */
/*                                                                            */

void
calculate_mobility ( void )
{
  int i,
    j;

  red_mobility = 0;
  black_mobility = 0;		/* init globals */

  for ( i = 1; i < 9; i++ )
    for ( j = 1; j < 9; j++ )
      {
	if ( reducible ( i, j, RED, board ) )	/* if reduction can be carried out */
	  red_mobility++;	/* increment mobility              */
	if ( reducible ( i, j, BLACK, board ) )
	  black_mobility++;
      }
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/



/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* check_deadlock - checks if a deadlock has occured in which case the game   */
/* has reached an end or turn passed (if mobility of current side is 0)       */
/*                                                                            */
/*                                                                            */


void
check_deadlock ( void )
{
  int deadlockflag = NONE;

  if ( ( turn == BLACK ) && ( black_mobility == 0 ) )
    deadlockflag = BLACK;

  if ( ( turn == RED ) && ( red_mobility == 0 ) )
    deadlockflag = RED;

  /* ispect deadlock for both colours */

  if ( ( deadlockflag == BLACK ) || ( deadlockflag == RED ) )
    /* if current player has no move to make */
    {
      if ( ( ( deadlockflag == RED ) && ( black_mobility == 0 ) ) ||
	   ( ( deadlockflag == BLACK ) && ( red_mobility == 0 ) ) )
	finishoff (  );		/* nobody can make move  */
      else
	{
	  turn = ( !turn );	/* pass turn to opponent         */
	  cpuflag = !cpuflag;	/* inverse the need for cpu move */
	}
    }
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/




/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* finishoff - called when the game has reached an end and declares the result*/
/*                                                                            */
/*                                                                            */


void
finishoff ( void )
{
  calculatescore (  );


  /* set view angle to the main one for score */
  eyex = 25.0;			/* set camera position                      */
  eyez = 20.0;
  eyey = 5.0;
  upx = 0.0;			/* Set up direction to be the +Y axis       */
  upy = 1.0;
  upz = 0.0;
  centerz = -20;		/* set the center of interest               */
  centerx = -8;
  centery = -10.0;

  if ( redscore > blackscore )	/* set view according to the score gap      */
    view = RED_WINS;
  else if ( redscore == blackscore )
    view = DRAW;
  else
    view = BLACK_WINS;

  if ( keep_log_file == TRUE )	/* record score                             */
    close_log_file (  );

  if ( add_to_report_file == TRUE )	/* add to report                    */
    add_to_report (  );

  game_on = FALSE;		/* nobody should play a move now            */
  if ( exit_game_when_finished == TRUE )	/* check this command-line option  */
    quit_game (  );
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/



/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* file_draw_ascii_board - puts an ASCII representation of the board on       */
/* the log file                                                               */
/* inputs: the input board and the file pointer                               */
/*                                                                            */

void
file_draw_ascii_board ( board_map board, FILE * file )
{
  int i,
    j;

  fprintf ( file, "####################\n" );
  for ( i = 0; i < 10; i++ )
    {
      for ( j = 0; j < 10; j++ )
	{
	  if ( i == 0 || i == 9 || j == 0 || j == 9 )
	    /* for valid board slots - excluding borders */
	    {
	      if ( board.slot[i][j] != NONE )
		{
		  printf ( "Borders were overwritten at %d, %d\n", i, j );
		  exit ( 1 );
		}
	      if ( i == 0 && j == 1 )
		fprintf ( file, "# " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "A " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "B " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "C " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "D " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "E " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "F " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "G " );
	      if ( i == 0 && j == 1 )
		fprintf ( file, "H " );

	      if ( j == 0 && i == 1 )
		fprintf ( file, "#1" );
	      if ( j == 0 && i == 2 )
		fprintf ( file, "#2" );
	      if ( j == 0 && i == 3 )
		fprintf ( file, "#3" );
	      if ( j == 0 && i == 4 )
		fprintf ( file, "#4" );
	      if ( j == 0 && i == 5 )
		fprintf ( file, "#5" );
	      if ( j == 0 && i == 6 )
		fprintf ( file, "#6" );
	      if ( j == 0 && i == 7 )
		fprintf ( file, "#7" );
	      if ( j == 0 && i == 8 )
		fprintf ( file, "#8" );
	      if ( i == 9 )
		fprintf ( file, "##" );
	      if ( ( j == 9 ) && ( i != 9 ) )
		fprintf ( file, "##" );
	    }

	  else
	    {
	      if ( board.slot[j][i] == NONE )
		fprintf ( file, "  " );
	      if ( board.slot[j][i] == RED )
		fprintf ( file, "0 " );
	      if ( board.slot[j][i] == BLACK )
		fprintf ( file, "x " );
	    }
	}
      fprintf ( file, "\n" );
    }
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/




/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* close_log_file - closes the log file when a game is finished and displays  */
/* the game score                                                             */
/*                                                                            */

void
close_log_file ( void )
{
  int red_corners = 0,
    black_corners = 0;

  void calculate_borders (  )	/* Check number of corners captured by each side */
  {
    if ( board.slot[1][8] == RED )
      red_corners++;
    if ( board.slot[1][1] == RED )
      red_corners++;
    if ( board.slot[8][1] == RED )
      red_corners++;
    if ( board.slot[8][8] == RED )
      red_corners++;
    if ( board.slot[1][8] == BLACK )
      black_corners++;
    if ( board.slot[1][1] == BLACK )
      black_corners++;
    if ( board.slot[8][1] == BLACK )
      black_corners++;
    if ( board.slot[8][8] == BLACK )
      black_corners++;
  }

  fprintf ( log_file, "\n\nGame has reached its end.\n\n" );
  fprintf ( log_file, "Score:\n" );
  fprintf ( log_file, "======\n\n" );
  fprintf ( log_file, "BLACK: %d\n\n", blackscore );
  fprintf ( log_file, "RED: %d\n\n", redscore );
  file_draw_ascii_board ( board, log_file );
  fprintf ( log_file, "\nAdditional Statistics\n" );
  fprintf ( log_file, "=====================\n\n" );
  calculate_borders (  );
  fprintf ( log_file, "RED corners captured: %d\n", red_corners );
  fprintf ( log_file, "BLACK corners captured: %d\n", black_corners );
  fprintf ( log_file, "\n====END OF LOG FILE====" );
  fclose ( log_file );
  keep_log_file = FALSE;
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/



/******************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* add_to_report - adds the given game to a report file                       */
/*                                                                            */
/*                                                                            */

void
add_to_report ( void )
{
  if ( gather_statistics == TRUE )	/* RED is CPU */
    {
      if ( stat_mode_difficulty == BEGINNER )	/* inspect difficulty of CPU */
	fprintf ( report_file, "BEGINNER  : %d    ", redscore );
      else if ( stat_mode_difficulty == NOVICE )
	fprintf ( report_file, "NOVICE    : %d    ", redscore );
      else if ( stat_mode_difficulty == EXPERT )
	fprintf ( report_file, "EXPERT    : %d    ", redscore );
      else if ( stat_mode_difficulty == PRE_MASTER )
	fprintf ( report_file, "PRE-MASTER: %d    ", redscore );
      else if ( stat_mode_difficulty == MASTER )
	fprintf ( report_file, "MASTER    : %d    ", redscore );
    }
  else				/* RED is player/human */
    fprintf ( report_file, "HUMAN     : %d    ", redscore );

  if ( playing_against_cpu == FALSE )	/* BLACK is human player */
    fprintf ( report_file, "HUMAN     : %d\n", blackscore );

  else				/* BLACK is CPU */
    {
      if ( difficulty == BEGINNER )	/* inspect difficulty of CPU */
	fprintf ( report_file, "BEGINNER  : %d", blackscore );
      else if ( difficulty == NOVICE )
	fprintf ( report_file, "NOVICE    : %d", blackscore );
      else if ( difficulty == EXPERT )
	fprintf ( report_file, "EXPERT    : %d", blackscore );
      else if ( difficulty == PRE_MASTER )
	fprintf ( report_file, "PRE-MASTER: %d", blackscore );
      else if ( difficulty == MASTER )
	fprintf ( report_file, "MASTER    : %d", blackscore );
    }
  fprintf ( report_file, "   GAP: %d\n", redscore - blackscore );
  /* record the gap between the two */
  fclose ( report_file );
  add_to_report_file = FALSE;
}

/*                                                                            */
/*                                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/******************************************************************************/





/*                                                                      */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*                     end of misc.c                                  */
/************************************************************************/

