using System;
using System.Collections;
namespace gma.Reversi {
/// <summary>
/// Occures when the move was transferred to another player.
/// </summary>
public delegate void OnMoveTransferredEvent(int aNextPlayer, int anAvailableMoveCount);
/// <summary>
/// Occures after each move or after StartGame.
/// </summary>
public delegate void OnNeedRedrawEvent();
/// <summary>
/// Occures when Game over conditions are reached.
/// </summary>
public delegate void OnGameOverEvent();
/// <summary>
/// Identifies a square on the board.
/// </summary>
public struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X=x;
Y=y;
}
/// <summary>
/// Is used to check if the given point belongs to 8x8 matrix.
/// </summary>
/// <returns></returns>
public bool IsInRange()
{
if (X<0 || Y<0 || X>=Board.SIZEX || Y>=Board.SIZEY) return false;
return true;
}
}
/// <summary>
/// This structure is used to describe neighboring points.
/// </summary>
public struct Direction
{
public int dX;
public int dY;
public Direction( int dx, int dy)
{
dX=Math.Sign(dx);
dY=Math.Sign(dy);
}
/// <summary>
/// Adding a direction to a point gives you a neighbour point in given direction.
/// </summary>
/// <param name="aPoint"></param>
/// <param name="aDirection"></param>
/// <returns></returns>
public static Point operator +(Point aPoint, Direction aDirection)
{
return new Point(aPoint.X + aDirection.dX, aPoint.Y + aDirection.dY );
}
/// <summary>
/// Every direction has an oposite direction.
/// </summary>
/// <param name="aDirection"></param>
/// <returns></returns>
public static Direction Opposite(Direction aDirection)
{
return new Direction(-aDirection.dX, -aDirection.dY);
}
}
/// <summary>
/// This class is a main dataStructure to describe a Board and all actions on it.
/// </summary>
public class Board : object {
public const int PLAYER_WHITE = -1;
public const int PLAYER_RED = 1;
public const int SQUARE_EMPTY = 0;
public const int SIZEX=8;
public const int SIZEY=8;
// NW N NE
// \ | /
//W -- -- E
// / | \
// SW S SE
public static Direction DirN = new Direction(0,-1);
public static Direction DirNE = new Direction(1,-1);
public static Direction DirE = new Direction(1,0);
public static Direction DirSE = new Direction(1,1);
public static Direction DirS = new Direction(0,1);
public static Direction DirSW = new Direction(-1,1);
public static Direction DirW = new Direction(-1,0);
public static Direction DirNW = new Direction(-1,-1);
public static Direction[] AllDirs = new Direction[8] {DirN, DirNE, DirE, DirSE, DirS, DirSW, DirW, DirNW};
//initial board placement
public static int[,] InitBoard= new int[SIZEX, SIZEY] {
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,-1,1,0,0,0},
{0,0,0,1,-1,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}};
//
public static int[,] LocationWeight= new int[SIZEX, SIZEY] {
{50 , -1, 5, 2 , 2, 5, -1, 50},
{-1 ,-10, 1, 1 , 1, 1,-10, -1},
{ 5 , 1, 1, 1 , 1, 1, 1, 5},
{ 2 , 1, 1, 0 , 0, 1, 1, 2},
{ 2 , 1, 1, 0 , 0, 1, 1, 2},
{ 5 , 1, 1, 1 , 1, 1, 1, 5},
{-1 ,-10, 1, 1 , 1, 1,-10, -1},
{50 , -1, 5, 2 , 2, 5, -1, 50}};
public static int[,] Irreversible= new int[SIZEX, SIZEY] {
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}};
public static Point NOMOVE = new Point(-1, -1);
public int GetStateAt(Point aPoint)
{
return _square[aPoint.X, aPoint.Y];
}
public int GetStateAt(int x, int y)
{
return _square[x, y];
}
protected IList _affectedSquares;
public IList AffectedSquares
{
get
{
if (_affectedSquares==null)
_affectedSquares= new ArrayList();
return _affectedSquares;
}
}
public event OnGameOverEvent OnGameOver;
public event OnMoveTransferredEvent OnMoveTransferred;
public event OnNeedRedrawEvent OnNeedRedraw;
public virtual event OnNeedRedrawEvent OnNeedRedrawAll;
protected virtual void SetStateAt(Point aPoint, int state)
{
//----- Statisticts
// Decrease
switch (_square[aPoint.X, aPoint.Y])
{
case PLAYER_WHITE:
_counterWhite--;
_weightWhite-=LocationWeight[aPoint.X, aPoint.Y];
break;
case PLAYER_RED:
_counterRed--;
_weightRed-=LocationWeight[aPoint.X, aPoint.Y];
break;
}
// Increase
switch (state)
{
case PLAYER_WHITE:
_counterWhite++;
_weightWhite+=LocationWeight[aPoint.X, aPoint.Y];
break;
case PLAYER_RED:
_counterRed++;
_weightRed+=LocationWeight[aPoint.X, aPoint.Y];
break;
}
//-----END Statisticts
_affectedSquares.Add(aPoint);
_square[aPoint.X, aPoint.Y]=state;
}
protected int _currentPlayer=PLAYER_RED;
public int CurrentPlayer
{
get {return _currentPlayer;}
}
protected int[,] _square;
public int[,] Square
{
get {return _square;}
}
public Board() {
_square= (int[,])InitBoard.Clone();
}
protected Board(Board aParent) {
_square = (int[,])aParent.Square.Clone();
_counterWhite = aParent.CounterWhite;
_counterRed = aParent.CounterRed;
_weightRed = aParent.WeightRed;
_weightWhite = aParent.WeightWhite;
_currentPlayer = aParent.CurrentPlayer;
}
public Board Clone()
{
return new Board(this);
}
public virtual void StartGame()
{
_square= (int[,])InitBoard.Clone();
_counterWhite = 2;
_counterRed = 2;
_weightRed = 0;
_weightWhite = 0;
AffectedSquares.Clear();
_availableMoves=null;
if (OnNeedRedrawAll != null) OnNeedRedrawAll();
// black starts
_currentPlayer = PLAYER_WHITE;
// the move will be transfered to black
TransferMove(0);
}
public bool Play(Point aPoint, int aPlayer, bool IsTestOnly)
{
if (!IsTestOnly) AffectedSquares.Clear();
if (!aPoint.IsInRange()) return false;
if (GetStateAt(aPoint)!=SQUARE_EMPTY) return false;
bool result = false;
for (int i=0; i<AllDirs.Length ; i++)
{
Point aNeighbourPoint = aPoint + AllDirs[i];
if (aNeighbourPoint.IsInRange())
{
int aNeigbourSquareState = GetStateAt(aNeighbourPoint);
if (aNeigbourSquareState == -aPlayer)
{
bool doFlip = Flipp(aPoint, AllDirs[i], aPlayer, IsTestOnly);
result=result || doFlip;
if (IsTestOnly && result) return true;
}
}
}
if (result && !IsTestOnly)
{
SetStateAt(aPoint,aPlayer);
TransferMove(0);
}
return result;
}
protected void TransferMove(int recursionDepth )
{
if (recursionDepth == 2)
{
if (OnGameOver != null)
{
if (OnNeedRedraw != null) OnNeedRedraw();
OnGameOver();
}
return;
}
_currentPlayer = -_currentPlayer;
_availableMoves = null;
GetAvailableMoves(_currentPlayer);
if (_availableMoves.Count == 0)
TransferMove(recursionDepth + 1);
else
{
if (OnNeedRedraw != null) OnNeedRedraw();
if (OnMoveTransferred != null)
OnMoveTransferred(_currentPlayer, _availableMoves.Count);
}
}
protected bool Flipp(Point aPoint, Direction aDirection, int aPlayer, bool IsTestOnly)
{
Point aNeighbourPoint = aPoint + aDirection;
if (!aNeighbourPoint.IsInRange()) return false;
int aNeigbourSquareState = GetStateAt(aNeighbourPoint);
if (aNeigbourSquareState == aPlayer) return true;
if (aNeigbourSquareState == -aPlayer)
if (Flipp(aNeighbourPoint, aDirection, aPlayer, IsTestOnly))
{
if (!IsTestOnly) SetStateAt(aNeighbourPoint, aPlayer);
return true;
}
return false;
}
//##################################################################
// STATISTICS
//##################################################################
private int _counterRed = 2;
public virtual int CounterRed
{
get { return _counterRed;}
}
private int _counterWhite = 2;
public virtual int CounterWhite
{
get { return _counterWhite;}
}
protected int _weightRed = 0;
public int WeightRed
{
get { return _weightRed;}
}
protected int _weightWhite = 0;
public int WeightWhite
{
get { return _weightWhite;}
}
protected ArrayList _availableMoves = null;
/// <summary>
/// Simple brutal Search for available Moves. It was overrided in BoardComplex
/// </summary>
/// <param name="aPlayer"></param>
/// <returns></returns>
public virtual IList GetAvailableMoves(int aPlayer)
{
if (_availableMoves==null)
{
_availableMoves = new ArrayList();
for (int i=0; i<SIZEX; i++)
for (int j=0; j<SIZEY; j++)
if (Play(new Point(i,j),aPlayer, true))
_availableMoves.Add(new Point(i,j));
}
return _availableMoves;
}
/// <summary>
/// Simple brutal chack for evry square. It was overrided in BoardComplex
/// </summary>
/// <param name="aPlayer"></param>
/// <returns></returns>
public virtual int GetIrreversibleCount(int aPlayer)
{
int aPlayerArrayIndex=aPlayer;
int counter=0;
if (aPlayer<0) aPlayerArrayIndex=0;
for (int i=0; i<SIZEX; i++)
for (int j=0; j<SIZEY; j++)
if (IsIrreversible(new Point(i,j),aPlayer, 0)) counter++;
return counter;
}
protected bool IsIrreversible(Point aPoint, int aPlayer, int recursionDepth)
{
if (!aPoint.IsInRange()) return true;
if (_square[aPoint.X, aPoint.Y]!=aPlayer) return false;
if (Irreversible[aPoint.X, aPoint.Y]==aPlayer) return true;
if (recursionDepth==1) return false;
if (IsLineBlocked(aPoint, DirN, aPlayer, recursionDepth) &&
IsLineBlocked(aPoint, DirNE, aPlayer, recursionDepth) &&
IsLineBlocked(aPoint, DirE, aPlayer, recursionDepth) &&
IsLineBlocked(aPoint, DirSE, aPlayer, recursionDepth))
{
Irreversible[aPoint.X, aPoint.Y]=aPlayer;
return true;
}
return false;
}
protected bool IsLineBlocked(Point aPoint, Direction lineDirection,int aPlayer, int recursionDepth)
{
return (IsIrreversible(aPoint+lineDirection, aPlayer, recursionDepth+1) ||
IsIrreversible(aPoint+Direction.Opposite(lineDirection), aPlayer, recursionDepth+1));
}
}
}