/**
module contains classes of pieces
@module Pieces
**/
/**
* A King class, represents a King piece
* @class King
* @constructor
* @param {} color king's color
* @param {} type type of the piece, e.g. "King"
* @param {} X x coordinate on the board (0-7), 0 represents 'a' file, 7 represents 'h' file
* @param {} Y y coordinate on the board (0-7), 0 represents 8-th rank, 7 represnts 1-st rank
* @param {} id id of the piece
*/
function King(color, type, X, Y, id) {
/**
* King's color
* @property color
* @type String
*/
this.color = color;
/**
* King's type
* @property type
* @type String
*/
this.type = type;
/**
* x coordinate
* @property X
* @type Number
*/
this.X = X;
/**
* y coordinate
* @property Y
* @type Number
*/
this.Y = Y;
/**
* King's ID
* @property ID
* @type Number
*/
this.ID = id;
/**
* notation symbol
* @property notationName
* @type String
*/
this.notationName = "K";
/**
* get relative path to the piece image
* @method getImageSource
* @return {String} path to the piece image
*/
this.getImageSource = function (){
if(this.color == "white") {
return "images/pieces/wking.png";
} else {
return "images/pieces/bking.png";
}
}
/**
* get piece legal moves
* @method getLegalMoves
* @return {Array} an array of (x,y) coordinates represents a legal moves for a piece
*/
this.getLegalMoves = function() {
var legalMoves = [
{x:this.X + 1, y:this.Y + 1},
{x:this.X - 1, y:this.Y - 1},
{x:this.X + 1, y:this.Y - 1},
{x:this.X - 1, y:this.Y + 1},
{x:this.X + 1, y:this.Y},
{x:this.X - 1, y:this.Y},
{x:this.X, y:this.Y + 1},
{x:this.X, y:this.Y - 1}
];
for(var i = 0; i < legalMoves.length; i++) {
if(legalMoves[i].x > 7 || legalMoves[i].y > 7 || legalMoves[i].x < 0 || legalMoves[i].y < 0) {
legalMoves[i] = null;
}
}
legalMoves = legalMoves.clean(null);
parentLoop:
for(var j = 0; j < legalMoves.length; j++) {
for(var i = 0; i < board.pieces.length; i++) {
var p = board.pieces[i];
var m = legalMoves[j];
if(legalMoves[j] == null) continue parentLoop;
if(p.X == m.x && p.Y == m.y && p.color == this.color) {
legalMoves[j] = null;
}
}
}
legalMoves = legalMoves.clean(null);
var temp = [];
for(var i = 0; i < board.pieces.length; i++) {
if(board.pieces[i].color != this.color) {
temp = temp.concat(board.pieces[i].getCoveredFields());
}
}
parentLoop:
for(var i = 0; i < legalMoves.length; i++) {
for(var j = 0; j < temp.length; j++) {
if(legalMoves[i].x == temp[j].x && legalMoves[i].y == temp[j].y) {
legalMoves[i] = null;
continue parentLoop;
}
}
}
legalMoves = legalMoves.clean(null);
var coveredFieldsBehind = [];
for(var i = 0; i < board.pieces.length; i++) {
var p = board.pieces[i];
if(p.type == "Bishop" && p.color != this.color) {
var f = getBishopFieldBehind(p.X, p.Y, p.color);
if(f!=null) coveredFieldsBehind.push(f);
}
if(p.type == "Rook" && p.color != this.color) {
var f = getRookFieldBehind(p.X, p.Y, p.color);
if(f!=null) coveredFieldsBehind.push(f);
}
if(p.type == "Queen" && p.color != this.color) {
var f = getBishopFieldBehind(p.X, p.Y, p.color);
if(f!=null) coveredFieldsBehind.push(f);
var f = getRookFieldBehind(p.X, p.Y, p.color);
if(f!=null) coveredFieldsBehind.push(f);
}
}
parentLoop:
for(var i = 0; i < legalMoves.length; i++) {
for(var j = 0; j < coveredFieldsBehind.length; j++) {
if(legalMoves[i].x == coveredFieldsBehind[j].x && legalMoves[i].y == coveredFieldsBehind[j].y) {
legalMoves[i] = null;
continue parentLoop;
}
}
}
legalMoves = legalMoves.clean(null);
if(this.color == "white" && this.checkCastling("short")) legalMoves.push({x:6,y:7});
if(this.color == "white" && this.checkCastling("long")) legalMoves.push({x:2,y:7});
if(this.color == "black" && this.checkCastling("short")) legalMoves.push({x:6,y:0});
if(this.color == "black" && this.checkCastling("long")) legalMoves.push({x:2,y:0});
legalMoves = legalMoves.clean(null);
return legalMoves;
}
/**
* get piece covered fields
* @method getCoveredFields
* @return {Array} an array of (x,y) coordinates represents a set of fields, covered by a piece
*/
this.getCoveredFields = function() {
var coveredFields = [
{x:this.X + 1, y:this.Y + 1},
{x:this.X - 1, y:this.Y - 1},
{x:this.X + 1, y:this.Y - 1},
{x:this.X - 1, y:this.Y + 1},
{x:this.X + 1, y:this.Y},
{x:this.X - 1, y:this.Y},
{x:this.X, y:this.Y + 1},
{x:this.X, y:this.Y - 1}
];
for(var i = 0; i < coveredFields.length; i++) {
if(coveredFields[i].x > 7 || coveredFields[i].y > 7 || coveredFields[i].x < 0 || coveredFields[i].y < 0) {
coveredFields[i] = null;
}
}
return coveredFields.clean(null);
}
/**
* checks if King has right to castle
* @method checkCastling
* @param {String} direction direction of the castling either 'long' or 'short'
* @return {Boolean} true if King has right to castle, false otherwise
*/
this.checkCastling = function(direction) {
if(this.color == "white") {
var canCastleLong = board.whiteCanCastleLong;
var canCastleShort = board.whiteCanCastleShort;
} else {
var canCastleLong = board.blackCanCastleLong;
var canCastleShort = board.blackCanCastleShort;
}
if(canCastleLong == "false" && canCastleShort == "false") return false;
if(direction == "short") {
if(canCastleShort == "false") return false;
for(var i = 0; i < board.pieces.length; i++) {
var p = board.pieces[i];
if(this.color == "white") {
if(p.X == 5 && p.Y == 7 || p.X == 6 && p.Y == 7) {
return false;
}
}
if(this.color == "black") {
if(p.X == 5 && p.Y == 0 || p.X == 6 && p.Y == 0) {
return false;
}
}
if(p.color != this.color) {
var cf = p.getCoveredFields();
for(var j = 0; j < cf.length; j++) {
if(this.color == "white") {
if(cf[j].x == 4 && cf[j].y == 7 || cf[j].x == 5 && cf[j].y == 7 || cf[j].x == 6 && cf[j].y == 7) {
return false;
}
}
if(this.color == "black") {
if(cf[j].x == 4 && cf[j].y == 0 || cf[j].x == 5 && cf[j].y == 0 || cf[j].x == 6 && cf[j].y == 0) {
return false;
}
}
}
}
}
return true;
}
if(direction == "long") {
if(canCastleLong == "false") return false;
for(var i = 0; i < board.pieces.length; i++) {
var p = board.pieces[i];
if(this.color == "white") {
if(p.X == 3 && p.Y == 7 || p.X == 2 && p.Y == 7 || p.X == 1 && p.Y == 7) {
return false;
}
}
if(this.color == "black") {
if(p.X == 3 && p.Y == 0 || p.X == 2 && p.Y == 0 || p.X == 1 && p.Y == 0) {
return false;
}
}
if(p.color != this.color) {
var cf = p.getCoveredFields();
for(var j = 0; j < cf.length; j++) {
if(this.color == "white") {
if(cf[j].x == 4 && cf[j].y == 7
|| cf[j].x == 3 && cf[j].y == 7
|| cf[j].x == 2 && cf[j].y == 7
|| cf[j].x == 1 && cf[j].y == 7) {
return false;
}
}
if(this.color == "black") {
if(cf[j].x == 4 && cf[j].y == 0
|| cf[j].x == 3 && cf[j].y == 0
|| cf[j].x == 2 && cf[j].y == 0
|| cf[j].x == 1 && cf[j].y == 0) {
return false;
}
}
}
}
}
return true;
}
}
/**
* moves piece to a new field
* @method move
* @param {Number} x x coordinate of destination
* @param {Number} y y coordinate of destination
* @return {Object} object represents a summary of the move
*/
this.move = function(x, y) {
if(!confirmMove(x,y,this)) return;
var _isCapture = removeCapturedPiece(x,y);
board.pieces = board.pieces.clean(null);
var origin = {x:this.X,y:this.Y};
var destination = {x:x,y:y};
for(var i = 0; i < board.pieces.length; i++) {
if(board.pieces[i].ID == this.ID) {
board.pieces[i].X = x;
board.pieces[i].Y = y;
}
}
var castling;
if(this.color == "white" && board.whiteCanCastleShort == "true" && x == 6 && y == 7) {
for(var i = 0; i < board.pieces.length; i++) {
if(board.pieces[i].X == 7 && board.pieces[i].Y == 7) {
board.pieces[i].X = 5;
board.pieces[i].Y = 7;
castling = "short";
board.whiteCanCastleShort = "false";
}
}
}
if(this.color == "white" && board.whiteCanCastleLong == "true" && x == 2 && y == 7) {
for(var i = 0; i < board.pieces.length; i++) {
if(board.pieces[i].X == 0 && board.pieces[i].Y == 7) {
board.pieces[i].X = 3;
board.pieces[i].Y = 7;
castling = "long";
board.whiteCanCastleLong = "false";
}
}
}
if(this.color == "black" && board.blackCanCastleShort == "true" && x == 6 && y == 0) {
for(var i = 0; i < board.pieces.length; i++) {
if(board.pieces[i].X == 7 && board.pieces[i].Y == 0) {
board.pieces[i].X = 5;
board.pieces[i].Y = 0;
castling = "short";
board.blackCanCastleShort = "false";
}
}
}
if(this.color == "black" && board.blackCanCastleLong == "true" && x == 2 && y == 0) {
for(var i = 0; i < board.pieces.length; i++) {
if(board.pieces[i].X == 0 && board.pieces[i].Y == 0) {
board.pieces[i].X = 3;
board.pieces[i].Y = 0;
castling = "long";
board.blackCanCastleLong = "false";
}
}
}
if(castling == "long" || castling == "short") {
board.drawCastling(origin, destination, this);
} else {
board.drawMove(origin, destination, this);
}
board.changeSideToMove();
var targetColor;
if(this.color == "white") {
targetColor = "black";
board.whiteCanCastleLong = "false";
board.whiteCanCastleShort = "false";
}
else {
targetColor = "white";
board.blackCanCastleLong = "false";
board.blackCanCastleShort = "false";
}
var _isCheck = isKingAttacked(targetColor);
var _isMate = isMate(targetColor);
var _isStalemate = isStalemate(targetColor);
if(_isCapture) {
board.drawMoves = 0;
} else {
board.drawMoves++;
}
return getMoveSummary(
this.notationName,
[],
origin,
destination,
castling,
_isCapture,
_isCheck,
_isMate,
_isStalemate,
"none",
"none");
}
/**
* get notation symbol of the piece
* @method getNotationSymbol
* @return {String} notation symbol
*/
this.getNotationSymbol = function() {
if(this.color == "white") {
return this.notationName.toUpperCase();
} else {
return this.notationName.toLowerCase();
}
}
}