/*------------------------------------------------------------------------------
Projekt: ICP - game Othello
Authors: Michal Schorm (xschor02)
Date: FIT VUTBR 2016
File content: class Field, enum FieldDirection
-------------------------------------------------------------------------------*/
#include <cstddef> // work with NULL
#include "./Disk.cpp" // Disks are placed on the fields.
using namespace std;
//! ENUM FieldDirection - contains values for distinguish the direction, in which its neighbour is in the board. 8 possible directions
#ifndef FIELD_TYPE
#define FIELD_TYPE
enum FieldDirection { RU, RR, RD, LU, LL, LD, UU, DD };
#endif
//! Class Field - represents a place on which disk can be placed.
/*!
Fields are inside game Board.
Fileds are either inside Board or compose border around.
Fields that are not borders must know all of their neighbours to work properly.
Fields that are borders must not contain any disks to work properly.
*/
#ifndef FIELD_CLASS_FULL
#define FIELD_CLASS_FULL
class Field
{
private:
//! Direction Right Up
Field * neighbourRU = NULL;
//! Direction Right
Field * neighbourRR = NULL;
//! Direction Right Down
Field * neighbourRD = NULL;
//! Direction Left Up
Field * neighbourLU = NULL;
//! Direction Left
Field * neighbourLL = NULL;
//! Direction Left down
Field * neighbourLD = NULL;
//! Direction Up
Field * neighbourUU = NULL;
//! Direction Down
Field * neighbourDD = NULL;
//! Pointer to Disk placed on this field
Disk * disk = NULL;
//! Information, if the field is border field. (true/false)
bool border;
//! Private method used by other methods in this class to see if some action will affect this filed neighbours or to affect them that way.
/*!
Operation determines whether calling method wants to check, if anything change or if it wants to apply changes.
Field Direction determines direction in which (from this filed) changes will be traced / applied
DiskColor determines color of the disk that would be put / is put on the filed
The method goes through fields neighbours one by one and looks for line of disks of opposite color ended by same colored disk.
*/
bool diskChangeLine(DiskColor color, FieldDirection dir, bool operation) // ověřuje, jestli vložený disk ovlivní daný směr
{
Field * soused;
if(color == white)
{
switch(dir)
{
case RU:
soused = this->neighbourRU;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourRU; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourRU; do{ soused->turnDisk(); soused = soused->neighbourRU; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case RR:
soused = this->neighbourRR;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourRR; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourRR; do{ soused->turnDisk(); soused = soused->neighbourRR; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case RD:
soused = this->neighbourRD;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourRD; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourRD; do{ soused->turnDisk(); soused = soused->neighbourRD; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case LU:
soused = this->neighbourLU;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourLU; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourLU; do{ soused->turnDisk(); soused = soused->neighbourLU; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case LL:
soused = this->neighbourLL;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourLL; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourLL; do{ soused->turnDisk(); soused = soused->neighbourLL; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case LD:
soused = this->neighbourLD;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourLD; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourLD; do{ soused->turnDisk(); soused = soused->neighbourLD; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case UU:
soused = this->neighbourUU;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourUU; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourUU; do{ soused->turnDisk(); soused = soused->neighbourUU; } while( soused->getDiskColor() == black ); } return true; } }
return false;
case DD:
soused = this->neighbourDD;
if(soused->getDiskColor() == black) { do{ soused = soused->neighbourDD; } while( soused->getDiskColor() == black ); if(soused->getDiskColor() == white)
{ if(operation){ soused = this->neighbourDD; do{ soused->turnDisk(); soused = soused->neighbourDD; } while( soused->getDiskColor() == black ); } return true; } }
return false;
}
}
else if(color == black)
{
switch(dir)
{
case RU:
soused = this->neighbourRU;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourRU; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourRU; do{ soused->turnDisk(); soused = soused->neighbourRU; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case RR:
soused = this->neighbourRR;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourRR; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourRR; do{ soused->turnDisk(); soused = soused->neighbourRR; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case RD:
soused = this->neighbourRD;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourRD; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourRD; do{ soused->turnDisk(); soused = soused->neighbourRD; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case LU:
soused = this->neighbourLU;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourLU; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourLU; do{ soused->turnDisk(); soused = soused->neighbourLU; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case LL:
soused = this->neighbourLL;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourLL; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourLL; do{ soused->turnDisk(); soused = soused->neighbourLL; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case LD:
soused = this->neighbourLD;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourLD; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourLD; do{ soused->turnDisk(); soused = soused->neighbourLD; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case UU:
soused = this->neighbourUU;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourUU; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourUU; do{ soused->turnDisk(); soused = soused->neighbourUU; } while( soused->getDiskColor() == white ); } return true; } }
return false;
case DD:
soused = this->neighbourDD;
if(soused->getDiskColor() == white) { do{ soused = soused->neighbourDD; } while( soused->getDiskColor() == white ); if(soused->getDiskColor() == black)
{ if(operation){ soused = this->neighbourDD; do{ soused->turnDisk(); soused = soused->neighbourDD; } while( soused->getDiskColor() == white ); } return true; } }
return false;
}
}
return false;
}
public:
//! Constructor only assign information whether is this field a border field
Field(bool border)
{
this->border = border;
}
//! Returns color of disk on this field or "none" if this field doesn´t contain any disk
DiskColor getDiskColor()
{
if( this->disk == NULL ) return none;
return this->disk->getColor();
}
//! Call method to swap color of the disk on this field
void turnDisk()
{
if( this->disk != NULL ) this->disk->turn();
}
//! Method to set pointers to neighbour field in given direcion
void setNeighbour(FieldDirection direction, Field * field)
{
switch (direction)
{
case RU:
this->neighbourRU = field;
break;
case RR:
this->neighbourRR = field;
break;
case RD:
this->neighbourRD = field;
break;
case LU:
this->neighbourLU = field;
break;
case LL:
this->neighbourLL = field;
break;
case LD:
this->neighbourLD = field;
break;
case UU:
this->neighbourUU = field;
break;
case DD:
this->neighbourDD = field;
break;
}
}
//! Method to get pointers to neighbour field in given direcion. Returns NULL if none neighbour is set in direction given.
Field * getNeighbour(FieldDirection direction)
{
switch (direction)
{
case RU:
return this->neighbourRU;
break;
case RR:
return this->neighbourRR;
break;
case RD:
return this->neighbourRD;
break;
case LU:
return this->neighbourLU;
break;
case LL:
return this->neighbourLL;
break;
case LD:
return this->neighbourLD;
break;
case UU:
return this->neighbourUU;
break;
case DD:
return this->neighbourDD;
break;
default:
return NULL;
}
}
//! Returns (true/false) if this filed is a border field
bool isBorder()
{
return this->border;
}
//! Returns pointer to disk on this filed. Can return NULL.
Disk * getDisk()
{
return this->disk;
}
//! Checks, whether a disk of given color can be put on this field. (true/false)
bool canPutDisk(DiskColor color)
{
if( this->disk != NULL ) return false; // there is a disk already on this field
if( this->border == true ) return false; // disks cannot be placed on border fields
//cout << "canPutDisk(" << color << ")\n"; // CLI debugg output
int dir;
for( dir=0; dir<=8; dir++){ if( this->diskChangeLine(color, (FieldDirection)dir, false) ) return true; }
return false;
}
//! Place a disk of given color on this field. (Without any check !! method canPutDisk MUST be always called before )
void putDisk(Disk * disk)
{
this->disk = disk;
DiskColor color = disk->getColor();
int dir;
for( dir=0; dir<=8; dir++) this->diskChangeLine(color, (FieldDirection)dir, true);
}
};
#endif