/*------------------------------------------------------------------------------
Projekt: ICP - game Othello
Authors: Michal Schorm (xschor02)
Date: FIT VUTBR 2016                                                

File content: class Board
-------------------------------------------------------------------------------*/
#include "./Field.cpp" // game Board contains fileds inside (playable) and fields around (border)



//!  Class Board - represents game Board which consists form Fields
/*!
Board can have only several fixed sizes 6*6, 8*8, 10*10, 12*12
This class contains methods to analyze Disk on the board and check if somebody aleady won or if actual player has any possible move.
*/
#ifndef BOARD_CLASS_FULL
#define BOARD_CLASS_FULL
class Board
{
 private:
   //! Array of pointers to fields. Maximum size of game Board is 12*12, one line on each side is consists from border fields so it is 14*14.
   Field * fields[14][14];
   //! square root of number of playable fields. On 8*8 board it is 8 etc. 
   int size;
   
   
   
 public:
   //! Constructor create game Board. Make array of Fileds and set neigbours to each other (of on-border fields)
   Board(int size)
     {
      this->size = size;
      int row, col;

      for(row = 0; row<=size+1; row++)
        {
         for(col = 0; col<=size+1; col++)
           {
            if(col == 0 || row == 0 || col == size+1 || row == size+1)
              {
               this->fields[row][col] = new Field(true);
              }
            else
              {
               this->fields[row][col] = new Field(false);
              }
            }
        }
        
        for(row = 1; row<=size; row++)
          {
           for(col = 1; col<=size; col++)
             {
              (*(this->fields[row][col])).setNeighbour(RR, fields[row][col+1]);
              (*(this->fields[row][col])).setNeighbour(RD, fields[row+1][col+1]);
              (*(this->fields[row][col])).setNeighbour(DD, fields[row+1][col]);
              (*(this->fields[row][col])).setNeighbour(LD, fields[row+1][col-1]);
              (*(this->fields[row][col])).setNeighbour(LL, fields[row][col-1]);
              (*(this->fields[row][col])).setNeighbour(LU, fields[row-1][col-1]);
              (*(this->fields[row][col])).setNeighbour(UU, fields[row-1][col]);
              (*(this->fields[row][col])).setNeighbour(RU, fields[row-1][col+1]);
             }
          }
    }
    
    //! returns pointer to filed on coordinates given
    Field * getField(int row, int col)
      {
       if(row<1 || row>this->size || col<1 || col>this->size) return NULL;
       return this->fields[col][row];
      }
    
    //! returns size of the game Board
    int getBoardSize()
      {
       return this->size;
      }

    //! put disk of givn color on coordinates given. Field::canPutDisk MUST always be checked before.
    void putDisk(int row, int col, DiskColor color)
      {
       this->fields[row][col]->putDisk(new Disk(color));
      }

    //! draw game Board into the console.
    void drawBoard()
      {
       int row, col;

       for(col = 0; col<=(this->size)+1; col++, cout << endl)
        {
         for(row = 0; row<=(this->size)+1; row++)
           {
            if(col == 0 || col == (this->size)+1 ) cout << "-";
            else if(row == 0 || row == (this->size)+1 ) cout << "|";
            else if( (*(this->fields[row][col])).getDiskColor() == none) cout << ".";
            else cout << (*(this->fields[row][col])).getDiskColor();
           }
        }          
      }

    //! return amount of Disks of color given on this board 
    int amount(DiskColor color)
      {
       int row, col, amount;

       for(row = 1, amount=0; row<=(this->size); row++)
         {
          for(col = 1; col<=(this->size); col++)
            {
             if( this->fields[row][col]->getDiskColor() == color) amount++;
            }    
         }      
      
       return amount;
      }
    
    //! chceck who won  (white/black/draw/none)         
    DiskColor checkWin()
      {
       int numWhite = this->amount(white);
       int numBlack = this->amount(black);
       
       if( numWhite == 0) return black;
       else if( numBlack == 0 ) return white;      
       else if( numWhite+numBlack == (this->size)*(this->size) )
         {
          if( numWhite > numBlack ) return white;
          else if( numBlack > numWhite ) return black;
          else return draw;
         }
       else return none;
      }
    
    //! chceck if player of color given has any possible move (true/false)  
    bool checkCanPlay(DiskColor color)
      {
       int row, col;

       for(row = 1; row<=(this->size); row++)
         {
          for(col = 1; col<=(this->size); col++)
            {
             if(this->fields[row][col]->canPutDisk(color)) return true;
            }    
         }      
       return false;
      }      
      
      
      
      
}; 
#endif