User prompt
Add one more column next to the palaces, and count the newly added columns as “Sea"
User prompt
Add one more row behind all black and white Pieces , define these new rows as the “sea” row, set no Pieces to be able to enter the sea, and do not change the position of the Pieces
User prompt
Add one more line after White and Black, Add the “Sea” property to new line and set it so that no Pieces can enter the sea.
User prompt
Add the “Sea” property to every square in column M outside of “Palace” and set it so that no Pieces can enter the sea.
User prompt
Add the squares of column M
User prompt
Delete seaTexture
User prompt
Give separate textures to the black squares and white squares that are considered sea squares
User prompt
Add sea texture
User prompt
delete stunSquare
User prompt
Add the “Sea” property to every square in column A outside of “Palace” and set it so that no Pieces can enter the sea.
User prompt
Add the “Sea” property to each square in column A of the Sayar external table and set it so that no stones can enter the sea
User prompt
Add the squares of column A
User prompt
Add the squares of a stun
User prompt
class Piece { String type; // e.g., "king", "pawn", etc. String color; // "white" or "black" boolean mustExitSaray = false; public Piece(String type, String color) { this.type = type; this.color = color; } public boolean isKing() { return this.type.equals("king"); } } public class ChessBoard { Piece[][] board = new Piece[8][8]; // Define saray positions (you can extend this to a list if saray is multi-cell) int[] whiteSaray = {0, 3}; int[] blackSaray = {7, 3}; // Is a given square a saray? boolean isSaray(int row, int col) { return (row == whiteSaray[0] && col == whiteSaray[1]) || (row == blackSaray[0] && col == blackSaray[1]); } // Is a piece inside its own saray? boolean isInOwnSaray(Piece p, int row, int col) { if (p.color.equals("white")) { return row == whiteSaray[0] && col == whiteSaray[1]; } else { return row == blackSaray[0] && col == blackSaray[1]; } } // Call this at the end of a turn to tag the king if it's in saray void checkIfKingMustExitNextTurn(String playerColor) { for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { Piece p = board[r][c]; if (p != null && p.color.equals(playerColor) && p.isKing() && isInOwnSaray(p, r, c)) { p.mustExitSaray = true; System.out.println(playerColor + "'s king must exit saray on next turn."); } } } } // Called at the start of player's turn — enforce exit or declare checkmate boolean enforceSarayExitOrMate(String playerColor) { for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { Piece p = board[r][c]; if (p != null && p.color.equals(playerColor) && p.isKing() && p.mustExitSaray && isInOwnSaray(p, r, c)) { if (canEscapeFromSaray(r, c)) { System.out.println(playerColor + " must move the king out of saray this turn."); return false; // Not checkmate, but required move } else { System.out.println(playerColor + " has no legal escape — checkmate."); return true; // Checkmate due to no exit } } } } return false; // No forced exits } // Check if the king can move out of saray boolean canEscapeFromSaray(int row, int col) { int[] dr = {-1, -1, -1, 0, 1, 1, 1, 0}; int[] dc = {-1, 0, 1, 1, 1, 0, -1, -1}; for (int i = 0; i < 8; i++) { int nr = row + dr[i]; int nc = col + dc[i]; if (isValidSquare(nr, nc) && board[nr][nc] == null) { return true; } } return false; } boolean isValidSquare(int r, int c) { return r >= 0 && r < 8 && c >= 0 && c < 8; } }
User prompt
Remove adventurous king promotion to king when entering own saray
User prompt
class Piece { String type; String color; boolean mustExitSaray = false; Piece(String type, String color) { this.type = type; this.color = color; } } public class ChessBoard { Piece[][] board = new Piece[8][8]; // Coordinates of the white and black saray squares int[] whiteSaray = {0, 3}; // Example: top middle int[] blackSaray = {7, 3}; // Example: bottom middle // Checks if a square is one of the saray squares boolean isSaray(int row, int col) { return (row == whiteSaray[0] && col == whiteSaray[1]) || (row == blackSaray[0] && col == blackSaray[1]); } // Checks if a piece is in its own saray boolean isInOwnSaray(Piece piece, int row, int col) { return (piece.color.equals("white") && row == whiteSaray[0] && col == whiteSaray[1]) || (piece.color.equals("black") && row == blackSaray[0] && col == blackSaray[1]); } // Promotion from adventurousKing to king void promoteAdventurousKingToKing(int row, int col) { Piece p = board[row][col]; if (p != null && p.type.equals("adventurousKing")) { boolean inSaray = isInOwnSaray(p, row, col); p.type = "king"; p.mustExitSaray = inSaray; if (inSaray) { System.out.println("AdventurousKing promoted to King inside own saray — must exit next turn."); } else { System.out.println("AdventurousKing promoted to King outside saray — no exit required."); } } } // Checks if the player has any king that is required to exit their saray boolean mustExitSarayThisTurn(String playerColor) { for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { Piece p = board[r][c]; if (p != null && p.color.equals(playerColor) && p.mustExitSaray && isInOwnSaray(p, r, c)) { return true; } } } return false; } // Checks if the king has any valid escape square from saray boolean canEscapeFromSaray(String playerColor) { for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { Piece p = board[r][c]; if (p != null && p.color.equals(playerColor) && p.mustExitSaray && isInOwnSaray(p, r, c)) { // Check 8 surrounding squares (like king movement) int[] dr = {-1, -1, -1, 0, 1, 1, 1, 0}; int[] dc = {-1, 0, 1, 1, 1, 0, -1, -1}; for (int i = 0; i < 8; i++) { int nr = r + dr[i], nc = c + dc[i]; if (isValidSquare(nr, nc) && board[nr][nc] == null) { return true; // Found an empty escape square } } return false; // Surrounded, no escape } } } return true; // No forced exit kings found } // Called at the beginning of a player's turn boolean checkForcedSarayExitOrMate(String playerColor) { if (mustExitSarayThisTurn(playerColor)) { if (canEscapeFromSaray(playerColor)) { System.out.println(playerColor + " must move King out of saray this turn."); return false; // Not mated, but must move } else { System.out.println(playerColor + " cannot escape saray — checkmate."); return true; // Mated } } return false; // No forced exits pending } boolean isValidSquare(int r, int c) { return r >= 0 && r < 8 && c >= 0 && c < 8; } }
User prompt
class Piece { String type; String color; boolean mustExitSaray = false; Piece(String type, String color) { this.type = type; this.color = color; } boolean isKingLike() { return type.equals("king") || type.equals("adventurousKing"); } } public class ChessBoard { Piece[][] board = new Piece[8][8]; int[] whiteSaray = {0, 3}; int[] blackSaray = {7, 3}; // Check if a square is a saray square boolean isSaray(int row, int col) { return (row == whiteSaray[0] && col == whiteSaray[1]) || (row == blackSaray[0] && col == blackSaray[1]); } // Check if a piece is in its own saray boolean isInOwnSaray(Piece p, int row, int col) { return (p.color.equals("white") && row == whiteSaray[0] && col == whiteSaray[1]) || (p.color.equals("black") && row == blackSaray[0] && col == blackSaray[1]); } // When adventurousKing transforms into king void transformToKing(Piece p, int row, int col) { if (p.type.equals("adventurousKing") && isInOwnSaray(p, row, col)) { p.type = "king"; p.mustExitSaray = true; System.out.println("AdventurousKing became King in saray — must exit next turn."); } else { p.type = "king"; // no restriction if not in saray } } // Check if any piece is flagged for forced saray exit boolean mustExitSaray(String color) { for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { Piece p = board[r][c]; if (p != null && p.color.equals(color) && p.mustExitSaray && isInOwnSaray(p, r, c)) { return true; } } } return false; } // Try to move the forced piece out of saray boolean hasEscapeFromSaray(String color) { for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { Piece p = board[r][c]; if (p != null && p.color.equals(color) && p.mustExitSaray && isInOwnSaray(p, r, c)) { // Try all 8 surrounding squares (king movement) int[] dr = {-1, -1, -1, 0, 1, 1, 1, 0}; int[] dc = {-1, 0, 1, 1, 1, 0, -1, -1}; for (int i = 0; i < 8; i++) { int nr = r + dr[i], nc = c + dc[i]; if (isValidSquare(nr, nc) && board[nr][nc] == null) { return true; // can escape } } return false; // surrounded } } } return true; // no forced piece found → no problem } boolean isValidSquare(int r, int c) { return r >= 0 && r < 8 && c >= 0 && c < 8; } // Call this at the beginning of player's turn boolean checkForcedExitOrMate(String playerColor) { if (mustExitSaray(playerColor)) { if (hasEscapeFromSaray(playerColor)) { System.out.println(playerColor + " must move king out of saray this turn."); return false; // not mated yet } else { System.out.println(playerColor + " has no way to exit saray — checkmated."); return true; // checkmate due to forced exit failure } } return false; } }
User prompt
class Piece { String type; String color; boolean mustExitSaray = false; Piece(String type, String color) { this.type = type; this.color = color; } } public class ChessBoard { Piece[][] board = new Piece[8][8]; int[] whiteSaray = {0, 3}; int[] blackSaray = {7, 3}; // Checks if the destination is a saray square boolean isSaray(int row, int col) { return (row == whiteSaray[0] && col == whiteSaray[1]) || (row == blackSaray[0] && col == blackSaray[1]); } // Determines if a piece is allowed to enter a saray square boolean canEnterSaray(Piece mover, int toRow, int toCol, Piece target, boolean isCapturing) { if (mover == null) return false; boolean isWhiteSaray = (toRow == whiteSaray[0] && toCol == whiteSaray[1]); boolean isBlackSaray = (toRow == blackSaray[0] && toCol == blackSaray[1]); String t = mover.type; String c = mover.color; // Normal allowed entry if ((t.equals("adventurousKing")) || (isBlackSaray && c.equals("white") && (t.equals("king") || t.equals("shahsade"))) || (isWhiteSaray && c.equals("black") && (t.equals("king") || t.equals("shahsade")))) { return true; } // Special rule: capture king/shahsade/adventurousKing in saray if under threat if (isCapturing && target != null && (target.type.equals("king") || target.type.equals("shahsade") || target.type.equals("adventurousKing")) && isSaray(toRow, toCol)) { return true; } return !isSaray(toRow, toCol); // deny entry to saray unless allowed } // After a saray capture, mark the attacking piece void handleSarayCapture(Piece attacker, int row, int col) { if (isSaray(row, col)) { attacker.mustExitSaray = true; } } // Enforce mandatory exit on player's next turn boolean mustMoveFirst(Piece piece, int row, int col) { if (piece == null || !piece.mustExitSaray) return false; if (isSaray(row, col)) { return true; // still inside → must move out } else { piece.mustExitSaray = false; // already out → clear flag return false; } } // Move logic sample (you can integrate this) boolean makeMove(int fromRow, int fromCol, int toRow, int toCol, String playerColor) { Piece mover = board[fromRow][fromCol]; if (mover == null || !mover.color.equals(playerColor)) return false; Piece target = board[toRow][toCol]; boolean isCapturing = target != null && !target.color.equals(playerColor); // Saray entry rule if (!canEnterSaray(mover, toRow, toCol, target, isCapturing)) return false; // Apply saray capture flag if needed if (isCapturing && isSaray(toRow, toCol)) { handleSarayCapture(mover, toRow, toCol); } // Move the piece board[toRow][toCol] = mover; board[fromRow][fromCol] = null; return true; } // Force piece out of saray if required void enforceSarayExit(String playerColor) { for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { Piece p = board[row][col]; if (p != null && p.color.equals(playerColor) && mustMoveFirst(p, row, col)) { System.out.println(playerColor + " must move piece at (" + row + "," + col + ") out of saray."); // Your move-forcing logic goes here } } } } }
User prompt
Please fix the bug: 'Uncaught TypeError: confirm is not a function' in or related to this line: 'var response = confirm(playerName + ' offers a draw. Do you accept? (OK for Yes, Cancel for No)');' Line Number: 3647
User prompt
boolean canEnterSaray(Piece piece, int row, int col) { // Coordinates of Saray squares int[] whiteSaray = {0, 3}; // example location int[] blackSaray = {7, 3}; // example location if (piece == null) return false; String type = piece.type; String color = piece.color; // Check if moving to Black Saray if (row == blackSaray[0] && col == blackSaray[1]) { return ( (type.equals("adventurousKing")) || (color.equals("white") && (type.equals("king") || type.equals("shahsade"))) ); } // Check if moving to White Saray if (row == whiteSaray[0] && col == whiteSaray[1]) { return ( (type.equals("adventurousKing")) || (color.equals("black") && (type.equals("king") || type.equals("shahsade"))) ); } // Not a saray square → no restriction return true; }
User prompt
Only the specified pieces can enter the white player's palace White Adventurer King, Black Adventurer King, Shah, shahsade
User prompt
Prevent pawn of pawns from being teleported outside the board
User prompt
Only Shahs, Princes, and Adventurous Kings can enter palaces, and players can only take the Adventurous King to their own palaces. If a Shah, Prince, or Adventurer King enters an opponent's palace, they may choose to end the game in a draw while they are in the palace. After one of the specified pieces enters the palace, ask the player if they wish to end the game in a draw. Add the options “yes” or “no.” If they say “yes,” the game ends in a draw. If they say “no,” the game continues. Palaces can be threatened by opposing pieces. If a palace is under threat, the specified pieces cannot enter the palace. If a piece inside the palace is captured by opposing pieces, the opponent must move the piece inside the palace in the next turn.
User prompt
Mark the square to the right of k9 as “White Palace” and give it a different texture
User prompt
Mark the square to the left of a2 as “Black Palace” and give it a different texture
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ChessPiece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.pieceType = type;
self.pieceColor = color; // 0 = white, 1 = black
self.boardRow = row;
self.boardCol = col;
self.hasMoved = false;
self.isPromoted = false; // Track permanent promotion status for vizier
self.hasTeleported = false; // Track if pawn's pawn has used teleportation
self.mustExitSaray = false; // Track if piece must exit saray after capture
var pieceGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
if (color === 1) {
pieceGraphics.tint = 0x333333;
}
self.moveTo = function (newRow, newCol) {
self.boardRow = newRow;
self.boardCol = newCol;
self.hasMoved = true;
var boardPos = getBoardPosition(newRow, newCol);
tween(self, {
x: boardPos.x,
y: boardPos.y
}, {
duration: 300
});
};
self.getRawMoves = function () {
var moves = [];
var directions = [];
switch (self.pieceType) {
case 'pawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'rook':
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist < 11; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'bishop':
// Bishop can move one square orthogonally (row/column only)
var oneSquareOrthogonalDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
// Add one square moves in orthogonal directions only
for (var i = 0; i < oneSquareOrthogonalDirections.length; i++) {
var dir = oneSquareOrthogonalDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Bishop can also move as many squares as wanted diagonally (minimum 2) without jumping over friendly pieces
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
for (var dist = 2; dist < 11; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Check if path is blocked by any piece (friendly or enemy)
var pathBlocked = false;
for (var checkDist = 1; checkDist < dist; checkDist++) {
var checkRow = self.boardRow + dir.dr * checkDist;
var checkCol = self.boardCol + dir.dc * checkDist;
var pathPiece = getPieceAt(checkRow, checkCol);
if (pathPiece) {
pathBlocked = true;
break;
}
}
if (pathBlocked) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'queen':
// Vizier: restricted to one square, enhanced to eight squares when promoted
// Diagonal movement is closed at the beginning (only orthogonal moves allowed)
// When promoted, both orthogonal and diagonal moves are allowed
if (self.isPromoted) {
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
} else {
// Only orthogonal moves at the beginning (diagonals closed)
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
}
var maxDistance = self.isPromoted ? 8 : 1;
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist <= maxDistance; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'king':
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'knight':
var knightMoves = [{
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}, {
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
}, {
dr: 1,
dc: 2
}, {
dr: 1,
dc: -2
}, {
dr: -1,
dc: 2
}, {
dr: -1,
dc: -2
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'warElephant':
// Moves 1 or 2 steps row, column, and diagonal with jumping ability
// Elephant cannot be stopped by any pieces (friendly or enemy)
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist <= 2; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Elephant ignores all pieces and can move through them
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
// Continue moving even if there's a piece - elephant cannot be stopped
}
}
break;
case 'siegeTower':
// Must move 1 square in row/column, then 1 square diagonally
// Captures enemy pieces in its path
// siegeTower cannot be stopped by enemies
var orthogonalDirections = [{
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}];
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
// Try L-shaped moves: orthogonal then diagonal
for (var i = 0; i < orthogonalDirections.length; i++) {
var orthDir = orthogonalDirections[i];
var firstRow = self.boardRow + orthDir.dr;
var firstCol = self.boardCol + orthDir.dc;
if (!isValidSquare(firstRow, firstCol)) {
continue;
}
var firstPiece = getPieceAt(firstRow, firstCol);
// siegeTower cannot be stopped by enemies, but friendly pieces still block
if (firstPiece && firstPiece.pieceColor === self.pieceColor) {
// Can't move through friendly piece, skip this direction
continue;
}
// Try diagonal moves from the orthogonal position
for (var j = 0; j < diagonalDirections.length; j++) {
var diagDir = diagonalDirections[j];
var finalRow = firstRow + diagDir.dr;
var finalCol = firstCol + diagDir.dc;
if (!isValidSquare(finalRow, finalCol)) {
continue;
}
var finalPiece = getPieceAt(finalRow, finalCol);
if (!finalPiece || finalPiece.pieceColor !== self.pieceColor) {
var moveData = {
row: finalRow,
col: finalCol,
capturesInPath: []
};
// Add captured pieces in path
if (firstPiece && firstPiece.pieceColor !== self.pieceColor) {
moveData.capturesInPath.push({
row: firstRow,
col: firstCol
});
}
if (finalPiece && finalPiece.pieceColor !== self.pieceColor) {
moveData.capturesInPath.push({
row: finalRow,
col: finalCol
});
}
moves.push(moveData);
}
}
}
// If friendly piece in orthogonal path, allow simple orthogonal move
for (var i = 0; i < orthogonalDirections.length; i++) {
var orthDir = orthogonalDirections[i];
var newRow = self.boardRow + orthDir.dr;
var newCol = self.boardCol + orthDir.dc;
if (!isValidSquare(newRow, newCol)) {
continue;
}
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'minister':
// Minister: 1 square diagonally, when promoted moves like rook and knight with jumping
if (self.isPromoted) {
// Rook-like moves (can jump over pieces when promoted)
var rookDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < rookDirections.length; i++) {
var dir = rookDirections[i];
for (var dist = 1; dist < 11; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// Knight-like moves (can jump over pieces)
var knightMoves = [{
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}, {
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
}, {
dr: 1,
dc: 2
}, {
dr: 1,
dc: -2
}, {
dr: -1,
dc: 2
}, {
dr: -1,
dc: -2
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
} else {
// Standard minister: 1 square diagonally
directions = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
}
break;
case 'royalGuard':
// Up to 3 squares diagonally with blockage of friendly pieces
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
for (var dist = 1; dist <= 3; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// Only 2 squares along rows and columns (no 1-step moves)
var orthogonalDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < orthogonalDirections.length; i++) {
var dir = orthogonalDirections[i];
// Only allow 2-step moves in orthogonal directions
var dist = 2;
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Forward or backward L-shaped moves (no left/right L moves)
var lShapeMoves = [
// Forward L-shapes
{
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
},
// Backward L-shapes
{
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}];
for (var i = 0; i < lShapeMoves.length; i++) {
var move = lShapeMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'giraffe':
// Giraffe: one diagonal move followed by 3-10 straight moves with obstacle checking
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var diagDir = diagonalDirections[i];
var firstRow = self.boardRow + diagDir.dr;
var firstCol = self.boardCol + diagDir.dc;
if (!isValidSquare(firstRow, firstCol)) {
continue;
}
var firstPiece = getPieceAt(firstRow, firstCol);
if (firstPiece) {
continue; // First diagonal square must be empty
}
// Determine straight directions based on diagonal direction
var straightDirections = [];
if (diagDir.dr > 0) {
straightDirections.push({
dr: 1,
dc: 0
}); // downward
}
if (diagDir.dr < 0) {
straightDirections.push({
dr: -1,
dc: 0
}); // upward
}
if (diagDir.dc > 0) {
straightDirections.push({
dr: 0,
dc: 1
}); // rightward
}
if (diagDir.dc < 0) {
straightDirections.push({
dr: 0,
dc: -1
}); // leftward
}
// Try straight moves from 3 to 10 squares in each valid direction
for (var j = 0; j < straightDirections.length; j++) {
var straightDir = straightDirections[j];
for (var step = 3; step <= 10; step++) {
var newRow = firstRow + straightDir.dr * step;
var newCol = firstCol + straightDir.dc * step;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Check if path is clear from diagonal position to target
var pathClear = true;
for (var checkStep = 1; checkStep <= step; checkStep++) {
var checkRow = firstRow + straightDir.dr * checkStep;
var checkCol = firstCol + straightDir.dc * checkStep;
var checkPiece = getPieceAt(checkRow, checkCol);
if (checkPiece) {
if (checkStep === step && checkPiece.pieceColor !== self.pieceColor) {
// Can capture enemy piece at final position
moves.push({
row: newRow,
col: newCol
});
}
pathClear = false;
break;
}
}
if (pathClear) {
moves.push({
row: newRow,
col: newCol
});
}
if (!pathClear) {
break; // Stop checking longer distances in this direction
}
}
}
}
break;
case 'bull':
// Bull can move one column forward or backward
var columnDirections = [{
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < columnDirections.length; i++) {
var colDir = columnDirections[i];
var newRow = self.boardRow + colDir.dr;
var newCol = self.boardCol + colDir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Bull moves one square forward or backward in column, then unlimited diagonal movement in same direction
for (var i = 0; i < columnDirections.length; i++) {
var colDir = columnDirections[i];
var firstRow = self.boardRow + colDir.dr;
var firstCol = self.boardCol + colDir.dc;
if (!isValidSquare(firstRow, firstCol)) {
continue;
}
var firstPiece = getPieceAt(firstRow, firstCol);
if (firstPiece) {
continue; // First square must be empty for bull movement
}
// From the first square, move diagonally unlimited in the forward/backward direction
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var j = 0; j < diagonalDirections.length; j++) {
var diagDir = diagonalDirections[j];
// Only allow diagonal movement in same forward/backward direction as column move
if (colDir.dr > 0 && diagDir.dr <= 0 || colDir.dr < 0 && diagDir.dr >= 0) {
continue; // Skip diagonal directions that don't match column direction
}
// Move unlimited squares diagonally from first position
for (var dist = 1; dist < 11; dist++) {
var finalRow = firstRow + diagDir.dr * dist;
var finalCol = firstCol + diagDir.dc * dist;
if (!isValidSquare(finalRow, finalCol)) {
break;
}
var finalPiece = getPieceAt(finalRow, finalCol);
if (finalPiece) {
if (finalPiece.pieceColor !== self.pieceColor) {
moves.push({
row: finalRow,
col: finalCol
});
}
break;
}
moves.push({
row: finalRow,
col: finalCol
});
}
}
}
// Bull can also jump two squares left and right
var leftRightJumps = [{
dr: 0,
dc: 2
}, {
dr: 0,
dc: -2
}];
for (var i = 0; i < leftRightJumps.length; i++) {
var jump = leftRightJumps[i];
var newRow = self.boardRow + jump.dr;
var newCol = self.boardCol + jump.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'camel':
// 1 square column and row (orthogonal moves)
var orthogonalDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < orthogonalDirections.length; i++) {
var dir = orthogonalDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// 1 square long L (knight-like moves)
var knightMoves = [{
dr: 3,
dc: 1
}, {
dr: 3,
dc: -1
}, {
dr: -3,
dc: 1
}, {
dr: -3,
dc: -1
}, {
dr: 1,
dc: 3
}, {
dr: 1,
dc: -3
}, {
dr: -1,
dc: 3
}, {
dr: -1,
dc: -3
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'lion':
// Lion has three distinct movement patterns:
// 1. Move 3 squares diagonally in one direction
// 2. L-shaped moves (forward/backward 2 + right/left 1)
// 3. Move 2 diagonally + 1 forward/backward
// 1st Move: 3 squares diagonally (similar to original code)
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
var pathBlocked = false;
for (var dist = 1; dist <= 3; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// 2nd Move: L-shaped moves (forward/backward 2 + right/left 1)
var lShapeMoves = [{
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
}, {
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}];
for (var i = 0; i < lShapeMoves.length; i++) {
var move = lShapeMoves[i];
var midRow = self.boardRow + move.dr / 2;
var endRow = self.boardRow + move.dr;
var endCol = self.boardCol + move.dc;
// Check if vertical path is clear (first two squares)
if (!isValidSquare(midRow, self.boardCol) || getPieceAt(midRow, self.boardCol)) {
continue;
}
// Check for diagonal obstacles
var diagonalBlocked = false;
if (move.dr < 0) {
// moving up
if (move.dc == -1 && getPieceAt(self.boardRow - 1, self.boardCol - 1)) {
diagonalBlocked = true;
}
if (move.dc == 1 && getPieceAt(self.boardRow - 1, self.boardCol + 1)) {
diagonalBlocked = true;
}
} else {
// moving down
if (move.dc == -1 && getPieceAt(self.boardRow + 1, self.boardCol - 1)) {
diagonalBlocked = true;
}
if (move.dc == 1 && getPieceAt(self.boardRow + 1, self.boardCol + 1)) {
diagonalBlocked = true;
}
}
if (diagonalBlocked) {
continue;
}
if (isValidSquare(endRow, endCol)) {
var piece = getPieceAt(endRow, endCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: endRow,
col: endCol
});
}
}
}
// 3rd Move: 2 diagonals + 1 forward/backward
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
var pathBlocked = false;
// Check if we can move 2 squares diagonally
for (var checkDist = 1; checkDist <= 2; checkDist++) {
var checkRow = self.boardRow + dir.dr * checkDist;
var checkCol = self.boardCol + dir.dc * checkDist;
if (!isValidSquare(checkRow, checkCol)) {
pathBlocked = true;
break;
}
var pathPiece = getPieceAt(checkRow, checkCol);
if (pathPiece) {
pathBlocked = true;
break;
}
}
if (pathBlocked) {
continue;
}
var twoSquareRow = self.boardRow + dir.dr * 2;
var twoSquareCol = self.boardCol + dir.dc * 2;
// Then move 1 square forward or backward
var verticalMoves = [{
dr: -1,
dc: 0
}, {
dr: 1,
dc: 0
}];
for (var j = 0; j < verticalMoves.length; j++) {
var vertMove = verticalMoves[j];
var finalRow = twoSquareRow + vertMove.dr;
var finalCol = twoSquareCol + vertMove.dc;
if (isValidSquare(finalRow, finalCol)) {
var piece = getPieceAt(finalRow, finalCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: finalRow,
col: finalCol
});
}
}
}
}
// Remove side L-shaped moves from the moves list
moves = moves.filter(function (move) {
return !isSideLMove(self.boardRow, self.boardCol, move.row, move.col);
});
break;
case 'pawnOfTheWarMachine':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheWarMachine' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'camelPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'camelPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'ministersPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'ministersPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnOfTheElephant':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheElephant' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'shahsade':
// King-like movement: 1 square in any direction
var kingDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < kingDirections.length; i++) {
var dir = kingDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// 2 squares diagonally, horizontally, vertically
var shahsadeDirections = [{
dr: 0,
dc: 2
}, {
dr: 0,
dc: -2
}, {
dr: 2,
dc: 0
}, {
dr: -2,
dc: 0
}, {
dr: 2,
dc: 2
}, {
dr: 2,
dc: -2
}, {
dr: -2,
dc: 2
}, {
dr: -2,
dc: -2
}];
for (var i = 0; i < shahsadeDirections.length; i++) {
var dir = shahsadeDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
// Check if path is blocked by any piece
var pathBlocked = false;
var stepRow = dir.dr === 0 ? 0 : dir.dr > 0 ? 1 : -1;
var stepCol = dir.dc === 0 ? 0 : dir.dc > 0 ? 1 : -1;
var checkRow = self.boardRow + stepRow;
var checkCol = self.boardCol + stepCol;
var pathPiece = getPieceAt(checkRow, checkCol);
if (pathPiece) {
pathBlocked = true;
}
if (!pathBlocked) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
}
break;
case 'adventurousKing':
// King-like movement: 1 square in any direction
var kingDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < kingDirections.length; i++) {
var dir = kingDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// 2 squares diagonally, horizontally, vertically (adventurous Shah can jump over pieces)
var adventurousKingDirections = [{
dr: 0,
dc: 2
}, {
dr: 0,
dc: -2
}, {
dr: 2,
dc: 0
}, {
dr: -2,
dc: 0
}, {
dr: 2,
dc: 2
}, {
dr: 2,
dc: -2
}, {
dr: -2,
dc: 2
}, {
dr: -2,
dc: -2
}];
for (var i = 0; i < adventurousKingDirections.length; i++) {
var dir = adventurousKingDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
// Adventurous Shah can jump over pieces - no path blocking check
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'kingsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'kingsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'viziersPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'viziersPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'giraffePawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'giraffePawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'knightPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'knightPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'rookPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'rookPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnOfTheLeader':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheLeader' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'guardsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
// Forward move (no double move for Guard's Pawn)
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'guardsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnOfTheBull':
var direction = self.pieceColor === 0 ? -1 : 1;
// Forward move (no double move for Pawn of the Bull)
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheBull' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'lionsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
// Forward move (no double move for Lion's Pawn)
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'lionsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
}
return moves;
};
self.getValidMoves = function () {
var moves = self.getRawMoves();
// Add castling for king after getting raw moves
if (self.pieceType === 'king' && !self.hasMoved && !isInCheck(self.pieceColor)) {
// Kingside castling - rook is at col + 5 (distance from king to rook)
var kingsideRook = getPieceAt(self.boardRow, self.boardCol + 5);
if (kingsideRook && kingsideRook.pieceType === 'rook' && !kingsideRook.hasMoved) {
var canCastle = true;
// Check squares between king and rook are empty and not attacked
for (var c = self.boardCol + 1; c < self.boardCol + 5; c++) {
if (getPieceAt(self.boardRow, c) || isSquareAttacked(self.boardRow, c, 1 - self.pieceColor)) {
canCastle = false;
break;
}
}
if (canCastle) {
moves.push({
row: self.boardRow,
col: self.boardCol + 2,
isCastling: true,
rookFromCol: self.boardCol + 5,
rookToCol: self.boardCol + 1
});
}
}
// Queenside castling - rook is at col - 5 (distance from king to rook)
var queensideRook = getPieceAt(self.boardRow, self.boardCol - 5);
if (queensideRook && queensideRook.pieceType === 'rook' && !queensideRook.hasMoved) {
var canCastle = true;
// Check squares between king and rook are empty and not attacked
for (var c = self.boardCol - 1; c > self.boardCol - 5; c--) {
if (getPieceAt(self.boardRow, c) || isSquareAttacked(self.boardRow, c, 1 - self.pieceColor)) {
canCastle = false;
break;
}
}
if (canCastle) {
moves.push({
row: self.boardRow,
col: self.boardCol - 2,
isCastling: true,
rookFromCol: self.boardCol - 5,
rookToCol: self.boardCol - 1
});
}
}
}
// Filter moves that would leave the king in check
var validMoves = [];
for (var i = 0; i < moves.length; i++) {
if (isValidMoveConsideringCheck(self, moves[i].row, moves[i].col)) {
// Additional check for palace entry
if (isPalaceSquare(moves[i].row, moves[i].col)) {
if (canEnterPalace(self, moves[i].row, moves[i].col)) {
validMoves.push(moves[i]);
}
} else {
validMoves.push(moves[i]);
}
}
}
return validMoves;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var BOARD_WIDTH = 13;
var BOARD_HEIGHT = 10;
var SQUARE_SIZE = 140;
var BOARD_START_X = (2048 - BOARD_WIDTH * SQUARE_SIZE) / 2;
var BOARD_START_Y = (2732 - BOARD_HEIGHT * SQUARE_SIZE) / 2 + 100;
var boardSquares = [];
var pieces = [];
var selectedPiece = null;
var highlightedSquares = [];
var currentPlayer = 0; // 0 = white, 1 = black
var gameStarted = false;
var lastMove = null;
var shahsadePromoted = [false, false]; // Track if shahsade has been promoted for each player
var pawnsPawnHasUsedSpecialMove = []; // Track which pawn's pawns have used their special move
var pawnsPawnMovementCount = []; // Track how many squares each pawn's pawn has moved
var shahPositionSwapUsed = [false, false]; // Track if Shah position swap has been used for each player
var swapHighlights = []; // Track swap highlight squares
function getBoardPosition(row, col) {
return {
x: BOARD_START_X + col * SQUARE_SIZE + SQUARE_SIZE / 2,
y: BOARD_START_Y + row * SQUARE_SIZE + SQUARE_SIZE / 2
};
}
function getBoardCoordinates(x, y) {
var col = Math.floor((x - BOARD_START_X) / SQUARE_SIZE);
var row = Math.floor((y - BOARD_START_Y) / SQUARE_SIZE);
return {
row: row,
col: col
};
}
function positionToAlgebraic(row, col) {
var files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'];
var ranks = ['10', '9', '8', '7', '6', '5', '4', '3', '2', '1'];
return files[col] + ranks[row];
}
function pieceToNotation(pieceType) {
var notationMap = {
'king': 'K',
'adventurousKing': 'AK',
'queen': 'V',
'rook': 'R',
'bishop': 'F',
'knight': 'N',
'warElephant': 'E',
'siegeTower': 'W',
'minister': 'F',
'royalGuard': 'RG',
'giraffe': 'G',
'bull': 'T',
'camel': 'C',
'lion': 'L',
'shahsade': 'K',
'pawn': 'PPP',
'pawnOfTheWarMachine': 'WP',
'camelPawn': 'CP',
'ministersPawn': 'FP',
'pawnOfTheElephant': 'EP',
'kingsPawn': 'KP',
'viziersPawn': 'VP',
'giraffePawn': 'GP',
'knightPawn': 'NP',
'rookPawn': 'RP',
'pawnOfTheLeader': 'BP',
'guardsPawn': 'RGP',
'pawnOfTheBull': 'TP',
'lionsPawn': 'LP',
'pawnsPawn': 'PP'
};
return notationMap[pieceType] || '';
}
function isValidSquare(row, col) {
// Special case: only allow column 0 at row 1 (left of a2)
if (col === 0 && row !== 1) {
return false;
}
// Special case: only allow column 12 at row 8 (right of k9)
if (col === 12 && row !== 8) {
return false;
}
return row >= 0 && row < BOARD_HEIGHT && col >= 0 && col < BOARD_WIDTH;
}
function getPieceAt(row, col) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].boardRow === row && pieces[i].boardCol === col) {
return pieces[i];
}
}
return null;
}
function createBoard() {
for (var row = 0; row < BOARD_HEIGHT; row++) {
boardSquares[row] = [];
for (var col = 0; col < BOARD_WIDTH; col++) {
// Only create square at column 0, row 1 (left of a2)
if (col === 0 && row !== 1) {
boardSquares[row][col] = null;
continue;
}
// Only create square at column 12, row 8 (right of k9)
if (col === 12 && row !== 8) {
boardSquares[row][col] = null;
continue;
}
// Special case: Black Palace at column 0, row 1 (left of a2)
// Special case: White Palace at column 12, row 8 (right of k9)
var squareAsset;
if (col === 0 && row === 1) {
squareAsset = 'blackPalace';
} else if (col === 12 && row === 8) {
squareAsset = 'whitePalace';
} else {
var isLight = (row + col) % 2 === 0;
squareAsset = isLight ? 'lightSquare' : 'darkSquare';
}
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
boardSquares[row][col] = square;
}
}
}
function createPieces() {
// Create pieces for both players
var pieceSetup = [
// White pieces (bottom)
{
type: 'rook',
color: 0,
row: 8,
col: 1
}, {
type: 'knight',
color: 0,
row: 8,
col: 2
}, {
type: 'warElephant',
color: 0,
row: 9,
col: 1
}, {
type: 'warElephant',
color: 0,
row: 9,
col: 11
}, {
type: 'bishop',
color: 0,
row: 8,
col: 3
}, {
type: 'minister',
color: 0,
row: 8,
col: 5
}, {
type: 'king',
color: 0,
row: 8,
col: 6
}, {
type: 'bishop',
color: 0,
row: 8,
col: 9
}, {
type: 'siegeTower',
color: 0,
row: 9,
col: 7
}, {
type: 'siegeTower',
color: 0,
row: 9,
col: 5
}, {
type: 'queen',
color: 0,
row: 8,
col: 7
}, {
type: 'giraffe',
color: 0,
row: 8,
col: 4
}, {
type: 'giraffe',
color: 0,
row: 8,
col: 8
}, {
type: 'knight',
color: 0,
row: 8,
col: 10
}, {
type: 'rook',
color: 0,
row: 8,
col: 11
},
// White royal guards
{
type: 'royalGuard',
color: 0,
row: 9,
col: 6
},
// White lions
{
type: 'lion',
color: 0,
row: 9,
col: 2
}, {
type: 'lion',
color: 0,
row: 9,
col: 10
},
// White camels
{
type: 'camel',
color: 0,
row: 9,
col: 3
}, {
type: 'camel',
color: 0,
row: 9,
col: 9
},
// White bulls
{
type: 'bull',
color: 0,
row: 9,
col: 4
}, {
type: 'bull',
color: 0,
row: 9,
col: 8
},
// Black pieces (top)
{
type: 'rook',
color: 1,
row: 1,
col: 1
}, {
type: 'knight',
color: 1,
row: 1,
col: 2
}, {
type: 'warElephant',
color: 1,
row: 0,
col: 1
}, {
type: 'warElephant',
color: 1,
row: 0,
col: 11
}, {
type: 'bishop',
color: 1,
row: 1,
col: 3
}, {
type: 'minister',
color: 1,
row: 1,
col: 7
}, {
type: 'king',
color: 1,
row: 1,
col: 6
}, {
type: 'bishop',
color: 1,
row: 1,
col: 9
}, {
type: 'siegeTower',
color: 1,
row: 0,
col: 7
}, {
type: 'siegeTower',
color: 1,
row: 0,
col: 5
}, {
type: 'queen',
color: 1,
row: 1,
col: 5
}, {
type: 'giraffe',
color: 1,
row: 1,
col: 4
}, {
type: 'giraffe',
color: 1,
row: 1,
col: 8
}, {
type: 'knight',
color: 1,
row: 1,
col: 10
}, {
type: 'rook',
color: 1,
row: 1,
col: 11
},
// Black royal guards
{
type: 'royalGuard',
color: 1,
row: 0,
col: 6
},
// Black lions
{
type: 'lion',
color: 1,
row: 0,
col: 2
}, {
type: 'lion',
color: 1,
row: 0,
col: 10
},
// Black camels
{
type: 'camel',
color: 1,
row: 0,
col: 3
}, {
type: 'camel',
color: 1,
row: 0,
col: 9
},
// Black bulls
{
type: 'bull',
color: 1,
row: 0,
col: 4
}, {
type: 'bull',
color: 1,
row: 0,
col: 8
}];
// Add Pawn of the War Machine for each side
pieceSetup.push({
type: 'pawnOfTheWarMachine',
color: 0,
row: 7,
col: 2
}); // White Pawn of the War Machine
pieceSetup.push({
type: 'pawnOfTheWarMachine',
color: 1,
row: 2,
col: 10
}); // Black Pawn of the War Machine
// Add Camel Pawn for each side
pieceSetup.push({
type: 'camelPawn',
color: 0,
row: 7,
col: 3
}); // White Camel Pawn
pieceSetup.push({
type: 'camelPawn',
color: 1,
row: 2,
col: 9
}); // Black Camel Pawn
// Add Pawn of the Elephant for each side
pieceSetup.push({
type: 'pawnOfTheElephant',
color: 0,
row: 7,
col: 4
}); // White Pawn of the Elephant
pieceSetup.push({
type: 'pawnOfTheElephant',
color: 1,
row: 2,
col: 8
}); // Black Pawn of the Elephant
// Add Minister's Pawn for each side
pieceSetup.push({
type: 'ministersPawn',
color: 0,
row: 7,
col: 5
}); // White Minister's Pawn
pieceSetup.push({
type: 'ministersPawn',
color: 1,
row: 2,
col: 7
}); // Black Minister's Pawn
// Add King's Pawn for each side
pieceSetup.push({
type: 'kingsPawn',
color: 0,
row: 7,
col: 6
}); // White King's Pawn
pieceSetup.push({
type: 'kingsPawn',
color: 1,
row: 2,
col: 6
}); // Black King's Pawn
// Add Vizier's Pawn for each side
pieceSetup.push({
type: 'viziersPawn',
color: 0,
row: 7,
col: 7
}); // White Vizier's Pawn
pieceSetup.push({
type: 'viziersPawn',
color: 1,
row: 2,
col: 5
}); // Black Vizier's Pawn
// Add Giraffe Pawn for each side
pieceSetup.push({
type: 'giraffePawn',
color: 0,
row: 7,
col: 8
}); // White Giraffe Pawn
pieceSetup.push({
type: 'giraffePawn',
color: 1,
row: 2,
col: 4
}); // Black Giraffe Pawn
// Add Knight Pawn for each side
pieceSetup.push({
type: 'knightPawn',
color: 0,
row: 7,
col: 10
}); // White Knight Pawn
pieceSetup.push({
type: 'knightPawn',
color: 1,
row: 2,
col: 2
}); // Black Knight Pawn
// Add Rook Pawn for each side
pieceSetup.push({
type: 'rookPawn',
color: 0,
row: 7,
col: 11
}); // White Rook Pawn
pieceSetup.push({
type: 'rookPawn',
color: 1,
row: 2,
col: 1
}); // Black Rook Pawn
// Add Pawn of the Leader for each side
pieceSetup.push({
type: 'pawnOfTheLeader',
color: 0,
row: 7,
col: 9
}); // White Pawn of the Leader
pieceSetup.push({
type: 'pawnOfTheLeader',
color: 1,
row: 2,
col: 3
}); // Black Pawn of the Leader
// Add Guard's Pawn for each side - in front of the King's Pawn
pieceSetup.push({
type: 'guardsPawn',
color: 0,
row: 6,
col: 6
}); // White Guard's Pawn (in front of White King's Pawn)
pieceSetup.push({
type: 'guardsPawn',
color: 1,
row: 3,
col: 6
}); // Black Guard's Pawn (in front of Black King's Pawn)
// Add Pawn of the Bull for each side - in front of the Pawn of the Leader
pieceSetup.push({
type: 'pawnOfTheBull',
color: 0,
row: 6,
col: 9
}); // White Pawn of the Bull (in front of White Pawn of the Leader)
pieceSetup.push({
type: 'pawnOfTheBull',
color: 1,
row: 3,
col: 3
}); // Black Pawn of the Bull (in front of Black Pawn of the Leader)
// Add Lion's Pawn for each side - in front of the Camel's Pawn
pieceSetup.push({
type: 'lionsPawn',
color: 0,
row: 6,
col: 3
}); // White Lion's Pawn (in front of White Camel Pawn)
pieceSetup.push({
type: 'lionsPawn',
color: 1,
row: 3,
col: 9
}); // Black Lion's Pawn (in front of Black Camel Pawn)
// Add regular pawn for each side
pieceSetup.push({
type: 'pawn',
color: 0,
row: 7,
col: 1
}); // White Pawn
pieceSetup.push({
type: 'pawn',
color: 1,
row: 2,
col: 11
}); // Black Pawn
for (var i = 0; i < pieceSetup.length; i++) {
var setup = pieceSetup[i];
var piece = game.addChild(new ChessPiece(setup.type, setup.color, setup.row, setup.col));
var pos = getBoardPosition(setup.row, setup.col);
piece.x = pos.x;
piece.y = pos.y;
pieces.push(piece);
}
}
function clearHighlights() {
for (var i = 0; i < highlightedSquares.length; i++) {
highlightedSquares[i].destroy();
}
highlightedSquares = [];
}
function clearSwapHighlights() {
for (var i = 0; i < swapHighlights.length; i++) {
swapHighlights[i].destroy();
}
swapHighlights = [];
}
function highlightMoves(moves) {
clearHighlights();
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
var assetName = move.isCastling ? 'castlingSquare' : 'highlightSquare';
var highlight = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
}));
var pos = getBoardPosition(move.row, move.col);
highlight.x = pos.x;
highlight.y = pos.y;
highlightedSquares.push(highlight);
}
}
function highlightSwappablePieces(swappablePieces) {
clearSwapHighlights();
for (var i = 0; i < swappablePieces.length; i++) {
var piece = swappablePieces[i];
var highlight = game.addChild(LK.getAsset('swapSquare', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
}));
var pos = getBoardPosition(piece.boardRow, piece.boardCol);
highlight.x = pos.x;
highlight.y = pos.y;
swapHighlights.push(highlight);
}
}
function selectPiece(piece) {
if (selectedPiece) {
selectedPiece.removeChild(selectedPiece.selectionHighlight);
selectedPiece.selectionHighlight = null;
}
selectedPiece = piece;
if (piece) {
piece.selectionHighlight = piece.addChild(LK.getAsset('selectedSquare', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
}));
var validMoves = piece.getValidMoves();
highlightMoves(validMoves);
// If selecting a Shah (king), also highlight swappable pieces
if (piece.pieceType === 'king') {
var swappablePieces = getSwappablePieces(piece);
highlightSwappablePieces(swappablePieces);
}
} else {
clearHighlights();
clearSwapHighlights();
}
}
function generateMoveNotation(piece, targetRow, targetCol, moveData, capturedPieces) {
var notation = '';
var pieceNotation = pieceToNotation(piece.pieceType);
var targetSquare = positionToAlgebraic(targetRow, targetCol);
// Handle special moves
if (moveData && moveData.isCastling) {
notation = targetCol > piece.boardCol ? 'O-O' : 'O-O-O';
} else {
// Add piece notation
notation += pieceNotation;
// Add capture notation
if (capturedPieces.length > 0) {
if (pieceNotation === '') {
// For pawn captures, add the file of origin
notation += positionToAlgebraic(piece.boardRow, piece.boardCol).charAt(0);
}
notation += 'x';
}
// Add destination square
notation += targetSquare;
}
return notation;
}
function makeMove(piece, targetRow, targetCol, moveData) {
var originalRow = piece.boardRow;
var originalCol = piece.boardCol;
// Check palace entry restrictions
if (isPalaceSquare(targetRow, targetCol)) {
if (!canEnterPalace(piece, targetRow, targetCol)) {
return; // Invalid move, cannot enter palace
}
}
var capturedPiece = null;
var capturedPieces = [];
// Handle special moves
if (moveData && moveData.isCastling) {
// Move the rook for castling
var rook = getPieceAt(originalRow, moveData.rookFromCol);
if (rook) {
rook.moveTo(originalRow, moveData.rookToCol);
}
} else if (moveData && moveData.isEnPassant) {
// Capture the pawn for en passant
capturedPiece = getPieceAt(moveData.captureRow, moveData.captureCol);
if (capturedPiece) {
capturedPieces.push(capturedPiece);
}
} else if (moveData && moveData.capturesInPath) {
// Handle siegeTower path captures
for (var k = 0; k < moveData.capturesInPath.length; k++) {
var capturePos = moveData.capturesInPath[k];
var pathPiece = getPieceAt(capturePos.row, capturePos.col);
if (pathPiece) {
capturedPieces.push(pathPiece);
}
}
} else {
capturedPiece = getPieceAt(targetRow, targetCol);
if (capturedPiece) {
capturedPieces.push(capturedPiece);
// Apply saray capture flag if needed
if (isSaray(targetRow, targetCol)) {
handleSarayCapture(piece, targetRow, targetCol);
}
}
}
// Remove all captured pieces
for (var k = 0; k < capturedPieces.length; k++) {
var capPiece = capturedPieces[k];
var index = pieces.indexOf(capPiece);
if (index > -1) {
pieces.splice(index, 1);
}
capPiece.destroy();
}
if (capturedPieces.length > 0) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
// Store move for en passant detection
lastMove = {
piece: piece,
fromRow: originalRow,
fromCol: originalCol,
toRow: targetRow,
toCol: targetCol
};
piece.moveTo(targetRow, targetCol);
// Track movement for pawn's pawn
if (piece.pieceType === 'pawnsPawn') {
for (var mc = 0; mc < pawnsPawnMovementCount.length; mc++) {
if (pawnsPawnMovementCount[mc].piece === piece) {
pawnsPawnMovementCount[mc].moves++;
break;
}
}
}
// Check for vizier promotion
if (piece.pieceType === 'queen' && !piece.isPromoted) {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
piece.isPromoted = true;
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
}
}
// Check for minister promotion
if (piece.pieceType === 'minister' && !piece.isPromoted) {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
piece.isPromoted = true;
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x9932CC, 1000); // Flash purple
}
}
// Check for Pawn of the War Machine promotion
if (piece.pieceType === 'pawnOfTheWarMachine') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into siege tower
piece.pieceType = 'siegeTower';
// Change texture to siege tower
piece.removeChildAt(0); // Remove old texture
var siegeTowerGraphics = piece.attachAsset('siegeTower', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
siegeTowerGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x00FF00, 1000); // Flash green
}
}
// Check for Camel Pawn promotion
if (piece.pieceType === 'camelPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into camel
piece.pieceType = 'camel';
// Change texture to camel
piece.removeChildAt(0); // Remove old texture
var camelGraphics = piece.attachAsset('camel', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
camelGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFFF00, 1000); // Flash yellow
}
}
// Check for Minister's Pawn promotion
if (piece.pieceType === 'ministersPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into promoted minister
piece.pieceType = 'minister';
piece.isPromoted = true;
// Change texture to minister
piece.removeChildAt(0); // Remove old texture
var ministerGraphics = piece.attachAsset('minister', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
ministerGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x9932CC, 1000); // Flash purple
}
}
// Check for Pawn of the Elephant promotion
if (piece.pieceType === 'pawnOfTheElephant') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into war elephant
piece.pieceType = 'warElephant';
// Change texture to war elephant
piece.removeChildAt(0); // Remove old texture
var warElephantGraphics = piece.attachAsset('warElephant', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
warElephantGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x8B4513, 1000); // Flash brown
}
}
// Check for King's Pawn promotion
if (piece.pieceType === 'kingsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into shahsade
piece.pieceType = 'shahsade';
// Change texture to shahsade
piece.removeChildAt(0); // Remove old texture
var shahsadeGraphics = piece.attachAsset('shahsade', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
shahsadeGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFF4500, 1000); // Flash orange red
}
}
// Check for Vizier's Pawn promotion
if (piece.pieceType === 'viziersPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into promoted vizier
piece.pieceType = 'queen';
piece.isPromoted = true;
// Change texture to queen
piece.removeChildAt(0); // Remove old texture
var queenGraphics = piece.attachAsset('queen', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
queenGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
}
}
// Check for Giraffe Pawn promotion
if (piece.pieceType === 'giraffePawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into giraffe
piece.pieceType = 'giraffe';
// Change texture to giraffe
piece.removeChildAt(0); // Remove old texture
var giraffeGraphics = piece.attachAsset('giraffe', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
giraffeGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFA500, 1000); // Flash orange
}
}
// Check for Knight Pawn promotion
if (piece.pieceType === 'knightPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into knight
piece.pieceType = 'knight';
// Change texture to knight
piece.removeChildAt(0); // Remove old texture
var knightGraphics = piece.attachAsset('knight', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
knightGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x00CED1, 1000); // Flash dark turquoise
}
}
// Check for Rook Pawn promotion
if (piece.pieceType === 'rookPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into rook
piece.pieceType = 'rook';
// Change texture to rook
piece.removeChildAt(0); // Remove old texture
var rookGraphics = piece.attachAsset('rook', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
rookGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x0000FF, 1000); // Flash blue
}
}
// Check for Pawn of the Leader promotion
if (piece.pieceType === 'pawnOfTheLeader') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into bishop
piece.pieceType = 'bishop';
// Change texture to bishop
piece.removeChildAt(0); // Remove old texture
var bishopGraphics = piece.attachAsset('bishop', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
bishopGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x800080, 1000); // Flash purple
}
}
// Check for Guard's Pawn promotion
if (piece.pieceType === 'guardsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into royalGuard
piece.pieceType = 'royalGuard';
// Change texture to royalGuard
piece.removeChildAt(0); // Remove old texture
var royalGuardGraphics = piece.attachAsset('royalGuard', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
royalGuardGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xCD5C5C, 1000); // Flash indian red
}
}
// Check for Pawn of the Bull promotion
if (piece.pieceType === 'pawnOfTheBull') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into bull
piece.pieceType = 'bull';
// Change texture to bull
piece.removeChildAt(0); // Remove old texture
var bullGraphics = piece.attachAsset('bull', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
bullGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xB8860B, 1000); // Flash dark goldenrod
}
}
// Check for Lion's Pawn promotion
if (piece.pieceType === 'lionsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into lion
piece.pieceType = 'lion';
// Change texture to lion
piece.removeChildAt(0); // Remove old texture
var lionGraphics = piece.attachAsset('lion', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
lionGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
}
}
// Check for regular pawn promotion to pawn's pawn
if (piece.pieceType === 'pawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into pawn's pawn
piece.pieceType = 'pawnsPawn';
// Initialize movement count for this pawn's pawn
pawnsPawnMovementCount.push({
piece: piece,
moves: 0
});
// Change texture to pawn's pawn
piece.removeChildAt(0); // Remove old texture
var pawnsPawnGraphics = piece.attachAsset('pawnsPawn', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
pawnsPawnGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFF69B4, 1000); // Flash hot pink
}
}
// Check for Pawn's Pawn promotion
if (piece.pieceType === 'pawnsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Find movement count for this piece
var moveCount = 0;
for (var mc = 0; mc < pawnsPawnMovementCount.length; mc++) {
if (pawnsPawnMovementCount[mc].piece === piece) {
moveCount = pawnsPawnMovementCount[mc].moves;
break;
}
}
// Must move at least 1 square to be promoted
if (moveCount >= 1) {
// Transform into adventurous king
piece.pieceType = 'adventurousKing';
// Change texture to adventurous king
piece.removeChildAt(0); // Remove old texture
var adventurousKingGraphics = piece.attachAsset('adventurousKing', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
adventurousKingGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x00FFFF, 1000); // Flash cyan
}
}
}
// Check for adventurous king promotion to king in own saray
if (piece.pieceType === 'adventurousKing') {
promoteAdventurousKingToKing(targetRow, targetCol);
}
// Check for shahsade victory condition - capturing king with shahsade is immediate win
if (piece.pieceType === 'shahsade' && capturedPieces.length > 0) {
for (var k = 0; k < capturedPieces.length; k++) {
if (capturedPieces[k].pieceType === 'king') {
// Shahsade captured the king - immediate victory
LK.setScore(1);
LK.showYouWin();
return;
}
}
}
// Generate and record move notation
var notation = generateMoveNotation(piece, targetRow, targetCol, moveData, capturedPieces);
var moveNumber = Math.floor(moveHistory.length / 2) + 1;
var colorPrefix = currentPlayer === 0 ? moveNumber + '.' : '';
moveHistory.push(colorPrefix + notation);
// Update move history display only if visible
if (moveHistoryVisible) {
var displayText = 'Move History:\n';
for (var i = 0; i < moveHistory.length; i++) {
if (i % 2 === 0) {
displayText += moveHistory[i] + ' ';
} else {
displayText += moveHistory[i] + '\n';
}
}
moveHistoryText.setText(displayText);
}
// Check for draw offer if piece entered opponent's palace
if (isPalaceSquare(targetRow, targetCol)) {
if (offerDraw(piece)) {
return; // Game ended in draw
}
}
currentPlayer = 1 - currentPlayer;
selectPiece(null);
// Check for victory conditions
checkGameEnd();
}
function isSquareAttacked(row, col, byColor) {
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor !== byColor) {
continue;
}
var moves = piece.getRawMoves();
for (var j = 0; j < moves.length; j++) {
if (moves[j].row === row && moves[j].col === col) {
return true;
}
}
}
return false;
}
function findKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceType === 'king' && pieces[i].pieceColor === color) {
return pieces[i];
}
}
return null;
}
function isInCheck(color) {
var king = findKing(color);
if (!king) {
return false;
}
// Check if the attacking player has a shahsade
var attackingColor = 1 - color;
var hasShahsade = false;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === attackingColor && pieces[i].pieceType === 'shahsade') {
hasShahsade = true;
break;
}
}
// If attacker has shahsade and it hasn't been promoted, they cannot check the king
if (hasShahsade && !shahsadePromoted[attackingColor]) {
return false;
}
return isSquareAttacked(king.boardRow, king.boardCol, 1 - color);
}
function isValidMoveConsideringCheck(piece, targetRow, targetCol) {
// Simulate the move
var originalRow = piece.boardRow;
var originalCol = piece.boardCol;
var capturedPiece = getPieceAt(targetRow, targetCol);
var capturedIndex = -1;
if (capturedPiece) {
capturedIndex = pieces.indexOf(capturedPiece);
pieces.splice(capturedIndex, 1);
}
piece.boardRow = targetRow;
piece.boardCol = targetCol;
// Convert adventurous king if needed after simulated move
convertAdventurousKingIfNeeded(piece.pieceColor);
var stillInCheck = isInCheck(piece.pieceColor);
var hasImmunity = hasImmunityPiece(piece.pieceColor);
// Restore the position
piece.boardRow = originalRow;
piece.boardCol = originalCol;
if (capturedPiece && capturedIndex > -1) {
pieces.splice(capturedIndex, 0, capturedPiece);
}
// Player can ignore check only if they have immunity piece
if (hasImmunity) return true;
// Otherwise check must be resolved
return !stillInCheck;
}
function hasValidMoves(color) {
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor !== color) {
continue;
}
var moves = piece.getRawMoves();
for (var j = 0; j < moves.length; j++) {
if (isValidMoveConsideringCheck(piece, moves[j].row, moves[j].col)) {
return true;
}
}
}
return false;
}
function isSideLMove(fromRow, fromCol, toRow, toCol) {
var rowDiff = Math.abs(toRow - fromRow);
var colDiff = Math.abs(toCol - fromCol);
// Yan L: 2 yatay (col), 1 dikey (row)
if (rowDiff === 1 && colDiff === 2) {
return true; // Bu hareket yan L hareketidir
}
return false;
}
function hasRealKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color && pieces[i].pieceType === 'king') {
return true;
}
}
return false;
}
function hasAdventurousKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color && pieces[i].pieceType === 'adventurousKing') {
return true;
}
}
return false;
}
function hasShahsade(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color && pieces[i].pieceType === 'shahsade') {
return true;
}
}
return false;
}
function convertAdventurousKingIfNeeded(color) {
if (hasRealKing(color) || hasShahsade(color)) {
return;
}
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === color && p.pieceType === 'adventurousKing') {
p.pieceType = 'king';
// Change texture to king
p.removeChildAt(0); // Remove old texture
var kingGraphics = p.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (p.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
// Visual feedback for conversion
LK.effects.flashObject(p, 0xFFD700, 1000); // Flash gold
console.log('AdventurousKing converted to KING at (' + r + ',' + c + ')');
return;
}
}
}
}
function checkGameEnd() {
// Convert adventurous kings if needed for both players
convertAdventurousKingIfNeeded(0);
convertAdventurousKingIfNeeded(1);
var whiteKing = findKing(0);
var blackKing = findKing(1);
// Check if a player who brought shahsade into play loses their king
if (!whiteKing) {
// White king is captured - check if white has shahsade
var whiteShahsade = null;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === 0 && pieces[i].pieceType === 'shahsade') {
whiteShahsade = pieces[i];
break;
}
}
if (whiteShahsade) {
// Promote shahsade to new shah (king)
whiteShahsade.pieceType = 'king';
// Mark that white's shahsade has been promoted
shahsadePromoted[0] = true;
// Change texture to king
whiteShahsade.removeChildAt(0); // Remove old texture
var kingGraphics = whiteShahsade.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (whiteShahsade.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(whiteShahsade, 0xFFD700, 1000); // Flash gold
// Check if player is in checkmate after promotion
if (isInCheck(0) && !hasValidMoves(0)) {
LK.setScore(1);
LK.showGameOver();
return;
}
// Game continues, don't end
return;
} else {
LK.setScore(1);
LK.showGameOver();
return;
}
}
if (!blackKing) {
// Black king is captured - check if black has shahsade
var blackShahsade = null;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === 1 && pieces[i].pieceType === 'shahsade') {
blackShahsade = pieces[i];
break;
}
}
if (blackShahsade) {
// Promote shahsade to new shah (king)
blackShahsade.pieceType = 'king';
// Mark that black's shahsade has been promoted
shahsadePromoted[1] = true;
// Change texture to king
blackShahsade.removeChildAt(0); // Remove old texture
var kingGraphics = blackShahsade.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (blackShahsade.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(blackShahsade, 0xFFD700, 1000); // Flash gold
// Check if player is in checkmate after promotion
if (isInCheck(1) && !hasValidMoves(1)) {
LK.setScore(1);
LK.showGameOver();
return;
}
// Game continues, don't end
return;
} else {
LK.setScore(1);
LK.showGameOver();
return;
}
}
var inCheck = isInCheck(currentPlayer);
var hasValid = hasValidMoves(currentPlayer);
// Check for checkmate using new function that respects check privileges
if (isCheckmate(currentPlayer)) {
// Checkmate
LK.setScore(1);
LK.showGameOver();
} else if (!hasValid) {
// Stalemate
LK.setScore(0);
LK.showGameOver();
}
}
function initializeGame() {
createBoard();
createPieces();
gameStarted = true;
}
// Player turn indicator
var turnText = new Text2('White to move', {
size: 80,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
// Move history display
var moveHistory = [];
var moveHistoryVisible = false;
var moveHistoryTab = new Text2('Move History', {
size: 50,
fill: 0xFFFFFF
});
moveHistoryTab.anchor.set(0, 0);
moveHistoryTab.x = 50;
moveHistoryTab.y = 150;
game.addChild(moveHistoryTab);
var moveHistoryText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
moveHistoryText.anchor.set(0, 0);
moveHistoryText.x = 50;
moveHistoryText.y = 200;
moveHistoryText.visible = false;
game.addChild(moveHistoryText);
game.down = function (x, y, obj) {
if (!gameStarted) {
return;
}
// Check if move history tab was clicked
if (x >= moveHistoryTab.x && x <= moveHistoryTab.x + 300 && y >= moveHistoryTab.y && y <= moveHistoryTab.y + 60) {
moveHistoryVisible = !moveHistoryVisible;
moveHistoryText.visible = moveHistoryVisible;
if (moveHistoryVisible) {
// Update display when showing
var displayText = 'Move History:\n';
for (var i = 0; i < moveHistory.length; i++) {
if (i % 2 === 0) {
displayText += moveHistory[i] + ' ';
} else {
displayText += moveHistory[i] + '\n';
}
}
moveHistoryText.setText(displayText);
}
return;
}
var coords = getBoardCoordinates(x, y);
if (!isValidSquare(coords.row, coords.col)) {
return;
}
var clickedPiece = getPieceAt(coords.row, coords.col);
if (selectedPiece) {
var validMoves = selectedPiece.getValidMoves();
var isValidMove = false;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === coords.row && validMoves[i].col === coords.col) {
isValidMove = true;
break;
}
}
if (isValidMove) {
var moveData = null;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === coords.row && validMoves[i].col === coords.col) {
moveData = validMoves[i];
break;
}
}
makeMove(selectedPiece, coords.row, coords.col, moveData);
return;
}
}
if (clickedPiece && clickedPiece.pieceColor === currentPlayer) {
// Check if this is a Shah position swap
if (selectedPiece && selectedPiece.pieceType === 'king' && clickedPiece !== selectedPiece) {
var swappablePieces = getSwappablePieces(selectedPiece);
var canSwap = false;
for (var i = 0; i < swappablePieces.length; i++) {
if (swappablePieces[i] === clickedPiece) {
canSwap = true;
break;
}
}
if (canSwap) {
performPositionSwap(selectedPiece, clickedPiece);
return;
}
}
selectPiece(clickedPiece);
} else {
selectPiece(null);
}
};
game.update = function () {
if (!gameStarted) {
initializeGame();
}
// Try teleporting pawn of pawns for current player
tryTeleportPawnOfPawns(currentPlayer);
// Enforce saray exit if required
enforceSarayExit(currentPlayer);
var playerText = currentPlayer === 0 ? 'White to move' : 'Black to move';
if (isInCheck(currentPlayer)) {
playerText += ' (Check!)';
}
turnText.setText(playerText);
};
function enforceSarayExit(playerColor) {
// Check if player is mated due to saray exit requirement
if (checkForcedSarayExitOrMate(playerColor)) {
// Player is mated - end game
LK.setScore(1);
LK.showGameOver();
return;
}
for (var row = 0; row < BOARD_HEIGHT; row++) {
for (var col = 0; col < BOARD_WIDTH; col++) {
var p = getPieceAt(row, col);
if (p && p.pieceColor === playerColor && mustMoveFirst(p, row, col)) {
// Highlight the piece that must exit saray
if (selectedPiece !== p) {
selectPiece(p);
}
return;
}
}
}
}
// List of types the pawn_of_pawns cannot threaten
var EXCLUDED_TYPES = ['camelPawn', 'giraffePawn', 'guardsPawn', 'kingsPawn', 'knightPawn', 'lionsPawn', 'ministersPawn', 'pawnOfTheBull', 'pawnOfTheElephant', 'pawnOfTheLeader', 'pawn', 'pawnOfTheWarMachine', 'viziersPawn', 'king'];
function tryTeleportPawnOfPawns(color) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceType === 'pawnsPawn' && p.pieceColor === color && !p.hasTeleported) {
for (var tr = 0; tr < BOARD_HEIGHT; tr++) {
for (var tc = 0; tc < BOARD_WIDTH; tc++) {
if (!isValidSquare(tr, tc)) continue; // Skip invalid squares
if (getPieceAt(tr, tc)) continue; // Square must be empty
var threats = countValidThreats(tr, tc, color);
var blocksImmobilizedEnemy = threatensBlockedEnemy(tr, tc, color);
if (threats >= 2 || blocksImmobilizedEnemy) {
// Teleport the pawn of pawns
p.boardRow = tr;
p.boardCol = tc;
p.hasTeleported = true;
var pos = getBoardPosition(tr, tc);
tween(p, {
x: pos.x,
y: pos.y
}, {
duration: 300
});
console.log('Pawn of Pawns TELEPORTED to (' + tr + ',' + tc + ')');
return;
}
}
}
}
}
}
}
function countValidThreats(row, col, color) {
var count = 0;
var dirs = [[-1, -1], [-1, 1], [1, -1], [1, 1]]; // Diagonals
for (var d = 0; d < dirs.length; d++) {
var dir = dirs[d];
var r = row + dir[0];
var c = col + dir[1];
if (isValidSquare(r, c)) {
var enemy = getPieceAt(r, c);
if (enemy && enemy.pieceColor !== color && EXCLUDED_TYPES.indexOf(enemy.pieceType) === -1) {
// Additional check: pawn of pawns cannot teleport to threaten the king
if (enemy.pieceType === 'king') {
return 0; // Prevent teleportation if it would threaten the king
}
count++;
}
}
}
return count;
}
function threatensBlockedEnemy(row, col, color) {
var dirs = [[-1, -1], [-1, 1], [1, -1], [1, 1]]; // Diagonals
for (var d = 0; d < dirs.length; d++) {
var dir = dirs[d];
var r = row + dir[0];
var c = col + dir[1];
if (isValidSquare(r, c)) {
var enemy = getPieceAt(r, c);
if (enemy && enemy.pieceColor !== color && EXCLUDED_TYPES.indexOf(enemy.pieceType) === -1) {
// Additional check: pawn of pawns cannot teleport to threaten the king
if (enemy.pieceType === 'king') {
return false; // Prevent teleportation if it would threaten the king
}
if (!hasLegalMovesForPiece(enemy, r, c)) {
return true;
}
}
}
}
return false;
}
function hasLegalMovesForPiece(piece, row, col) {
var moves = piece.getRawMoves();
for (var i = 0; i < moves.length; i++) {
if (isValidMoveConsideringCheck(piece, moves[i].row, moves[i].col)) {
return true;
}
}
return false;
}
function hasImmunityPiece(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color) {
if (pieces[i].pieceType === 'adventurousKing' || pieces[i].pieceType === 'shahsade') {
return true;
}
}
}
return false;
}
function isPieceUnderThreat(piece) {
return isSquareAttacked(piece.boardRow, piece.boardCol, 1 - piece.pieceColor);
}
function hasCheckPrivilege(color) {
return hasAdventurousKing(color) || hasShahsade(color);
}
function getSwappablePieces(shahPiece) {
var swappablePieces = [];
// Check if Shah position swap has already been used
if (shahPositionSwapUsed[shahPiece.pieceColor]) {
return swappablePieces;
}
// Shah must not be under threat
if (isPieceUnderThreat(shahPiece)) {
return swappablePieces;
}
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
// Must be same color but not the Shah itself
if (piece.pieceColor === shahPiece.pieceColor && piece !== shahPiece) {
// Piece must not be under threat
if (!isPieceUnderThreat(piece)) {
swappablePieces.push(piece);
}
}
}
return swappablePieces;
}
function isCheckmate(color) {
if (hasImmunityPiece(color)) {
console.log(color === 0 ? 'White' : 'Black' + ' has immunity — checkmate ignored.');
return false;
}
return isInCheck(color) && !hasValidMoves(color);
}
function isPalaceSquare(row, col) {
return row === 1 && col === 0 || row === 8 && col === 12;
}
function isSaray(row, col) {
return row === 1 && col === 0 || row === 8 && col === 12;
}
function isInOwnSaray(piece, row, col) {
return piece.pieceColor === 0 && row === 8 && col === 12 || piece.pieceColor === 1 && row === 1 && col === 0;
}
function promoteAdventurousKingToKing(row, col) {
var p = getPieceAt(row, col);
if (p && p.pieceType === 'adventurousKing') {
var inSaray = isInOwnSaray(p, row, col);
p.pieceType = 'king';
p.mustExitSaray = inSaray;
// Change texture to king
p.removeChildAt(0); // Remove old texture
var kingGraphics = p.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (p.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
if (inSaray) {
console.log('AdventurousKing promoted to King inside own saray — must exit next turn.');
// Visual feedback for promotion in saray
LK.effects.flashObject(p, 0xFFD700, 1000); // Flash gold
} else {
console.log('AdventurousKing promoted to King outside saray — no exit required.');
// Visual feedback for promotion outside saray
LK.effects.flashObject(p, 0x00FF00, 1000); // Flash green
}
}
}
function mustExitSarayThisTurn(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === playerColor && p.mustExitSaray && isInOwnSaray(p, r, c)) {
return true;
}
}
}
return false;
}
function canEscapeFromSaray(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === playerColor && p.mustExitSaray && isInOwnSaray(p, r, c)) {
// Check 8 surrounding squares (like king movement)
var dr = [-1, -1, -1, 0, 1, 1, 1, 0];
var dc = [-1, 0, 1, 1, 1, 0, -1, -1];
for (var i = 0; i < 8; i++) {
var nr = r + dr[i];
var nc = c + dc[i];
if (isValidSquare(nr, nc) && !getPieceAt(nr, nc)) {
return true; // Found an empty escape square
}
}
return false; // Surrounded, no escape
}
}
}
return true; // No forced exit kings found
}
function checkForcedSarayExitOrMate(playerColor) {
if (mustExitSarayThisTurn(playerColor)) {
if (canEscapeFromSaray(playerColor)) {
console.log((playerColor === 0 ? 'White' : 'Black') + ' must move King out of saray this turn.');
return false; // Not mated, but must move
} else {
console.log((playerColor === 0 ? 'White' : 'Black') + ' cannot escape saray — checkmate.');
return true; // Mated
}
}
return false; // No forced exits pending
}
function handleSarayCapture(attacker, row, col) {
if (isSaray(row, col)) {
attacker.mustExitSaray = true;
}
}
function mustMoveFirst(piece, row, col) {
if (!piece || !piece.mustExitSaray) return false;
if (isSaray(row, col)) {
return true; // still inside → must move out
} else {
piece.mustExitSaray = false; // already out → clear flag
return false;
}
}
function getPlayerPalace(color) {
return color === 1 ? {
row: 1,
col: 0
} : {
row: 8,
col: 12
};
}
function isOpponentPalace(row, col, color) {
if (color === 0) {
return row === 1 && col === 0; // White player, black palace
} else {
return row === 8 && col === 12; // Black player, white palace
}
}
function canEnterPalace(piece, targetRow, targetCol) {
// Coordinates of palace squares
var blackPalace = {
row: 1,
col: 0
}; // Black Palace location
var whitePalace = {
row: 8,
col: 12
}; // White Palace location
if (!piece) return false;
var type = piece.pieceType;
var color = piece.pieceColor === 0 ? 'white' : 'black';
var isWhiteSaray = targetRow === whitePalace.row && targetCol === whitePalace.col;
var isBlackSaray = targetRow === blackPalace.row && targetCol === blackPalace.col;
var target = getPieceAt(targetRow, targetCol);
var isCapturing = target && target.pieceColor !== piece.pieceColor;
// Normal allowed entry
if (type === 'adventurousKing' || isBlackSaray && color === 'white' && (type === 'king' || type === 'shahsade') || isWhiteSaray && color === 'black' && (type === 'king' || type === 'shahsade')) {
return true;
}
// Special rule: capture king/shahsade/adventurousKing in saray if under threat
if (isCapturing && target && (target.pieceType === 'king' || target.pieceType === 'shahsade' || target.pieceType === 'adventurousKing') && isSaray(targetRow, targetCol)) {
return true;
}
return !isSaray(targetRow, targetCol); // deny entry to saray unless allowed
}
function isPieceInPalace(piece) {
return isPalaceSquare(piece.boardRow, piece.boardCol);
}
var drawOfferPending = false;
var drawOfferPiece = null;
function offerDraw(piece) {
// Check if piece is in opponent's palace
if (isOpponentPalace(piece.boardRow, piece.boardCol, piece.pieceColor)) {
var playerName = piece.pieceColor === 0 ? 'White' : 'Black';
drawOfferPending = true;
drawOfferPiece = piece;
// Create draw offer dialog
showDrawOfferDialog(playerName);
return true; // Game is paused for draw offer
}
return false;
}
function showDrawOfferDialog(playerName) {
// Create dialog background
var dialogBg = game.addChild(LK.getAsset('darkSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 3,
alpha: 0.9
}));
dialogBg.x = 2048 / 2;
dialogBg.y = 2732 / 2;
// Create dialog text
var dialogText = new Text2(playerName + ' offers a draw.\nDo you accept?', {
size: 60,
fill: 0xFFFFFF
});
dialogText.anchor.set(0.5, 0.5);
dialogText.x = 2048 / 2;
dialogText.y = 2732 / 2 - 100;
game.addChild(dialogText);
// Create Yes button
var yesButton = game.addChild(LK.getAsset('lightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
}));
yesButton.x = 2048 / 2 - 200;
yesButton.y = 2732 / 2 + 100;
var yesText = new Text2('Yes', {
size: 50,
fill: 0x000000
});
yesText.anchor.set(0.5, 0.5);
yesText.x = yesButton.x;
yesText.y = yesButton.y;
game.addChild(yesText);
// Create No button
var noButton = game.addChild(LK.getAsset('lightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
}));
noButton.x = 2048 / 2 + 200;
noButton.y = 2732 / 2 + 100;
var noText = new Text2('No', {
size: 50,
fill: 0x000000
});
noText.anchor.set(0.5, 0.5);
noText.x = noButton.x;
noText.y = noButton.y;
game.addChild(noText);
// Add click handlers
yesButton.down = function () {
// Accept draw
LK.setScore(0); // Draw
LK.showGameOver();
};
noButton.down = function () {
// Decline draw - clean up dialog and continue game
dialogBg.destroy();
dialogText.destroy();
yesButton.destroy();
yesText.destroy();
noButton.destroy();
noText.destroy();
drawOfferPending = false;
drawOfferPiece = null;
};
}
function performPositionSwap(shahPiece, targetPiece) {
// Store original positions
var shahRow = shahPiece.boardRow;
var shahCol = shahPiece.boardCol;
var targetRow = targetPiece.boardRow;
var targetCol = targetPiece.boardCol;
// Swap positions
shahPiece.boardRow = targetRow;
shahPiece.boardCol = targetCol;
targetPiece.boardRow = shahRow;
targetPiece.boardCol = shahCol;
// Animate the swap
var shahPos = getBoardPosition(targetRow, targetCol);
var targetPos = getBoardPosition(shahRow, shahCol);
tween(shahPiece, {
x: shahPos.x,
y: shahPos.y
}, {
duration: 300
});
tween(targetPiece, {
x: targetPos.x,
y: targetPos.y
}, {
duration: 300
});
// Mark that position swap has been used
shahPositionSwapUsed[shahPiece.pieceColor] = true;
// Record position swap in move history
var notation = 'K-' + pieceToNotation(targetPiece.pieceType) + ' swap';
var moveNumber = Math.floor(moveHistory.length / 2) + 1;
var colorPrefix = currentPlayer === 0 ? moveNumber + '.' : '';
moveHistory.push(colorPrefix + notation);
// Update move history display only if visible
if (moveHistoryVisible) {
var displayText = 'Move History:\n';
for (var i = 0; i < moveHistory.length; i++) {
if (i % 2 === 0) {
displayText += moveHistory[i] + ' ';
} else {
displayText += moveHistory[i] + '\n';
}
}
moveHistoryText.setText(displayText);
}
// Play move sound
LK.getSound('move').play();
// Change turn
currentPlayer = 1 - currentPlayer;
selectPiece(null);
clearSwapHighlights();
} ===================================================================
--- original.js
+++ change.js
@@ -15,11 +15,8 @@
self.hasMoved = false;
self.isPromoted = false; // Track permanent promotion status for vizier
self.hasTeleported = false; // Track if pawn's pawn has used teleportation
self.mustExitSaray = false; // Track if piece must exit saray after capture
- self.isKingLike = function () {
- return self.pieceType === 'king' || self.pieceType === 'adventurousKing';
- };
var pieceGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
@@ -2996,23 +2993,8 @@
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFF69B4, 1000); // Flash hot pink
}
}
- // Check for adventurous king transformation when entering own saray
- if (piece.pieceType === 'adventurousKing' && isInOwnSaray(piece, targetRow, targetCol)) {
- transformToKing(piece, targetRow, targetCol);
- // Change texture to king
- piece.removeChildAt(0); // Remove old texture
- var kingGraphics = piece.attachAsset('king', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- if (piece.pieceColor === 1) {
- kingGraphics.tint = 0x333333;
- }
- // Visual feedback for transformation
- LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
- }
// Check for Pawn's Pawn promotion
if (piece.pieceType === 'pawnsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
@@ -3041,8 +3023,12 @@
LK.effects.flashObject(piece, 0x00FFFF, 1000); // Flash cyan
}
}
}
+ // Check for adventurous king promotion to king in own saray
+ if (piece.pieceType === 'adventurousKing') {
+ promoteAdventurousKingToKing(targetRow, targetCol);
+ }
// Check for shahsade victory condition - capturing king with shahsade is immediate win
if (piece.pieceType === 'shahsade' && capturedPieces.length > 0) {
for (var k = 0; k < capturedPieces.length; k++) {
if (capturedPieces[k].pieceType === 'king') {
@@ -3309,14 +3295,8 @@
LK.showGameOver();
return;
}
}
- // Check for forced saray exit checkmate
- if (checkForcedExitOrMate(currentPlayer)) {
- LK.setScore(1);
- LK.showGameOver();
- return;
- }
var inCheck = isInCheck(currentPlayer);
var hasValid = hasValidMoves(currentPlayer);
// Check for checkmate using new function that respects check privileges
if (isCheckmate(currentPlayer)) {
@@ -3444,8 +3424,15 @@
}
turnText.setText(playerText);
};
function enforceSarayExit(playerColor) {
+ // Check if player is mated due to saray exit requirement
+ if (checkForcedSarayExitOrMate(playerColor)) {
+ // Player is mated - end game
+ LK.setScore(1);
+ LK.showGameOver();
+ return;
+ }
for (var row = 0; row < BOARD_HEIGHT; row++) {
for (var col = 0; col < BOARD_WIDTH; col++) {
var p = getPieceAt(row, col);
if (p && p.pieceColor === playerColor && mustMoveFirst(p, row, col)) {
@@ -3595,60 +3582,77 @@
}
function isInOwnSaray(piece, row, col) {
return piece.pieceColor === 0 && row === 8 && col === 12 || piece.pieceColor === 1 && row === 1 && col === 0;
}
-function transformToKing(piece, row, col) {
- if (piece.pieceType === 'adventurousKing' && isInOwnSaray(piece, row, col)) {
- piece.pieceType = 'king';
- piece.mustExitSaray = true;
- console.log('AdventurousKing became King in saray — must exit next turn.');
- } else if (piece.pieceType === 'adventurousKing') {
- piece.pieceType = 'king'; // no restriction if not in saray
+function promoteAdventurousKingToKing(row, col) {
+ var p = getPieceAt(row, col);
+ if (p && p.pieceType === 'adventurousKing') {
+ var inSaray = isInOwnSaray(p, row, col);
+ p.pieceType = 'king';
+ p.mustExitSaray = inSaray;
+ // Change texture to king
+ p.removeChildAt(0); // Remove old texture
+ var kingGraphics = p.attachAsset('king', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ if (p.pieceColor === 1) {
+ kingGraphics.tint = 0x333333;
+ }
+ if (inSaray) {
+ console.log('AdventurousKing promoted to King inside own saray — must exit next turn.');
+ // Visual feedback for promotion in saray
+ LK.effects.flashObject(p, 0xFFD700, 1000); // Flash gold
+ } else {
+ console.log('AdventurousKing promoted to King outside saray — no exit required.');
+ // Visual feedback for promotion outside saray
+ LK.effects.flashObject(p, 0x00FF00, 1000); // Flash green
+ }
}
}
-function mustExitSaray(color) {
+function mustExitSarayThisTurn(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
- if (p && p.pieceColor === color && p.mustExitSaray && isInOwnSaray(p, r, c)) {
+ if (p && p.pieceColor === playerColor && p.mustExitSaray && isInOwnSaray(p, r, c)) {
return true;
}
}
}
return false;
}
-function hasEscapeFromSaray(color) {
+function canEscapeFromSaray(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
- if (p && p.pieceColor === color && p.mustExitSaray && isInOwnSaray(p, r, c)) {
- // Try all 8 surrounding squares (king movement)
+ if (p && p.pieceColor === playerColor && p.mustExitSaray && isInOwnSaray(p, r, c)) {
+ // Check 8 surrounding squares (like king movement)
var dr = [-1, -1, -1, 0, 1, 1, 1, 0];
var dc = [-1, 0, 1, 1, 1, 0, -1, -1];
for (var i = 0; i < 8; i++) {
var nr = r + dr[i];
var nc = c + dc[i];
if (isValidSquare(nr, nc) && !getPieceAt(nr, nc)) {
- return true; // can escape
+ return true; // Found an empty escape square
}
}
- return false; // surrounded
+ return false; // Surrounded, no escape
}
}
}
- return true; // no forced piece found → no problem
+ return true; // No forced exit kings found
}
-function checkForcedExitOrMate(playerColor) {
- if (mustExitSaray(playerColor)) {
- if (hasEscapeFromSaray(playerColor)) {
- console.log((playerColor === 0 ? 'White' : 'Black') + ' must move king out of saray this turn.');
- return false; // not mated yet
+function checkForcedSarayExitOrMate(playerColor) {
+ if (mustExitSarayThisTurn(playerColor)) {
+ if (canEscapeFromSaray(playerColor)) {
+ console.log((playerColor === 0 ? 'White' : 'Black') + ' must move King out of saray this turn.');
+ return false; // Not mated, but must move
} else {
- console.log((playerColor === 0 ? 'White' : 'Black') + ' has no way to exit saray — checkmated.');
- return true; // checkmate due to forced exit failure
+ console.log((playerColor === 0 ? 'White' : 'Black') + ' cannot escape saray — checkmate.');
+ return true; // Mated
}
}
- return false;
+ return false; // No forced exits pending
}
function handleSarayCapture(attacker, row, col) {
if (isSaray(row, col)) {
attacker.mustExitSaray = true;