///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//         This example code is from the book:
//
//           Object-Oriented Programming with C++ and OSF/Motif, 2nd Edition
//         by
//           Douglas Young
//           Prentice Hall, 1995
//           ISBN 0-13-20925507
//
//         Copyright 1995 by Prentice Hall
//         All Rights Reserved
//
//  Permission to use, copy, modify, and distribute this software for 
//  any purpose except publication and without fee is hereby granted, provided 
//  that the above copyright notice appear in all copies of the software.
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////
// Board.C
/////////////////////////////////////////////////////////////
#include "Board.h"

// Array of all possible winning patterns (1 indicates a win)

int Board::_winningBits[8][9] = {
{ 1, 0, 0,
      1, 0, 0,
      1, 0, 0 },
{ 0, 1, 0,
      0, 1, 0,
      0, 1, 0 },
{ 0, 0, 1,
      0, 0, 1,
      0, 0, 1 },
{ 1, 1, 1,
      0, 0, 0,
      0, 0, 0 },
{ 0, 0, 0,
      1, 1, 1,
      0, 0, 0 },
{ 0, 0, 0,
      0, 0, 0,
      1, 1, 1 },
{ 1, 0, 0,
      0, 1, 0,
      0, 0, 1 },
{ 0, 0, 1,
      0, 1, 0,
      1, 0, 0 },
  };

Board::Board()
{
    clear();  // Initialize the board
}

void Board::clear()
{
    // NOBODYYET doubles as an indication that no one has won
    // and that no move has been recorded for a square
    
    for ( int i = 0; i < 9; i++ )
	_state[i] = NOBODYYET;
}

MoveStatus Board::recordMove ( int position, markType mark )
{
    if ( _state[position] != NOBODYYET ) // Make sure square is empty
    {
	return ( ILLEGALMOVE );
    }
    
    // Record the move, and report it as legal
    
    _state[position] = mark;
    
    return ( VALIDMOVE );
}

const int *Board::freeSquares ( int& numFree )
{
    int i, j;
  
    // Build up a list of the indexes (0-8) of free squares
    
    for ( j = 0, i = 0; i < 9; i++ )
	if ( _state[i] == NOBODYYET )
	    _freeList[j++] = i;
    
    numFree = j;
    return ( _freeList );
}

int Board::numFreeSquares()
{
    int i, count;
    
    // Look for and count unmarked squares
    
    for ( count = 0, i = 0; i < 9; i++ )
	if ( _state[i] == NOBODYYET )
	    count++;
    
    return ( count );
}

markType Board::whoHasWon()
{
    int i, j;
    
    // Check the state of the board to see if anyone has won
    
    for ( i = 0; i < 8; i++ )
    {
	int xcount = 0;  // Initialize to no Xs, no Os
	int ocount = 0;
	
	_winningPattern = _winningBits[i];	 // Remember in case of a win
	
	for ( j = 0; j < 9; j++ )     // Test each winning pattern
	    if ( _winningBits[i][j] )
		if ( _state[j] == OO )
		    ocount++;          // Count Os in winning squares
		else if ( _state[j] == XX )		  		  
		    xcount++;          // Count Xs in winning squares
  	
	if ( ocount == 3 )   // If either mark occupied 3 squares
	    return ( OO );   // then return the winner
	if ( xcount == 3 )
	    return ( XX );
    }
    
    if ( numFreeSquares() > 0 )  // If no one won, report a tie or
	return ( NOBODYYET );    // continue the game, as appropriate
    else
	return ( TIE );
}

int Board::winningMove ( markType player )
{
    int i, j;
    
    for ( i = 0; i < 8; i++ )
    {
	int count    = 0;  // Initialize to no matches
	int opponent = 0;
 	
	for ( j = 0; j < 9; j++ )     // Test each winning pattern
	    if ( _winningBits[i][j] )
		if ( _state[j] == player )
		    count++;          
		else if ( _state[j] != NOBODYYET )
		    opponent++;
	
	// If the requested player has two in a row, and the
	// remaining square in that row is blank, return the
	// move that could win for that player.
	
	if ( count == 2 && opponent == 0)   
	{
	    int index;
	    
	    for ( index = 0; index < 9 ; index++ )
	    {
		if ( _winningBits[i][index] &&
		     _state[index] == NOBODYYET )
		{
		    return index;
		}
	    }
	}
    }
    return ( -1 );
}


int Board::winningPositions ( markType player )
{
    int i, j;
    int positions = 0;
    
    for ( i = 0; i < 8; i++ )
    {
	int count    = 0;  // Initialize to no matches
	int opponent = 0;
 	
	for ( j = 0; j < 9; j++ )     // Test each winning pattern
	    if ( _winningBits[i][j] )
		if ( _state[j] == player )
		    count++;          
		else if ( _state[j] != NOBODYYET )
		    opponent++;
	
	// If the requested player has two in a row, and the
	// remaining square in that row is blank, return the
	// move that could win for that player.
	
	if ( count == 2 && opponent == 0)   
	{
	    positions++;
	}
    }
    return ( positions );
}
