Click here to Skip to main content
15,886,519 members
Articles / Web Development / ASP.NET

Online Circular Chess in Silverlight, ASP.NET AJAX, WCF Web Services, and LINQ to SQL

Rate me:
Please Sign up or sign in to vote.
4.84/5 (61 votes)
31 Dec 2007CPOL34 min read 219.8K   1.9K   145  
An application for users to play Circular Chess over the internet based on Silverlight, ASP.NET AJAX, WCF Web Services, and LINQ to SQL.
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());
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Israel Israel
My name is Julian, I was born in Argentina, but I've been living in Israel for 6 years already. I'm a high school student in my last year, I study computer science, physics and math.
Other than programming, I really enjoy watching anime and reading manga.

Comments and Discussions