API Docs for:
Show:

File: js/classes/Board.js

/**
* A Board class, represents a state of the game
* @class Board
* @constructor
*/
function Board() {
	
	/**
 	* self reference
 	* @property that
 	* @type Object
 	*/
	var that = this;
	/**
 	* Board side, either 'black' or 'white'
 	* @property side
 	* @type String
 	*/
    this.side;
	
	/**
 	* Current side to move, either 'black' or 'white'
 	* @property sideToMove
 	* @type String
 	*/
	this.sideToMove;
	
	/**
 	* The color of the white fields
	* @private
 	* @property whiteField
 	* @type String
 	*/
    var whiteField = "rgb(221, 221, 221)";
	
	/**
 	* The color of the black fields
	* @private
 	* @property blackField
 	* @type String
 	*/
    var blackField = "rgb(136, 173, 177)";
	
	/**
 	* canvas context to draw pieces
	* @private
 	* @property piecesContext
 	* @type Object
 	*/
	piecesContext 		= $('#chess-pieces').get(0).getContext('2d');
	
	/**
 	* canvas context to draw legal moves highlight
	* @private
 	* @property lmovesContext
 	* @type Object
 	*/
	lmovesContext 		= $('#legal-moves').get(0).getContext('2d');
	
	/**
 	* canvas context to draw board
	* @private
 	* @property boardContext
 	* @type Object
 	*/
	boardContext 		= $('#chess-board').get(0).getContext('2d');
	
	/**
 	* Counter of moves to achieve a draw by 50 moves rule
 	* @property drawMoves
 	* @type Number
 	*/
    this.drawMoves = 0;
	
	/**
 	* A flag, represents if white side has right to castle long, valid falues are 'true' and 'false'
 	* @property whiteCanCastleLong
 	* @type String
 	*/
	this.whiteCanCastleLong		= "true";
	
	/**
 	* A flag, represents if white side has right to castle short, valid falues are 'true' and 'false'
 	* @property whiteCanCastleLong
 	* @type String
 	*/
	this.whiteCanCastleShort	= "true";
	
	/**
 	* A flag, represents if black side has right to castle long, valid falues are 'true' and 'false'
 	* @property whiteCanCastleLong
 	* @type String
 	*/
	this.blackCanCastleLong		= "true";
	
	/**
 	* A flag, represents if black side has right to castle short, valid falues are 'true' and 'false'
 	* @property whiteCanCastleLong
 	* @type String
 	*/
	this.blackCanCastleShort	= "true";
	
	/**
 	* An array of pieces on the board
 	* @property pieces
 	* @type Array
 	*/
    this.pieces = [];

	/**
	 * draws chess board with out pieces
	 * @method drawBoard
	 */
    this.drawBoard = function() {
        for(var i = 0; i < 8; i++) {
            for(var j = 0; j < 8; j++) {
                if((i+j)%2 == 0) {
                    boardContext.fillStyle = whiteField;
                } else {
                    boardContext.fillStyle = blackField;
                }               
                boardContext.fillRect(
					i * this.getFieldSize(), 
					j * this.getFieldSize(), 
					this.getFieldSize(), 
					this.getFieldSize());
            }
        }
    }
    
	/**
	 * draws chess pieces
	 * @method drawPieces
	 */
    this.drawPieces = function() {

        piecesContext.clearRect(0, 0, this.getBoardWidth(), this.getBoardWidth());
        
        for(var i = 0; i < this.pieces.length; i++) {
            
            var coord = getCanvasCoordinates(
				this.pieces[i].X, 
				this.pieces[i].Y, 
				this.getFieldSize());
			
			var img    = new Image();
			
			img.onload = (function(i, coord, fieldSize, img, ctx){
			   return function(){
				   ctx.drawImage(
					   img, 
					   coord.x, 
					   coord.y, 
					   fieldSize, 
					   fieldSize);
			   }
			})(i,coord,this.getFieldSize(), img, piecesContext);
			
			img.src = this.pieces[i].getImageSource();
			
        }
    }
    
	/**
	 * draws highlight of legal moves
	 * @method drawLegalMoves
	 */
    this.drawLegalMoves = function(moves) {
        for(var i = 0; i < moves.length; i++) {            
            lmovesContext.beginPath();
            var coor = getCanvasCoordinates(moves[i].x, moves[i].y, this.getFieldSize());
            lmovesContext.arc(
				coor.x + this.getFieldSize() * 0.5, 
				coor.y + this.getFieldSize() * 0.5,
				this.getFieldSize()*0.1,0,2*Math.PI);
            lmovesContext.closePath();
            lmovesContext.lineWidth = 2;
            lmovesContext.fillStyle = '#BC1B00';
            lmovesContext.fill();
            lmovesContext.strokeStyle = '#660E00';
            lmovesContext.stroke();
        }
    }
    
	/**
	 * draws highlight of selected piece
	 * @method highlightSelectedPiece
	 * @param {Object} piece selected piece
	 */
    this.highlightSelectedPiece = function(piece) {
		this.clearSelection();
        var coor = getCanvasCoordinates(piece.X, piece.Y, this.getFieldSize());    
        boardContext.fillStyle="rgb(199, 179, 125)";
        boardContext.fillRect(coor.x, coor.y, this.getFieldSize(), this.getFieldSize());
        this.drawLegalMoves(piece.getLegalMoves());
    }
    
	/**
	 * clears highlight of the selected piece
	 * @method clearSelection
	 */
    this.clearSelection = function() {
        lmovesContext.clearRect(0, 0, this.getBoardWidth(), this.getBoardWidth());
       
        for(var i = 0; i < 8; i++) {
            for(var j = 0; j < 8; j++) {
                if((i+j)%2 == 0) {
                    boardContext.fillStyle = whiteField;
                } else {
                    boardContext.fillStyle = blackField;
                }               
                boardContext.fillRect(
					i * this.getFieldSize(), 
					j * this.getFieldSize(), 
					this.getFieldSize(), 
					this.getFieldSize());
            }
        }
    }
	
	/**
	 * chnages current side to move
	 * @method changeSideToMove
	 */
	this.changeSideToMove = function() {
		if(this.sideToMove == "white") {
			this.sideToMove = "black";
			return;
		}
		if(this.sideToMove == "black") {
			this.sideToMove = "white";
			return;
		}
	}
	
	/**
	 * gets width of the board
	 * @method getBoardWidth
	 */
	this.getBoardWidth = function() {
		return $('#chess-pieces').get(0).width;
	}
	
	/**
	 * gets length of the side of the field
	 * @method getBoardWidth
	 */
	this.getFieldSize = function() {
		return $('#chess-pieces').get(0).width / 8;
	}
	
	/**
	 * renders the move of a piece 
	 * @method drawMove
	 * @param {Object} origin coordinates of origin
	 * @param {Object} destination coordinates of destination
	 * @param {Object} piece piece to move 
	 */
	this.drawMove = function(origin, destination, piece) {
		
		var originCanvasCoordinates = getCanvasCoordinates(origin.x, origin.y, this.getFieldSize());
		var destinationCoordinates	= getCanvasCoordinates(destination.x, destination.y, this.getFieldSize());
		
		piecesContext.clearRect(
			originCanvasCoordinates.x, 
			originCanvasCoordinates.y, 
			this.getFieldSize(), 
			this.getFieldSize());
		
		piecesContext.clearRect(
			destinationCoordinates.x, 
			destinationCoordinates.y, 
			this.getFieldSize(), 
			this.getFieldSize());
			
		var img    = new Image();
		img.onload = (function(coord, fieldSize, img, ctx){
		   return function(){
			   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
		   }
		})(destinationCoordinates,this.getFieldSize(), img, piecesContext);
		
		img.src = piece.getImageSource();
	}
	
	/**
	 * renders the castling 
	 * @method drawCastling
	 * @param {Object} origin coordinates of origin
	 * @param {Object} destination coordinates of destination
	 * @param {Object} piece piece to castle 
	 */
	this.drawCastling = function(origin, destination, piece) {
		
		var originCanvasCoordinates = getCanvasCoordinates(origin.x, origin.y, this.getFieldSize());
		var destinationCoordinates	= getCanvasCoordinates(destination.x, destination.y, this.getFieldSize());
		
		piecesContext.clearRect(
			originCanvasCoordinates.x, 
			originCanvasCoordinates.y, 
			this.getFieldSize(), 
			this.getFieldSize());
		
		if(destination.x == 2 && destination.y == 0) {
			var rookField = getCanvasCoordinates(0, 0, this.getFieldSize());
			piecesContext.clearRect(destinationCoordinates.x, destinationCoordinates.y, this.getFieldSize(), this.getFieldSize());
			piecesContext.clearRect(rookField.x, rookField.y, this.getFieldSize(), this.getFieldSize());
		}
		
		if(destination.x == 6 && destination.y == 0) {
			var rookField = getCanvasCoordinates(7, 0, this.getFieldSize());
			piecesContext.clearRect(destinationCoordinates.x, destinationCoordinates.y, this.getFieldSize(), this.getFieldSize());
			piecesContext.clearRect(rookField.x, rookField.y, this.getFieldSize(), this.getFieldSize());
		}
		
		if(destination.x == 2 && destination.y == 7) {
			var rookField = getCanvasCoordinates(0, 7, this.getFieldSize());
			piecesContext.clearRect(destinationCoordinates.x, destinationCoordinates.y, this.getFieldSize(), this.getFieldSize());
			piecesContext.clearRect(rookField.x, rookField.y, this.getFieldSize(), this.getFieldSize());
		}
		
		if(destination.x == 6 && destination.y == 7) {
			var rookField = getCanvasCoordinates(7, 7, this.getFieldSize());
			piecesContext.clearRect(destinationCoordinates.x, destinationCoordinates.y, this.getFieldSize(), this.getFieldSize());
			piecesContext.clearRect(rookField.x, rookField.y, this.getFieldSize(), this.getFieldSize());
		}
			
		var img    = new Image();
		img.onload = (function(coord, fieldSize, img, ctx){
		   return function(){
			   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
		   }
		})(destinationCoordinates,this.getFieldSize(), img, piecesContext);
		img.src = piece.getImageSource();
		
		
		if(destination.x == 2 && destination.y == 0) {
			var img_rook    = new Image();
			var coord = getCanvasCoordinates(3,0,this.getFieldSize());
			
			img_rook.onload = (function(coord, fieldSize, img, ctx){
			   return function(){
				   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
			   }
			})(coord,this.getFieldSize(), img_rook, piecesContext);
			img_rook.src = "images/pieces/brook.png";
		}
		
		if(destination.x == 6 && destination.y == 0) {
			var img_rook    = new Image();
			var coord = getCanvasCoordinates(5,0,this.getFieldSize());
			
			img_rook.onload = (function(coord, fieldSize, img, ctx){
			   return function(){
				   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
			   }
			})(coord,this.getFieldSize(), img_rook, piecesContext);
			img_rook.src = "images/pieces/brook.png";
		}
		
		if(destination.x == 2 && destination.y == 7) {
			var img_rook    = new Image();
			var coord = getCanvasCoordinates(3,7,this.getFieldSize());
			
			img_rook.onload = (function(coord, fieldSize, img, ctx){
			   return function(){
				   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
			   }
			})(coord,this.getFieldSize(), img_rook, piecesContext);
			img_rook.src = "images/pieces/wrook.png";
		}
		
		if(destination.x == 6 && destination.y == 7) {
			var img_rook    = new Image();
			var coord = getCanvasCoordinates(5,7,this.getFieldSize());
			
			img_rook.onload = (function(coord, fieldSize, img, ctx){
			   return function(){
				   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
			   }
			})(coord,this.getFieldSize(), img_rook, piecesContext);
			img_rook.src = "images/pieces/wrook.png";
		}
	}
	
	/**
	 * renders the en passant capture 
	 * @method drawEnpassant
	 * @param {Object} origin coordinates of origin
	 * @param {Object} destination coordinates of destination
	 * @param {Object} piece piece to take en passant 
	 */
	this.drawEnpassant = function(origin, destination, piece) {
		
		var originCanvasCoordinates = getCanvasCoordinates(origin.x, origin.y, this.getFieldSize());
		var destinationCoordinates	= getCanvasCoordinates(destination.x, destination.y, this.getFieldSize());
		
		piecesContext.clearRect(
			originCanvasCoordinates.x, 
			originCanvasCoordinates.y, 
			this.getFieldSize(), 
			this.getFieldSize());
		
		piecesContext.clearRect(
			destinationCoordinates.x, 
			destinationCoordinates.y, 
			this.getFieldSize(), 
			this.getFieldSize());
		
		if(piece.color == "white") {
			
			var clear = getCanvasCoordinates(destination.x, destination.y + 1, this.getFieldSize());
			
			piecesContext.clearRect(
			clear.x, 
			clear.y, 
			this.getFieldSize(), 
			this.getFieldSize());
		}
		
		if(piece.color == "black") {
			
			var clear = getCanvasCoordinates(destination.x, destination.y - 1, this.getFieldSize());
			
			piecesContext.clearRect(
			clear.x, 
			clear.y, 
			this.getFieldSize(), 
			this.getFieldSize());
		}
			
		var img    = new Image();
		img.onload = (function(coord, fieldSize, img, ctx){
		   return function(){
			   ctx.drawImage(img, coord.x, coord.y, fieldSize, fieldSize);
		   }
		})(destinationCoordinates,this.getFieldSize(), img, piecesContext);
		
		img.src = piece.getImageSource();
	}
	
	/**
	 * generates Forsyth–Edwards notation of the current state of the chess game
	 * @method getFEN
	 * @return {String} string represnts a Forsyth–Edwards notation of the current state of the chess game 
	 */
	this.getFEN = function() {
		var boardFields = [];
		
		for(var i = 0; i < 64; i++) boardFields.push(null);
		
		for(var i = 0; i < this.pieces.length; i++) {
			var piecePosition = this.pieces[i].Y * 8 + this.pieces[i].X;
			boardFields[piecePosition] = this.pieces[i];
		}
		
		var fenString = '';
		var spaces = 0;
		for(var i = 0; i < 64; i++) {
			
			if(boardFields[i] == null) {
				spaces++;
			} else {
				if(spaces != 0) fenString = fenString + spaces;
				
				fenString = fenString + boardFields[i].getNotationSymbol();
				spaces = 0;
			}
			
			if((i + 1)%8 == 0 && i != 63) {
				if(spaces != 0) {
					fenString = fenString + spaces;
					spaces = 0;
				}
				fenString = fenString + "/";
			}
		}
		
		return fenString;
	}
	
	/**
	 * sets a pieces property according to a given Forsyth–Edwards notation value
	 * @method setPieces
	 * @private
	 * @param {String} fen string represnts a Forsyth–Edwards notation
	 */
	setPieces = function(fen) {
		var boardFields = [];
		
		for(var i = 0; i < 64; i++) boardFields.push(null);
		
		var id = 0;
		var pieces = [];
		var fields = [];
		var skip = 0;
		
		for (var i = 0; i < fen.length; i++) {
			if(fen[i] == "/") continue;
			
			if(isNormalInteger(fen[i])) {
				
				var skip = fen[i];
				for(var j = 0; j < skip; j++) {
					fields.push(null);
				}
			}
			
			if(fen[i] == "K") fields.push("K");
			if(fen[i] == "k") fields.push("k");
			if(fen[i] == "Q") fields.push("Q");
			if(fen[i] == "q") fields.push("q");
			if(fen[i] == "R") fields.push("R");
			if(fen[i] == "r") fields.push("r");
			if(fen[i] == "B") fields.push("B");
			if(fen[i] == "b") fields.push("b");
			if(fen[i] == "N") fields.push("N");
			if(fen[i] == "n") fields.push("n");
			if(fen[i] == "P") fields.push("P");
			if(fen[i] == "p") fields.push("p");
		}
		
		for (var i = 0; i < fields.length; i++) {
			if(fields[i] == null) continue;
			
			curX = i%8;
			curY = Math.floor(i / 8);
			var curPiece;
			
			if(fields[i] == "K") curPiece = new King("white", "King", curX, curY, id++);
			if(fields[i] == "k") curPiece = new King("black", "King", curX, curY, id++);
			if(fields[i] == "Q") curPiece = new Queen("white", "Queen", curX, curY, id++);
			if(fields[i] == "q") curPiece = new Queen("black", "Queen", curX, curY, id++);
			if(fields[i] == "R") curPiece = new Rook("white", "Rook", curX, curY, id++);
			if(fields[i] == "r") curPiece = new Rook("black", "Rook", curX, curY, id++);
			if(fields[i] == "B") curPiece = new Bishop("white", "Bishop", curX, curY, id++);
			if(fields[i] == "b") curPiece = new Bishop("black", "Bishop", curX, curY, id++);
			if(fields[i] == "N") curPiece = new Knight("white", "Knight", curX, curY, id++);
			if(fields[i] == "n") curPiece = new Knight("black", "Knight", curX, curY, id++);
			if(fields[i] == "P") curPiece = new Pawn("white", "Pawn", curX, curY, id++);
			if(fields[i] == "p") curPiece = new Pawn("black", "Pawn", curX, curY, id++);
			
			pieces.push(curPiece);
		}
		
		that.pieces = pieces;
	}
	
	/**
	 * sets a board side of a player according to a given white player id
	 * @method setBoardSide
	 * @private
	 * @param {Number} wp_id white player id
	 */
	setBoardSide = function(wp_id) {
		if(userId == wp_id) {
			that.side = "white";
		} else {
			that.side = "black";
		}
	}
	
	/**
	 * sets a boolean flag to pawn which can be taken en passant
	 * @method setEnPassant
	 * @private
	 * @param {Object} coor the coordinates of the pawn to be set
	 */
	setEnPassant = function(coor) {
		var target = getXYfromNotationCoordinates(coor);
		
		if(!target) return;
		
		for(var i = 0; i < that.pieces.length; i++) {
			var p = that.pieces[i];
			if(p.X == target.x && p.Y == target.y && p.type == "Pawn") {
				p.canBeTakenEnPassant = true;
				return;
			}
		}
	}
	
	/**
	 * sets a chess board according to a given data
	 * @method setBoard
	 * @param {Object} data data represents the state of the game
	 */
	this.setBoard = function(data) {
		this.sideToMove = data.side_to_move;
		setPieces(data.fen);
		setBoardSide(data.white_player_id);
		setEnPassant(data.en_passant);
		this.whiteCanCastleLong 	= data.white_long_castling;
		this.whiteCanCastleShort 	= data.white_short_castling;
		this.blackCanCastleLong		= data.black_long_castling;
		this.blackCanCastleShort	= data.black_short_castling;
	} 
}