using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
namespace CChess.Controls
{
public class CChessBoard : Control
{
#region Constructor
public CChessBoard(Color orientation, double radius, double inner_radius, CChess.CChessBoard data_board)
{
System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("CircularChess.CChess.Controls.CChessBoard.xaml");
_canvas = (Canvas)this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());
_radius = radius;
_inner_radius = inner_radius;
Width = _radius * 2;
Height = _radius * 2;
_orientation = orientation;
_pieces = new CChessPiece[Const.PIECES];
_squares = new CChessSquare[Const.RINGS, Const.SQUARES];
_graphic_arranged_squares = new CChessSquare[Const.RINGS, Const.SQUARES];
_data_board = data_board;
double curr_inner, curr_outer;
byte graphic_square;
for (byte i = 0; i < Const.RINGS; i++)
{
curr_inner = _inner_radius + i * SquareHeight;
curr_outer = _inner_radius + (i + 1) * SquareHeight;
for (byte j = 0; j < Const.SQUARES; j++)
{
if (_orientation == black_color)
{
graphic_square = (byte) ((j < 8) ? j + 8 : j - 8);
}
else
{
graphic_square = j;
}
_graphic_arranged_squares[i, j] = new CChessSquare(curr_outer, curr_inner, _data_board.Squares[i, graphic_square], (byte)(i + 1), (byte)(j + 1));
_squares[i, graphic_square] = _graphic_arranged_squares[i, j];
_canvas.Children.Add(_graphic_arranged_squares[i, j]);
}
}
Downloader dl = new Downloader();
dl.Open("GET", new Uri("images/images.zip", UriKind.RelativeOrAbsolute));
dl.DownloadFailed += new ErrorEventHandler(dl_DownloadFailed);
dl.Completed += new EventHandler(dl_Completed);
dl.Send();
Draw();
}
#endregion
#region Fields
private CChess.CChessBoard _data_board;
private Canvas _canvas;
private double _radius;
private double _inner_radius;
private CChessSquare[,] _squares;
private CChessSquare[,] _graphic_arranged_squares;
private CChessPiece[] _pieces;
private Color _orientation;
private Dictionary<CChess.ChessPieceTypes, Dictionary<CChessColors, Image>> _images;
public static Color black_color = Colors.Black;
public static Color white_color = Colors.White;
public delegate void NoParametersEventHandler();
public event NoParametersEventHandler OnLoad;
/// <summary>
/// Gets or sets the radius of the board.
/// </summary>
public double Radius
{
get { return _radius; }
set
{
_radius = value;
// Make sure the board fits exactly into the canvas
Width = value * 2;
Height = value * 2;
// If the radius is changed, we must redraw the board
Draw();
}
}
/// <summary>
/// Gets or sets the radius of the circle in the middle of the board.
/// </summary>
public double InnerRadius
{
get { return _inner_radius; }
set
{
_inner_radius = value;
// If the inner radius is changed, we must redraw the board.
Draw();
}
}
public CChessSquare[,] Squares
{
get { return _squares; }
}
public CChessPiece[] Pieces
{
get { return _pieces; }
}
public double SquareHeight
{
get { return ((_radius - _inner_radius) / 4); }
}
public CChessColors CurrentMoveColor
{
get { return _data_board.CurrentMoveColor; }
}
#endregion
#region Initializing
void dl_DownloadFailed(object sender, ErrorEventArgs e)
{
throw new Exception(e.ErrorMessage);
}
void dl_Completed(object sender, EventArgs e)
{
Downloader dl = sender as Downloader;
_images = new Dictionary<CChess.ChessPieceTypes, Dictionary<CChessColors, Image>>();
Dictionary<CChessColors, Image> tmp_dictionary = new Dictionary<CChessColors, Image>();
Image tmp_img;
// Now we manually fill the dictionary
// Rooks
tmp_dictionary = new Dictionary<CChessColors, Image>();
tmp_img = new Image();
tmp_img.SetSource(dl, "black_rook.png");
tmp_dictionary.Add(CChessColors.Black, tmp_img);
tmp_img = new Image();
tmp_img.SetSource(dl, "white_rook.png");
tmp_dictionary.Add(CChessColors.White, tmp_img);
_images.Add(CChess.ChessPieceTypes.Rook, tmp_dictionary);
// Knights
tmp_dictionary = new Dictionary<CChessColors, Image>();
tmp_img = new Image();
tmp_img.SetSource(dl, "black_knight.png");
tmp_dictionary.Add(CChessColors.Black, tmp_img);
tmp_img = new Image();
tmp_img.SetSource(dl, "white_knight.png");
tmp_dictionary.Add(CChessColors.White, tmp_img);
_images.Add(CChess.ChessPieceTypes.Knight, tmp_dictionary);
// Bishops
tmp_dictionary = new Dictionary<CChessColors, Image>();
tmp_img = new Image();
tmp_img.SetSource(dl, "black_bishop.png");
tmp_dictionary.Add(CChessColors.Black, tmp_img);
tmp_img = new Image();
tmp_img.SetSource(dl, "white_bishop.png");
tmp_dictionary.Add(CChessColors.White, tmp_img);
_images.Add(CChess.ChessPieceTypes.Bishop, tmp_dictionary);
// Kings
tmp_dictionary = new Dictionary<CChessColors, Image>();
tmp_img = new Image();
tmp_img.SetSource(dl, "black_king.png");
tmp_dictionary.Add(CChessColors.Black, tmp_img);
tmp_img = new Image();
tmp_img.SetSource(dl, "white_king.png");
tmp_dictionary.Add(CChessColors.White, tmp_img);
_images.Add(CChess.ChessPieceTypes.King, tmp_dictionary);
// Queens
tmp_dictionary = new Dictionary<CChessColors, Image>();
tmp_img = new Image();
tmp_img.SetSource(dl, "black_queen.png");
tmp_dictionary.Add(CChessColors.Black, tmp_img);
tmp_img = new Image();
tmp_img.SetSource(dl, "white_queen.png");
tmp_dictionary.Add(CChessColors.White, tmp_img);
_images.Add(CChess.ChessPieceTypes.Queen, tmp_dictionary);
// Pawns
tmp_dictionary = new Dictionary<CChessColors, Image>();
tmp_img = new Image();
tmp_img.SetSource(dl, "black_pawn.png");
tmp_dictionary.Add(CChessColors.Black, tmp_img);
tmp_img = new Image();
tmp_img.SetSource(dl, "white_pawn.png");
tmp_dictionary.Add(CChessColors.White, tmp_img);
_images.Add(CChess.ChessPieceTypes.Pawn, tmp_dictionary);
Initialize();
}
public void Draw()
{
double square_height = SquareHeight;
double curr_inner, curr_outer;
for (byte i = 1; i <= Const.RINGS; i++)
{
curr_inner = _inner_radius + (i - 1) * square_height;
curr_outer = _inner_radius + i * square_height;
for (byte j = 1; j <= Const.SQUARES; j++)
{
_squares[i - 1, j - 1].InnerRadius = curr_inner;
_squares[i - 1, j - 1].OuterRadius = curr_outer;
_squares[i - 1, j - 1].Draw();
}
}
}
private void AddPiece(int id, Image img, ChessPieceTypes type, CChessSquare square)
{
// Note that img uses the extender method inside the Extensions class (Clone).
_pieces[id - 1] = new CChessPiece(_data_board.Pieces[id - 1], square, img.Clone());
}
/// <summary>
/// Puts the pieces in their respective positions
/// </summary>
/// <param name="images">A Dictionary containing sample images</param>
public void Initialize()
{
for (int i = 1; i <= Const.PIECES; i++)
{
CChess.CChessPiece piece = _data_board.Pieces[i - 1];
CChessSquare square = (piece.IsAlive) ? _squares[piece.Square.Ring - 1, piece.Square.Square - 1] : null;
AddPiece(
i,
_images[piece.Type][piece.Color],
piece.Type,
square);
}
OnLoad();
}
#endregion
/// <summary>
/// Checks if the point is over the board according to the radius. If it is
/// over the board, then it uses trigonometry to find out the square, if not,
/// it returns null.
/// </summary>
/// <param name="p">The point to check.</param>
/// <returns>The CChessSquare that is under Point p. Returns null if no square was found.</returns>
public CChessSquare GetSquare(Point p)
{
CChessSquare square = null;
double radius = Math.Sqrt(Math.Pow(p.X - _radius, 2) + Math.Pow(p.Y - _radius, 2));
if (radius >= 0 && radius <= _radius)
// Check what ring it belongs in
{
double current_radius;
byte ring = 0;
for (int i = 0; i < Const.RINGS; i++)
{
current_radius = _inner_radius + i * SquareHeight;
if (radius > current_radius && radius < (current_radius + SquareHeight))
{
ring = (byte)(i + 1);
break;
}
}
if (ring >= 1 && ring <= Const.RINGS)
// The piece is over one of the rings, now we must find over what
// square
{
// To bust performance, we'll first find what quarter the cursor is in
// We'll then store what is the range that has to be checked
byte first_square, last_square;
Range<double> x_range;
double angle;
if (p.X > _radius)
// Right side
{
if (p.Y > _radius)
// Bottom
{
first_square = 1;
last_square = Const.SQUARES / 4;
}
else
// Top
{
first_square = Const.SQUARES / 4 + 1;
last_square = 2 * Const.SQUARES / 4;
}
}
else
// Left side
{
if (p.Y > _radius)
// Bottom
{
first_square = 3 * Const.SQUARES / 4 + 1;
last_square = Const.SQUARES;
}
else
// Top
{
first_square = 2 * Const.SQUARES / 4 + 1;
last_square = 3 * Const.SQUARES / 4;
}
}
// The method is to find the range of Sin and Cos that the cursor
// may be in for each of the squares. If the cursor is in that
// range, then we found the square, and we return it
for (int i = first_square; i <= last_square; i++)
{
angle = Const.SQUARE_ANGLE * i;
x_range = new CChess.Range<double>();
x_range.Val1 = _radius + radius * Math.Sin(angle);
x_range.Val2 = _radius + radius * Math.Sin(angle - Const.SQUARE_ANGLE);
if (x_range.FitsInRange(p.X))
{
square = _graphic_arranged_squares[ring - 1, i - 1];
// No need to check the y axis, because we're only checking
// a quarter of the circle, and only the x is enough to
// determine the square.
//y_range = new Range<double>();
//y_range.Val1 = _radius + radius * Math.Cos(angle);
//y_range.Val2 = _radius + radius * Math.Cos(angle - CChessSquare.SQUARE_ANGLE);
//if (y_range.FitsInRange(p.Y))
//{
// square = _squares[ring - 1, i - 1];
// break;
//}
}
}
}
}
return square;
}
public void MovePiece(byte piece_id, byte square_ring, byte square)
{
CChess.ChessPieceTypes previous_type = _pieces[piece_id - 1].Type;
_data_board.MovePiece(piece_id, square_ring, square);
CChessSquare cchess_square = _squares[square_ring - 1, square - 1];
CChessPiece piece = _pieces[piece_id - 1];
cchess_square.Piece = piece;
// Check if the move was a pawn promotion
if (previous_type != piece.Type)
{
piece.ChangeImage(_images[piece.Type][piece.CChessColor].Clone());
}
}
}
}