User prompt
Use separate assets for the returning queens and the princess stone belonging to their side and give the queen her old asset back.
User prompt
Add the queen and the knights back to the game, only 2 princess pieces with their own special assets. And these will replace a queen and a knight.
User prompt
Add a separate asset for the princess chess piece
User prompt
Add a new piece called the princess instead of a queen and a knight. This piece can move two squares straight if it wishes. It cannot jump over pieces or move diagonally. However, instead of moving, it can eliminate two enemy pieces it selects nearby. When it does this, it doesn't move. Instead, it clicks on two selected pieces.
User prompt
The snake can also checkmate the stone or prevent it from escaping.
User prompt
If we trap the opponent's king in a way that he cannot escape, the opponent's king will lose 2 lives and only the piece that is currently in check will be destroyed.
User prompt
Only the snake should not play with the chess piece, only the snake should play more often like the other pieces.
User prompt
The opponent AI also plays the snake chess piece according to the same rules as the player and uses the snake actively like the queen and uses the queen less and more timidly but for solid compression and checkmate.
User prompt
Examine all codes, chess pieces, rules, and the AI opponent. Correct any errors. Adjust the game according to the rules of chess. Arrange for the non-pawn pieces to be randomly swapped with each other on each new play (opponent AI and player). For example, swap the black rook with the black snake, or the white rook with the white knight.
User prompt
The king can also be protected from other pieces by capturing the piece that threatens the king. One of the primary ways to protect the king is to capture the piece threatening the king rather than fleeing. However, in this case, fleeing, intervening, or capturing the opposing piece can be a solution.
User prompt
The piece that controls the king can also be captured
User prompt
Only the piece that is checking is lost, and 2 lives are lost. While the piece that is checking is lost, nothing happens to the other pieces, and only the pieces that are checking the opponent are lost. By the way, when the name of the winning side is mentioned, if the winning side is black, it should say "Black side won."
User prompt
Now when the king cant escape, 2 lives are lost instead of 2 and all the pieces that are in check are lost. By the way, fix the bug where the player's hearts are black.
User prompt
Examine the game and codes and make an adjustment for possible bugs and detect and fix bugs.
User prompt
If the king can capture the piece that is being held in check, the place is not missed, and the game does this automatically. However, if the king's position is disrupted during the king's progress, the king will escape. If none of these conditions are met, and the side being held in check can neither escape nor capture the piece that is being held in check, then a cant escape occurs, and the game starts over.
User prompt
Eğer şahı şah durumuna düşüren taş, şahın onu alabileceği bir karede ise oyun bitmez; şah otomatik olarak o taşı alır.
User prompt
If the piece that prevents the king from escaping is on a square where the king can capture it, the game automatically captures that piece and the game continues with 1 damage to the side where the king escaped.
User prompt
The opposing AI steals the snake piece according to the rules. When it sees the opponent's snake piece and queen in play, it attempts to capture it with pieces other than its own queen and snake. It attempts to poison the snake piece by moving it closer to the pieces protecting the king.
User prompt
Yılan taşı 3. hamlesini yapmak istediği kareye yapabilir
User prompt
Piyonlar diğer taşların üzerinden atlayamaz. Bir oyuncu bir yılan taşı oynadığında, üç hamle boyunca başka bir taşı hareket ettiremez, ardından hamle rakibine geçer. Kısacası, üç hamle tek hamle sayılır. Her iki yılan taşı da ayrı taşlardır ve bir yılan taşı oynandığında, yalnızca o anda oynanan taşın üç kez hareket ettirilmesi gerekir.
User prompt
Reduce the snake stone's movements to 1 square and prevent the snake stone from jumping over other stones to make it blockable
User prompt
When playing the snake chess piece, AI plays three moves. After AI plays three snake moves, the player's turn passes. When a new game begins, a one-second win screen appears. The winning team's name is displayed as "Win." This is how the new game begins. It's a sort of winning side-by-side and transition screen. Four lives must be exhausted for this screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The opponent's AI should now withdraw its pieces when necessary. It shouldn't use its non-pawn pieces immediately. It should wait for the opponent's mistake to use its non-pawn pieces. However, it should sometimes use its knight and bishop to force the opponent to play. When taking the cards it can take in the game, it should analyze the next two moves and make moves based on the possible outcomes to pressure its opponent. If it sees a situation where it can checkmate its opponent, it should checkmate them. Sometimes, it will try to force a cant escape by pressuring its opponent.
User prompt
If poisoning occurs, the right of play immediately passes to the opponent and the snake's movements are reduced to 2 squares, only 2 squares. This piece poisons the opponent's pieces it leaves behind. It has no effect on its own pieces or the pieces around it. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
After the snake piece makes its third move, movement rights pass to the opponent. The player plays the snake three moves, after which movement rights pass to the opponent. The snake piece cannot be moved consecutively. At least one move must be waited. Three moves by the snake piece count as one move. On its first move, the snake piece moves 3 squares in any direction, on its second move, it moves 3 squares diagonally in any direction, and on its final move, it moves 3 squares straight ahead, after which movement rights pass to the opponent. Both the player and the opponent can use this piece in this manner. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* 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;
self.row = row;
self.col = col;
self.hasMoved = false;
self.poisonTurns = 0;
self.poisonEffect = null;
self.poisonCounterText = null;
self.snakeMovesThisTurn = 0;
self.maxSnakeMoves = 3;
self.snakeLastMoveDirection = null; // Track last move direction for straight ahead requirement
self.snakeOnCooldown = false; // Prevent consecutive snake usage
var assetName = color + type.charAt(0).toUpperCase() + type.slice(1);
var pieceGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.updatePosition = function (animate) {
var targetX = boardStartX + self.col * squareSize + squareSize / 2;
var targetY = boardStartY + self.row * squareSize + squareSize / 2;
if (animate && (self.x !== targetX || self.y !== targetY)) {
tween(self, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
} else {
self.x = targetX;
self.y = targetY;
}
};
self.canMoveTo = function (targetRow, targetCol) {
// Poisoned pieces cannot move
if (self.poisonTurns > 0) {
return false;
}
if (targetRow < 0 || targetRow > 7 || targetCol < 0 || targetCol > 15) {
return false;
}
var targetPiece = getPieceAt(targetRow, targetCol);
if (targetPiece && targetPiece.pieceColor === self.pieceColor) {
return false;
}
switch (self.pieceType) {
case 'pawn':
return self.canPawnMove(targetRow, targetCol);
case 'rook':
return self.canRookMove(targetRow, targetCol);
case 'knight':
return self.canKnightMove(targetRow, targetCol);
case 'bishop':
return self.canBishopMove(targetRow, targetCol);
case 'queen':
return self.canQueenMove(targetRow, targetCol);
case 'king':
return self.canKingMove(targetRow, targetCol);
case 'snake':
return self.canSnakeMove(targetRow, targetCol);
}
return false;
};
self.canPawnMove = function (targetRow, targetCol) {
var direction = self.pieceColor === 'white' ? -1 : 1;
var startRow = self.pieceColor === 'white' ? 6 : 1;
if (targetCol === self.col) {
if (targetRow === self.row + direction && !getPieceAt(targetRow, targetCol)) {
return true;
}
if (self.row === startRow && targetRow === self.row + 2 * direction && !getPieceAt(targetRow, targetCol)) {
// Check if path is clear for 2-square pawn move
return isPathClear(self.row, self.col, targetRow, targetCol);
}
} else if (Math.abs(targetCol - self.col) === 1 && targetRow === self.row + direction) {
var targetPiece = getPieceAt(targetRow, targetCol);
if (targetPiece && targetPiece.pieceColor !== self.pieceColor) {
return true;
}
}
return false;
};
self.canRookMove = function (targetRow, targetCol) {
if (self.row !== targetRow && self.col !== targetCol) {
return false;
}
return isPathClear(self.row, self.col, targetRow, targetCol);
};
self.canKnightMove = function (targetRow, targetCol) {
var rowDiff = Math.abs(targetRow - self.row);
var colDiff = Math.abs(targetCol - self.col);
return rowDiff === 2 && colDiff === 1 || rowDiff === 1 && colDiff === 2;
};
self.canBishopMove = function (targetRow, targetCol) {
if (Math.abs(targetRow - self.row) !== Math.abs(targetCol - self.col)) {
return false;
}
return isPathClear(self.row, self.col, targetRow, targetCol);
};
self.canQueenMove = function (targetRow, targetCol) {
return self.canRookMove(targetRow, targetCol) || self.canBishopMove(targetRow, targetCol);
};
self.canKingMove = function (targetRow, targetCol) {
var rowDiff = Math.abs(targetRow - self.row);
var colDiff = Math.abs(targetCol - self.col);
if (rowDiff <= 1 && colDiff <= 1) {
// Check if king would be safe at target position
return isKingSafeAt(self, targetRow, targetCol);
}
return false;
};
self.applyPoison = function (turns) {
self.poisonTurns = turns;
self.showPoisonEffect();
};
self.showPoisonEffect = function () {
if (self.poisonEffect) {
self.poisonEffect.destroy();
self.poisonEffect = null;
}
if (self.poisonCounterText) {
self.poisonCounterText.destroy();
self.poisonCounterText = null;
}
if (self.poisonTurns > 0) {
self.poisonEffect = self.attachAsset('poisonEffect', {
anchorX: 0.5,
anchorY: 0.5
});
self.poisonEffect.x = 30;
self.poisonEffect.y = -30;
self.poisonCounterText = new Text2(self.poisonTurns.toString(), {
size: 24,
fill: 0xFFFFFF
});
self.poisonCounterText.anchor.set(0.5, 0.5);
self.poisonCounterText.x = 30;
self.poisonCounterText.y = -30;
self.addChild(self.poisonCounterText);
// Tint piece red when poisoned
tween(pieceGraphics, {
tint: 0xff6666
}, {
duration: 300,
easing: tween.easeOut
});
} else {
// Remove red tint when poison wears off
tween(pieceGraphics, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
}
};
self.reducePoisonTurns = function () {
if (self.poisonTurns > 0) {
self.poisonTurns--;
self.showPoisonEffect();
}
};
self.canSnakeMove = function (targetRow, targetCol) {
// Check if snake is on cooldown
if (self.snakeOnCooldown) {
return false;
}
var rowDiff = targetRow - self.row;
var colDiff = targetCol - self.col;
var distance = Math.max(Math.abs(rowDiff), Math.abs(colDiff));
// Check if poisoning will occur
var willPoison = false;
var poisonPositions = [{
row: self.row - 1,
col: self.col - 1
}, {
row: self.row - 1,
col: self.col
}, {
row: self.row - 1,
col: self.col + 1
}, {
row: self.row,
col: self.col - 1
}, {
row: self.row,
col: self.col + 1
}, {
row: self.row + 1,
col: self.col - 1
}, {
row: self.row + 1,
col: self.col
}, {
row: self.row + 1,
col: self.col + 1
}];
for (var i = 0; i < poisonPositions.length; i++) {
var pos = poisonPositions[i];
if (pos.row >= 0 && pos.row < 8 && pos.col >= 0 && pos.col < 16) {
var pieceAtPos = getPieceAt(pos.row, pos.col);
if (pieceAtPos && pieceAtPos.pieceColor !== self.pieceColor) {
willPoison = true;
break;
}
}
}
// Snake can only move exactly 1 square
if (distance !== 1) {
return false;
}
// Check if the path is clear (no jumping over pieces)
if (!isPathClear(self.row, self.col, targetRow, targetCol)) {
return false;
}
// First move: 1 square in any direction (straight lines only)
if (self.snakeMovesThisTurn === 0) {
// Must be straight line movement (horizontal, vertical, or diagonal)
if (rowDiff === 0 || colDiff === 0 || Math.abs(rowDiff) === Math.abs(colDiff)) {
return true;
}
return false;
}
// Second move: 1 square diagonally in any direction
if (self.snakeMovesThisTurn === 1) {
// Must be diagonal movement
if (Math.abs(rowDiff) === Math.abs(colDiff) && Math.abs(rowDiff) === 1) {
return true;
}
return false;
}
// Third move: 1 square in any direction - only if not poisoning
if (self.snakeMovesThisTurn === 2 && !willPoison) {
// Can move to any adjacent square (any direction)
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2D1810
});
/****
* Game Code
****/
// Game dimensions and board setup
// Chess board squares
// White pieces
// Black pieces
// Sound effects
var squareSize = 128;
var boardStartX = (2048 - squareSize * 16) / 2;
var boardStartY = (2732 - squareSize * 8) / 2 + 100;
// Game state
var currentPlayer = 'white';
var selectedPiece = null;
var validMoves = [];
var pieces = [];
var gameBoard = [];
var highlightSquares = [];
var validMoveSquares = [];
var escapeSquares = [];
var kingSquare = null;
var blackKingSquare = null;
var dragNode = null;
var gameState = 'playing'; // playing, check, checkmate, stalemate
var whiteKingLives = 4;
var blackKingLives = 4;
var currentSnakePiece = null;
var snakeMovesRemaining = 0;
var activeSnakePiece = null; // Track which specific snake is currently active
// Initialize empty board
for (var row = 0; row < 8; row++) {
gameBoard[row] = [];
for (var col = 0; col < 16; col++) {
gameBoard[row][col] = null;
}
}
// Create visual board
var boardContainer = game.addChild(new Container());
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 16; col++) {
var isLight = (row + col) % 2 === 0;
var square = LK.getAsset(isLight ? 'lightSquare' : 'darkSquare', {
anchorX: 0,
anchorY: 0
});
square.x = boardStartX + col * squareSize;
square.y = boardStartY + row * squareSize;
boardContainer.addChild(square);
}
}
// Initialize pieces with traditional chess layout - 2 snakes replace specific rook and knight positions
var pieceSetup = [['rook', 'knight', 'bishop', 'queen', 'king', 'queen', 'bishop', 'knight', 'rook', 'rook', 'knight', 'bishop', 'queen', 'snake', 'snake', 'rook'], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn']];
// Create black pieces
for (var row = 0; row < 2; row++) {
for (var col = 0; col < 16; col++) {
var piece = new ChessPiece(pieceSetup[row][col], 'black', row, col);
pieces.push(piece);
gameBoard[row][col] = piece;
game.addChild(piece);
piece.updatePosition();
}
}
// Create white pieces
for (var row = 6; row < 8; row++) {
for (var col = 0; col < 16; col++) {
var pieceType = row === 6 ? 'pawn' : pieceSetup[7 - row][col];
var piece = new ChessPiece(pieceType, 'white', row, col);
pieces.push(piece);
gameBoard[row][col] = piece;
game.addChild(piece);
piece.updatePosition();
}
}
// Initialize king square
updateKingSquare();
// UI Elements
var turnText = new Text2('Your Turn', {
size: 80,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
// Lives display - positioned behind chess pieces on the board
var whiteLivesContainer = new Container();
game.addChild(whiteLivesContainer);
var blackLivesContainer = new Container();
game.addChild(blackLivesContainer);
var whiteLivesText = new Text2('Your Lives: 4', {
size: 40,
fill: 0xFFFFFF
});
whiteLivesText.anchor.set(0.5, 0.5);
whiteLivesText.x = boardStartX + 16 * squareSize / 2;
whiteLivesText.y = boardStartY + 8 * squareSize + 50;
whiteLivesContainer.addChild(whiteLivesText);
var blackLivesText = new Text2('Enemy Lives: 4', {
size: 40,
fill: 0xFF0000
});
blackLivesText.anchor.set(0.5, 0.5);
blackLivesText.x = boardStartX + 16 * squareSize / 2;
blackLivesText.y = boardStartY - 50;
blackLivesContainer.addChild(blackLivesText);
// Lives visual indicators
var whiteLivesHearts = [];
var blackLivesHearts = [];
for (var i = 0; i < 4; i++) {
var whiteHeart = LK.getAsset('playerLifeBar', {
anchorX: 0.5,
anchorY: 0.5
});
whiteHeart.x = boardStartX + 16 * squareSize / 2 - 75 + i * 50;
whiteHeart.y = boardStartY + 8 * squareSize + 100;
whiteLivesContainer.addChild(whiteHeart);
whiteLivesHearts.push(whiteHeart);
var blackHeart = LK.getAsset('aiLifeBar', {
anchorX: 0.5,
anchorY: 0.5
});
blackHeart.x = boardStartX + 16 * squareSize / 2 - 75 + i * 50;
blackHeart.y = boardStartY - 100;
blackLivesContainer.addChild(blackHeart);
blackLivesHearts.push(blackHeart);
}
function getPieceAt(row, col) {
if (row < 0 || row > 7 || col < 0 || col > 15) {
return null;
}
return gameBoard[row][col];
}
function isPathClear(fromRow, fromCol, toRow, toCol) {
var rowStep = toRow > fromRow ? 1 : toRow < fromRow ? -1 : 0;
var colStep = toCol > fromCol ? 1 : toCol < fromCol ? -1 : 0;
var currentRow = fromRow + rowStep;
var currentCol = fromCol + colStep;
while (currentRow !== toRow || currentCol !== toCol) {
if (getPieceAt(currentRow, currentCol)) {
return false;
}
currentRow += rowStep;
currentCol += colStep;
}
return true;
}
function getSquareFromPosition(x, y) {
var col = Math.floor((x - boardStartX) / squareSize);
var row = Math.floor((y - boardStartY) / squareSize);
if (row >= 0 && row < 8 && col >= 0 && col < 16) {
return {
row: row,
col: col
};
}
return null;
}
function clearHighlights() {
for (var i = 0; i < highlightSquares.length; i++) {
highlightSquares[i].destroy();
}
highlightSquares = [];
for (var i = 0; i < validMoveSquares.length; i++) {
validMoveSquares[i].destroy();
}
validMoveSquares = [];
for (var i = 0; i < escapeSquares.length; i++) {
escapeSquares[i].destroy();
}
escapeSquares = [];
}
function updateKingSquare() {
// Remove existing king squares
if (kingSquare) {
kingSquare.destroy();
kingSquare = null;
}
if (blackKingSquare) {
blackKingSquare.destroy();
blackKingSquare = null;
}
// Find the white king and create purple square under it
var whiteKing = findKing('white');
if (whiteKing) {
kingSquare = LK.getAsset('kingSquare', {
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
kingSquare.x = boardStartX + whiteKing.col * squareSize;
kingSquare.y = boardStartY + whiteKing.row * squareSize;
boardContainer.addChild(kingSquare);
}
// Find the black king and create purple square under it
var blackKing = findKing('black');
if (blackKing) {
blackKingSquare = LK.getAsset('kingSquare', {
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
blackKingSquare.x = boardStartX + blackKing.col * squareSize;
blackKingSquare.y = boardStartY + blackKing.row * squareSize;
boardContainer.addChild(blackKingSquare);
}
}
function highlightSquare(row, col, color) {
var assetName = 'validMoveSquare';
if (color === 'blue') {
assetName = 'highlightSquare';
} else if (color === 'yellow') {
assetName = 'escapeSquare';
}
var highlight = LK.getAsset(assetName, {
anchorX: 0,
anchorY: 0,
alpha: 0.7
});
highlight.x = boardStartX + col * squareSize;
highlight.y = boardStartY + row * squareSize;
game.addChild(highlight);
if (color === 'blue') {
highlightSquares.push(highlight);
} else if (color === 'yellow') {
escapeSquares.push(highlight);
} else {
validMoveSquares.push(highlight);
}
}
function showValidMoves(piece) {
validMoves = [];
var playerInCheck = isInCheck(piece.pieceColor);
// Always highlight the selected piece position in blue first
highlightSquare(piece.row, piece.col, 'blue');
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 16; col++) {
if (piece.canMoveTo(row, col)) {
// If in check, only allow moves that escape check
if (playerInCheck) {
if (canEscapeCheck(piece, row, col)) {
validMoves.push({
row: row,
col: col
});
// Highlight escape move in yellow when in check
highlightSquare(row, col, 'yellow');
}
} else {
validMoves.push({
row: row,
col: col
});
highlightSquare(row, col, 'green');
}
}
}
}
}
function movePiece(piece, newRow, newCol) {
var capturedPiece = getPieceAt(newRow, newCol);
var isCapture = capturedPiece !== null;
// Remove piece from old position
gameBoard[piece.row][piece.col] = null;
// Remove captured piece
if (capturedPiece) {
// Handle king capture - check if king can counter-capture
if (capturedPiece.pieceType === 'king') {
// Check if captured king can counter-capture the attacking piece
var canCounterCapture = capturedPiece.canMoveTo(piece.row, piece.col) && isKingSafeAt(capturedPiece, piece.row, piece.col);
if (canCounterCapture) {
// Auto counter-capture: king takes the attacking piece
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] === piece) {
pieces[i].destroy();
pieces.splice(i, 1);
break;
}
}
// Move king to attacking piece position
gameBoard[capturedPiece.row][capturedPiece.col] = null;
capturedPiece.row = piece.row;
capturedPiece.col = piece.col;
gameBoard[capturedPiece.row][capturedPiece.col] = capturedPiece;
capturedPiece.updatePosition(true);
updateKingSquare();
LK.getSound('capture').play();
// Apply 1 damage to the king's side for escaping
if (capturedPiece.pieceColor === 'white') {
whiteKingLives--;
activateAbility('white', whiteKingLives);
} else {
blackKingLives--;
activateAbility('black', blackKingLives);
}
updateLivesDisplay();
turnText.setText(capturedPiece.pieceColor.charAt(0).toUpperCase() + capturedPiece.pieceColor.slice(1) + ' King Counter-Attacks! 1 Life Lost for Escaping!');
return;
} else {
// Reduce king lives
if (capturedPiece.pieceColor === 'white') {
whiteKingLives--;
activateAbility('white', whiteKingLives);
} else {
blackKingLives--;
activateAbility('black', blackKingLives);
}
// Update lives display
updateLivesDisplay();
// Check if king is out of lives (restart game when lives reach 0)
if (whiteKingLives <= 0 || blackKingLives <= 0) {
var winner = whiteKingLives <= 0 ? 'Black' : 'White';
turnText.setText(winner + ' Wins! King Defeated!');
LK.setTimeout(function () {
restartGame();
}, 2000);
return;
}
}
} else {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] === capturedPiece) {
pieces[i].destroy();
pieces.splice(i, 1);
break;
}
}
}
}
// Move piece to new position
piece.row = newRow;
piece.col = newCol;
piece.hasMoved = true;
gameBoard[newRow][newCol] = piece;
piece.updatePosition(true);
// Update king square if a king moved
if (piece.pieceType === 'king') {
updateKingSquare();
}
// Play sound
if (isCapture) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
// Check for pawn promotion
if (piece.pieceType === 'pawn' && (newRow === 0 || newRow === 7)) {
promotePawn(piece);
}
// Handle snake multi-move mechanics
if (piece.pieceType === 'snake') {
// Set this snake as the active snake if starting its turn
if (piece.snakeMovesThisTurn === 0) {
activeSnakePiece = piece;
var rowDiff = newRow - piece.row;
var colDiff = newCol - piece.col;
piece.snakeLastMoveDirection = {
row: rowDiff === 0 ? 0 : rowDiff > 0 ? 1 : -1,
col: colDiff === 0 ? 0 : colDiff > 0 ? 1 : -1
};
}
// Check if poisoning will occur before the move
var willPoison = false;
var poisonPositions = [{
row: piece.row - 1,
col: piece.col - 1
}, {
row: piece.row - 1,
col: piece.col
}, {
row: piece.row - 1,
col: piece.col + 1
}, {
row: piece.row,
col: piece.col - 1
}, {
row: piece.row,
col: piece.col + 1
}, {
row: piece.row + 1,
col: piece.col - 1
}, {
row: piece.row + 1,
col: piece.col
}, {
row: piece.row + 1,
col: piece.col + 1
}];
for (var i = 0; i < poisonPositions.length; i++) {
var pos = poisonPositions[i];
if (pos.row >= 0 && pos.row < 8 && pos.col >= 0 && pos.col < 16) {
var pieceAtPos = getPieceAt(pos.row, pos.col);
if (pieceAtPos && pieceAtPos.pieceColor !== piece.pieceColor) {
willPoison = true;
break;
}
}
}
piece.snakeMovesThisTurn++;
var maxMoves = willPoison ? 2 : piece.maxSnakeMoves;
snakeMovesRemaining = maxMoves - piece.snakeMovesThisTurn;
currentSnakePiece = piece;
// Apply poison to pieces behind the snake
applyPoisonBehindSnake(piece, piece.row, piece.col);
// If poisoning occurred, immediately switch turns after 2 moves
if (willPoison) {
// Snake completed poisoning moves - put on cooldown and reset
piece.snakeMovesThisTurn = 0;
piece.snakeOnCooldown = true;
piece.snakeLastMoveDirection = null;
currentSnakePiece = null;
snakeMovesRemaining = 0;
activeSnakePiece = null; // Reset active snake
turnText.setText(piece.pieceColor.charAt(0).toUpperCase() + piece.pieceColor.slice(1) + ' Snake poisoned enemies! Turn passes to opponent.');
} else {
// Snake eats piece at each stop - already handled by capture logic above
// If snake has more moves, don't switch turns yet
if (piece.snakeMovesThisTurn < maxMoves) {
var moveNames = ['', 'First', 'Second', 'Third'];
turnText.setText(piece.pieceColor.charAt(0).toUpperCase() + piece.pieceColor.slice(1) + ' Snake - ' + moveNames[piece.snakeMovesThisTurn] + ' move complete, ' + snakeMovesRemaining + ' moves remaining');
// Clear current selection to allow new move
clearHighlights();
selectedPiece = null;
return; // Don't switch turns
}
// Snake completed all 3 moves - put on cooldown and reset
piece.snakeMovesThisTurn = 0;
piece.snakeOnCooldown = true;
piece.snakeLastMoveDirection = null;
currentSnakePiece = null;
snakeMovesRemaining = 0;
activeSnakePiece = null; // Reset active snake
}
}
// Switch turns
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
// Reduce poison turns and remove snake cooldown for all pieces of the new current player
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === currentPlayer) {
pieces[i].reducePoisonTurns();
// Remove snake cooldown when it becomes this player's turn
if (pieces[i].pieceType === 'snake') {
pieces[i].snakeOnCooldown = false;
}
}
}
turnText.setText(currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1) + '\'s Turn');
// Check for check/checkmate
if (isInCheck(currentPlayer)) {
// In must-escape situations, first check if king and other pieces can counter-capture
var king = findKing(currentPlayer);
var threateningPiece = findThreateningPiece(king);
var canAutoCapture = false;
var capturingPiece = null;
var captureRow = -1;
var captureCol = -1;
// First check if king can capture the threatening piece
if (king && threateningPiece && king.canMoveTo(threateningPiece.row, threateningPiece.col) && isKingSafeAt(king, threateningPiece.row, threateningPiece.col)) {
canAutoCapture = true;
capturingPiece = king;
captureRow = threateningPiece.row;
captureCol = threateningPiece.col;
} else if (threateningPiece) {
// Check if any other piece can capture the threatening piece
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === currentPlayer && piece.canMoveTo(threateningPiece.row, threateningPiece.col)) {
// Test if this capture would get the king out of check
if (canEscapeCheck(piece, threateningPiece.row, threateningPiece.col)) {
canAutoCapture = true;
capturingPiece = piece;
captureRow = threateningPiece.row;
captureCol = threateningPiece.col;
break;
}
}
}
}
// If counter-capture is possible, execute it
if (canAutoCapture) {
// Auto-capture: piece takes the threatening piece
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] === threateningPiece) {
pieces[i].destroy();
pieces.splice(i, 1);
break;
}
}
// Move capturing piece to threatening piece position
gameBoard[capturingPiece.row][capturingPiece.col] = null;
capturingPiece.row = captureRow;
capturingPiece.col = captureCol;
gameBoard[capturingPiece.row][capturingPiece.col] = capturingPiece;
capturingPiece.updatePosition(true);
if (capturingPiece.pieceType === 'king') {
updateKingSquare();
// Apply 1 damage to king's side for escaping by counter-capture
if (capturingPiece.pieceColor === 'white') {
whiteKingLives--;
activateAbility('white', whiteKingLives);
} else {
blackKingLives--;
activateAbility('black', blackKingLives);
}
updateLivesDisplay();
}
LK.getSound('capture').play();
var pieceTitle = capturingPiece.pieceType.charAt(0).toUpperCase() + capturingPiece.pieceType.slice(1);
var escapeMessage = capturingPiece.pieceType === 'king' ? ' Auto-Captures Threatening Piece! 1 Life Lost for Escaping!' : ' Auto-Captures Threatening Piece!';
turnText.setText(capturingPiece.pieceColor.charAt(0).toUpperCase() + capturingPiece.pieceColor.slice(1) + ' ' + pieceTitle + escapeMessage);
// Continue game - switch turns without losing lives
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
turnText.setText(currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1) + '\'s Turn');
gameState = 'playing';
// Trigger AI move if it's black's turn
if (currentPlayer === 'black') {
makeAIMove();
}
return;
}
// Check if player is checkmated (no escape moves) - only after counter-capture check fails
if (!hasValidEscapeMoves(currentPlayer)) {
// Must escape situation failed - no counter-capture possible, restart game
turnText.setText('Must Escape Situation! No counter-capture available - Game Restarting!');
LK.setTimeout(function () {
restartGame();
}, 2000);
return;
}
// Reduce king lives when in check but not checkmated
if (currentPlayer === 'white') {
whiteKingLives--;
activateAbility('white', whiteKingLives);
} else {
blackKingLives--;
activateAbility('black', blackKingLives);
}
updateLivesDisplay();
// Check if king is out of lives (restart game when lives reach 0)
if (whiteKingLives <= 0 || blackKingLives <= 0) {
var winner = whiteKingLives <= 0 ? 'Black' : 'White';
turnText.setText(winner + ' Wins! King Out of Lives!');
LK.setTimeout(function () {
restartGame();
}, 2000);
return;
}
gameState = 'check';
LK.getSound('check').play();
var currentLives = currentPlayer === 'white' ? whiteKingLives : blackKingLives;
if (currentLives === 0) {
turnText.setText(currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1) + ' in Check! FINAL LIFE - Must Escape or Lose!');
} else {
turnText.setText(currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1) + ' in Check! Lives: ' + currentLives + ' - Must Escape!');
}
} else if (isStalemate(currentPlayer)) {
gameState = 'stalemate';
turnText.setText('Stalemate!');
LK.setTimeout(function () {
restartGame();
}, 2000);
} else {
gameState = 'playing';
}
// Trigger AI move if it's black's turn
if (currentPlayer === 'black' && (gameState === 'playing' || gameState === 'check')) {
makeAIMove();
}
}
function getPieceValue(pieceType) {
switch (pieceType) {
case 'pawn':
return 1;
case 'knight':
return 3;
case 'bishop':
return 3;
case 'rook':
return 5;
case 'snake':
return 6;
// Higher value due to special abilities
case 'queen':
return 9;
case 'king':
return 0;
default:
return 0;
}
}
function promotePawn(pawn) {
// Simple promotion to queen for now
pawn.pieceType = 'queen';
pawn.destroy();
var newQueen = new ChessPiece('queen', pawn.pieceColor, pawn.row, pawn.col);
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] === pawn) {
pieces[i] = newQueen;
break;
}
}
gameBoard[pawn.row][pawn.col] = newQueen;
game.addChild(newQueen);
newQueen.updatePosition();
}
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;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor !== color && piece.canMoveTo(king.row, king.col)) {
return true;
}
}
return false;
}
function isCheckmate(color) {
if (!isInCheck(color)) return false;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 16; col++) {
if (piece.canMoveTo(row, col)) {
// Simulate move
var originalRow = piece.row;
var originalCol = piece.col;
var capturedPiece = getPieceAt(row, col);
gameBoard[originalRow][originalCol] = null;
gameBoard[row][col] = piece;
piece.row = row;
piece.col = col;
var stillInCheck = isInCheck(color);
// Restore position
piece.row = originalRow;
piece.col = originalCol;
gameBoard[originalRow][originalCol] = piece;
gameBoard[row][col] = capturedPiece;
if (!stillInCheck) {
return false;
}
}
}
}
}
}
return true;
}
function isStalemate(color) {
if (isInCheck(color)) return false;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 16; col++) {
if (piece.canMoveTo(row, col)) {
return false;
}
}
}
}
}
return true;
}
function getAllValidMoves(color) {
var allMoves = [];
var playerInCheck = isInCheck(color);
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 16; col++) {
if (piece.canMoveTo(row, col)) {
// If in check, only allow moves that escape check
if (playerInCheck) {
if (canEscapeCheck(piece, row, col)) {
allMoves.push({
piece: piece,
toRow: row,
toCol: col
});
}
} else {
allMoves.push({
piece: piece,
toRow: row,
toCol: col
});
}
}
}
}
}
}
return allMoves;
}
function makeAIMove() {
if (currentPlayer !== 'black' || gameState !== 'playing' && gameState !== 'check') return;
var validAIMoves = getAllValidMoves('black');
// Check if AI is in checkmate but can auto-capture
if (validAIMoves.length === 0 && isInCheck('black')) {
var blackKing = findKing('black');
var threateningPiece = findThreateningPiece(blackKing);
var canAutoCapture = false;
var capturingPiece = null;
var captureRow = -1;
var captureCol = -1;
// First check if king can capture the threatening piece
if (blackKing && threateningPiece && blackKing.canMoveTo(threateningPiece.row, threateningPiece.col) && isKingSafeAt(blackKing, threateningPiece.row, threateningPiece.col)) {
canAutoCapture = true;
capturingPiece = blackKing;
captureRow = threateningPiece.row;
captureCol = threateningPiece.col;
} else if (threateningPiece) {
// Check if any other AI piece can capture the threatening piece
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === 'black' && piece.canMoveTo(threateningPiece.row, threateningPiece.col)) {
// Test if this capture would get the king out of check
if (canEscapeCheck(piece, threateningPiece.row, threateningPiece.col)) {
canAutoCapture = true;
capturingPiece = piece;
captureRow = threateningPiece.row;
captureCol = threateningPiece.col;
break;
}
}
}
}
if (canAutoCapture) {
// Auto-capture: AI piece takes the threatening piece
LK.setTimeout(function () {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] === threateningPiece) {
pieces[i].destroy();
pieces.splice(i, 1);
break;
}
}
// Move AI capturing piece to threatening piece position
gameBoard[capturingPiece.row][capturingPiece.col] = null;
capturingPiece.row = captureRow;
capturingPiece.col = captureCol;
gameBoard[capturingPiece.row][capturingPiece.col] = capturingPiece;
capturingPiece.updatePosition(true);
if (capturingPiece.pieceType === 'king') {
updateKingSquare();
// Apply 1 damage to AI king for escaping by counter-capture
blackKingLives--;
activateAbility('black', blackKingLives);
updateLivesDisplay();
}
LK.getSound('capture').play();
var pieceTitle = capturingPiece.pieceType.charAt(0).toUpperCase() + capturingPiece.pieceType.slice(1);
var escapeMessage = capturingPiece.pieceType === 'king' ? ' Auto-Captures Threatening Piece! 1 Life Lost for Escaping!' : ' Auto-Captures Threatening Piece!';
turnText.setText('Black ' + pieceTitle + escapeMessage);
// Continue game - switch turns without loses
currentPlayer = 'white';
turnText.setText('Your Turn');
gameState = 'playing';
}, 800);
return;
}
}
if (validAIMoves.length === 0) return;
// Advanced AI Strategy Implementation
var bestMove = chooseBestAIMove(validAIMoves);
if (bestMove) {
// Check if this is a snake move and handle multi-move sequence
if (bestMove.piece.pieceType === 'snake') {
// Execute the move after a short delay
LK.setTimeout(function () {
movePiece(bestMove.piece, bestMove.toRow, bestMove.toCol);
// If snake has more moves remaining, continue with AI moves
if (currentSnakePiece && currentSnakePiece.pieceColor === 'black' && snakeMovesRemaining > 0) {
// Delay before next snake move
LK.setTimeout(function () {
makeAIMove(); // Recursive call for next snake move
}, 800);
}
}, 800);
} else {
// Execute regular move after a short delay
LK.setTimeout(function () {
movePiece(bestMove.piece, bestMove.toRow, bestMove.toCol);
}, 800);
}
}
}
function isMoveThreatening(fromRow, fromCol, targetRow, targetCol) {
// Simple check if move gets closer to target (used for king protection)
var currentDistance = Math.abs(fromRow - targetRow) + Math.abs(fromCol - targetCol);
var newDistance = Math.abs(fromRow - targetRow) + Math.abs(fromCol - targetCol);
return newDistance < currentDistance;
}
function chooseBestAIMove(validMoves) {
// Strategic AI decision making with lookahead analysis
var checkmateMove = findCheckmateMove(validMoves);
if (checkmateMove) {
return checkmateMove;
}
// Prioritize capturing opponent's snake and queen with non-queen/snake pieces
var highValueCapture = findHighValueCapture(validMoves);
if (highValueCapture && shouldTakeCapture(highValueCapture)) {
return highValueCapture;
}
// Use snake to poison pieces protecting the king
var poisonMove = findPoisonOpportunity(validMoves);
if (poisonMove) {
return poisonMove;
}
var captureMove = findBestCapture(validMoves);
if (captureMove && shouldTakeCapture(captureMove)) {
return captureMove;
}
var tacticalMove = findTacticalMove(validMoves);
if (tacticalMove) {
return tacticalMove;
}
var withdrawMove = findWithdrawMove(validMoves);
if (withdrawMove) {
return withdrawMove;
}
// Default to safe positional move
return findSafePositionalMove(validMoves);
}
function findCheckmateMove(validMoves) {
// Look for moves that can checkmate the opponent
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (simulateMove(move, function () {
return isCheckmate('white');
})) {
return move;
}
}
return null;
}
function findBestCapture(validMoves) {
var bestCapture = null;
var bestValue = 0;
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
var targetPiece = getPieceAt(move.toRow, move.toCol);
if (targetPiece && targetPiece.pieceColor === 'white') {
var captureValue = getPieceValue(targetPiece.pieceType);
// Prioritize king captures highly
if (targetPiece.pieceType === 'king') {
captureValue = 1000;
}
if (captureValue > bestValue) {
bestValue = captureValue;
bestCapture = move;
}
}
}
return bestCapture;
}
function shouldTakeCapture(captureMove) {
// Analyze if capture is safe by looking ahead 2 moves
var isSafe = simulateMove(captureMove, function () {
// Check if the capturing piece can be counter-captured
var capturedPosition = {
row: captureMove.toRow,
col: captureMove.toCol
};
var opponentMoves = getAllValidMoves('white');
for (var i = 0; i < opponentMoves.length; i++) {
var counterMove = opponentMoves[i];
if (counterMove.toRow === capturedPosition.row && counterMove.toCol === capturedPosition.col) {
var counterValue = getPieceValue(counterMove.piece.pieceType);
var captureValue = getPieceValue(getPieceAt(captureMove.toRow, captureMove.toCol).pieceType);
// Only take if gain is worth the risk
return captureValue > counterValue;
}
}
return true; // Safe capture
});
return isSafe;
}
function findTacticalMove(validMoves) {
// Look for moves that create pressure or tactical advantages
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
// Check if move puts opponent in check
if (simulateMove(move, function () {
return isInCheck('white');
})) {
return move;
}
// Check if move creates fork or pin opportunities
if (createsFork(move) || createsPin(move)) {
return move;
}
}
return null;
}
function findWithdrawMove(validMoves) {
// Sometimes withdraw valuable pieces when under threat
var valuablePieces = [];
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === 'black' && (piece.pieceType === 'queen' || piece.pieceType === 'snake' || piece.pieceType === 'rook')) {
if (isPieceUnderThreat(piece)) {
valuablePieces.push(piece);
}
}
}
for (var i = 0; i < valuablePieces.length; i++) {
var piece = valuablePieces[i];
for (var j = 0; j < validMoves.length; j++) {
var move = validMoves[j];
if (move.piece === piece && !isPieceUnderThreatAt(piece, move.toRow, move.toCol)) {
// Use knight and bishop to create pressure occasionally
if (Math.random() < 0.3 && (piece.pieceType === 'knight' || piece.pieceType === 'bishop')) {
if (createsPressure(move)) {
return move;
}
}
return move; // Safe withdrawal
}
}
}
return null;
}
function findSafePositionalMove(validMoves) {
// Choose a move that improves position without risk
var safeMoves = [];
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (!isPieceUnderThreatAt(move.piece, move.toRow, move.toCol)) {
safeMoves.push(move);
}
}
if (safeMoves.length > 0) {
return safeMoves[Math.floor(Math.random() * safeMoves.length)];
}
return validMoves[Math.floor(Math.random() * validMoves.length)];
}
function simulateMove(move, testFunction) {
// Temporarily execute move and test condition
var originalRow = move.piece.row;
var originalCol = move.piece.col;
var capturedPiece = getPieceAt(move.toRow, move.toCol);
// Make temporary move
gameBoard[originalRow][originalCol] = null;
gameBoard[move.toRow][move.toCol] = move.piece;
move.piece.row = move.toRow;
move.piece.col = move.toCol;
var result = testFunction();
// Restore position
move.piece.row = originalRow;
move.piece.col = originalCol;
gameBoard[originalRow][originalCol] = move.piece;
gameBoard[move.toRow][move.toCol] = capturedPiece;
return result;
}
function isPieceUnderThreat(piece) {
var whitePieces = pieces.filter(function (p) {
return p.pieceColor === 'white';
});
for (var i = 0; i < whitePieces.length; i++) {
if (whitePieces[i].canMoveTo(piece.row, piece.col)) {
return true;
}
}
return false;
}
function isPieceUnderThreatAt(piece, row, col) {
var whitePieces = pieces.filter(function (p) {
return p.pieceColor === 'white';
});
for (var i = 0; i < whitePieces.length; i++) {
if (whitePieces[i].canMoveTo(row, col)) {
return true;
}
}
return false;
}
function createsFork(move) {
// Check if move attacks two or more enemy pieces
var attackCount = 0;
var whitePieces = pieces.filter(function (p) {
return p.pieceColor === 'white';
});
return simulateMove(move, function () {
for (var i = 0; i < whitePieces.length; i++) {
if (move.piece.canMoveTo(whitePieces[i].row, whitePieces[i].col)) {
attackCount++;
}
}
return attackCount >= 2;
});
}
function createsPin(move) {
// Simplified pin detection - attacks piece that's protecting the king
var whiteKing = findKing('white');
if (!whiteKing) return false;
return simulateMove(move, function () {
var targetPiece = getPieceAt(move.toRow, move.toCol);
if (targetPiece && targetPiece.pieceColor === 'white') {
// Check if removing this piece would expose king
var originalRow = targetPiece.row;
var originalCol = targetPiece.col;
gameBoard[originalRow][originalCol] = null;
var exposesKing = move.piece.canMoveTo(whiteKing.row, whiteKing.col);
gameBoard[originalRow][originalCol] = targetPiece;
return exposesKing;
}
return false;
});
}
function createsPressure(move) {
// Check if move creates pressure on opponent's position
var pressureScore = 0;
var whitePieces = pieces.filter(function (p) {
return p.pieceColor === 'white';
});
return simulateMove(move, function () {
for (var i = 0; i < whitePieces.length; i++) {
var piece = whitePieces[i];
if (move.piece.canMoveTo(piece.row, piece.col)) {
pressureScore += getPieceValue(piece.pieceType);
}
}
return pressureScore > 3; // Creates meaningful pressure
});
}
function findHighValueCapture(validMoves) {
// AI prioritizes capturing opponent's snake and queen with non-queen/snake pieces
var bestCapture = null;
var bestPriority = 0;
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
var targetPiece = getPieceAt(move.toRow, move.toCol);
if (targetPiece && targetPiece.pieceColor === 'white') {
// Prioritize capturing snake and queen
if ((targetPiece.pieceType === 'snake' || targetPiece.pieceType === 'queen') && move.piece.pieceType !== 'queen' && move.piece.pieceType !== 'snake') {
var priority = targetPiece.pieceType === 'snake' ? 10 : 8;
if (priority > bestPriority) {
bestPriority = priority;
bestCapture = move;
}
}
}
}
return bestCapture;
}
function findPoisonOpportunity(validMoves) {
// AI uses snake to move closer to enemy pieces protecting the king to poison them
var whiteKing = findKing('white');
if (!whiteKing) return null;
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (move.piece.pieceType === 'snake') {
// Check if this snake move would poison pieces near the white king
var kingProtectors = getKingProtectors('white');
if (kingProtectors.length > 0) {
// Check if moving snake to this position would poison any king protectors
var wouldPoisonProtector = simulateMove(move, function () {
var poisonPositions = [{
row: move.toRow - 1,
col: move.toCol - 1
}, {
row: move.toRow - 1,
col: move.toCol
}, {
row: move.toRow - 1,
col: move.toCol + 1
}, {
row: move.toRow,
col: move.toCol - 1
}, {
row: move.toRow,
col: move.toCol + 1
}, {
row: move.toRow + 1,
col: move.toCol - 1
}, {
row: move.toRow + 1,
col: move.toCol
}, {
row: move.toRow + 1,
col: move.toCol + 1
}];
for (var j = 0; j < poisonPositions.length; j++) {
var pos = poisonPositions[j];
if (pos.row >= 0 && pos.row < 8 && pos.col >= 0 && pos.col < 16) {
var pieceAtPos = getPieceAt(pos.row, pos.col);
if (pieceAtPos && pieceAtPos.pieceColor === 'white') {
for (var k = 0; k < kingProtectors.length; k++) {
if (kingProtectors[k] === pieceAtPos) {
return true;
}
}
}
}
}
return false;
});
if (wouldPoisonProtector) {
return move;
}
}
}
}
return null;
}
function getKingProtectors(color) {
// Find pieces that are protecting the king
var king = findKing(color);
if (!king) return [];
var protectors = [];
var enemyColor = color === 'white' ? 'black' : 'white';
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor === color && piece !== king) {
// Check if removing this piece would expose king to attack
var originalRow = piece.row;
var originalCol = piece.col;
gameBoard[originalRow][originalCol] = null;
var exposesKing = false;
for (var j = 0; j < pieces.length; j++) {
var enemyPiece = pieces[j];
if (enemyPiece.pieceColor === enemyColor && enemyPiece.canMoveTo(king.row, king.col)) {
exposesKing = true;
break;
}
}
gameBoard[originalRow][originalCol] = piece;
if (exposesKing) {
protectors.push(piece);
}
}
}
return protectors;
}
function canEscapeCheck(piece, newRow, newCol) {
// Simulate the move to see if it gets the king out of check
var originalRow = piece.row;
var originalCol = piece.col;
var capturedPiece = getPieceAt(newRow, newCol);
// Make temporary move
gameBoard[originalRow][originalCol] = null;
gameBoard[newRow][newCol] = piece;
piece.row = newRow;
piece.col = newCol;
// Check if still in check after move
var stillInCheck = isInCheck(piece.pieceColor);
// Restore original position
piece.row = originalRow;
piece.col = originalCol;
gameBoard[originalRow][originalCol] = piece;
gameBoard[newRow][newCol] = capturedPiece;
return !stillInCheck;
}
function isKingSafeAt(king, newRow, newCol) {
// Check if king would be safe at this position
var originalRow = king.row;
var originalCol = king.col;
var capturedPiece = getPieceAt(newRow, newCol);
// Temporarily move king to test position
gameBoard[originalRow][originalCol] = null;
gameBoard[newRow][newCol] = king;
king.row = newRow;
king.col = newCol;
// Check if king would be in check at new position
var wouldBeInCheck = isInCheck(king.pieceColor);
// Restore original position
king.row = originalRow;
king.col = originalCol;
gameBoard[originalRow][originalCol] = king;
gameBoard[newRow][newCol] = capturedPiece;
return !wouldBeInCheck;
}
function hasValidEscapeMoves(color) {
// Check if color has any valid moves when in check
var allMoves = getAllValidMoves(color);
return allMoves.length > 0;
}
function findThreateningPiece(king) {
// Find the piece that is threatening the king
if (!king) return null;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor !== king.pieceColor && piece.canMoveTo(king.row, king.col)) {
return piece;
}
}
return null;
}
function updateLivesDisplay() {
// Update text
whiteLivesText.setText('Your Lives: ' + whiteKingLives);
blackLivesText.setText('Enemy Lives: ' + blackKingLives);
// Update visual hearts with smooth animation
for (var i = 0; i < 4; i++) {
if (i < whiteKingLives) {
tween(whiteLivesHearts[i], {
alpha: 1.0,
tint: 0x00FF00
}, {
duration: 300,
easing: tween.easeOut
});
} else {
tween(whiteLivesHearts[i], {
alpha: 0.3,
tint: 0x666666
}, {
duration: 300,
easing: tween.easeOut
});
}
if (i < blackKingLives) {
tween(blackLivesHearts[i], {
alpha: 1.0,
tint: 0xFF0000
}, {
duration: 300,
easing: tween.easeOut
});
} else {
tween(blackLivesHearts[i], {
alpha: 0.3,
tint: 0x666666
}, {
duration: 300,
easing: tween.easeOut
});
}
}
}
function activateAbility(color, remainingLives) {
var abilityName = '';
var abilityEffect = '';
switch (remainingLives) {
case 3:
abilityName = 'Shield Boost';
abilityEffect = 'All pieces gain temporary protection';
// Flash all pieces of that color green to show protection
flashPiecesOfColor(color, 0x00FF00, 1000);
break;
case 2:
abilityName = 'Speed Rush';
abilityEffect = 'Pieces move faster for next 3 turns';
// Make pieces glow blue to show speed boost
flashPiecesOfColor(color, 0x0099FF, 1500);
break;
case 1:
abilityName = 'Rage Mode';
abilityEffect = 'Double damage on next capture';
// Make pieces glow red to show rage
flashPiecesOfColor(color, 0xFF3333, 2000);
break;
case 0:
abilityName = 'Final Stand';
abilityEffect = 'Last desperate attempt';
break;
}
// Show ability activation message
var message = color.charAt(0).toUpperCase() + color.slice(1) + ' Ability: ' + abilityName;
var abilityText = new Text2(message, {
size: 60,
fill: color === 'white' ? 0xFFFFFF : 0xFF0000
});
abilityText.anchor.set(0.5, 0.5);
abilityText.x = 1024;
abilityText.y = 1200;
game.addChild(abilityText);
// Animate ability text
tween(abilityText, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 2000,
easing: tween.easeOut,
onComplete: function onComplete() {
abilityText.destroy();
}
});
}
function flashPiecesOfColor(color, flashColor, duration) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color) {
LK.effects.flashObject(pieces[i], flashColor, duration);
}
}
}
function applyPoisonBehindSnake(snake, oldRow, oldCol) {
// Apply poison to pieces around the snake's previous position (behind it)
var poisonPositions = [{
row: oldRow - 1,
col: oldCol - 1
}, {
row: oldRow - 1,
col: oldCol
}, {
row: oldRow - 1,
col: oldCol + 1
}, {
row: oldRow,
col: oldCol - 1
}, {
row: oldRow,
col: oldCol + 1
}, {
row: oldRow + 1,
col: oldCol - 1
}, {
row: oldRow + 1,
col: oldCol
}, {
row: oldRow + 1,
col: oldCol + 1
}];
for (var i = 0; i < poisonPositions.length; i++) {
var pos = poisonPositions[i];
if (pos.row >= 0 && pos.row < 8 && pos.col >= 0 && pos.col < 16) {
var pieceAtPos = getPieceAt(pos.row, pos.col);
if (pieceAtPos && pieceAtPos.pieceColor !== snake.pieceColor) {
pieceAtPos.applyPoison(3); // Poison for 3 turns
// Flash piece red to show poison application with proper closure
var targetPiece = pieceAtPos; // Capture the piece in closure
tween(targetPiece, {
tint: 0xff0000
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(targetPiece, {
tint: 0xff6666
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}
}
}
function restartGame() {
// Determine winner before clearing state
var winner = whiteKingLives <= 0 ? 'Black' : 'White';
// Show win screen with team name
showWinScreen(winner);
}
function showWinScreen(winningTeam) {
// Create win screen overlay
var winScreen = new Container();
game.addChild(winScreen);
// Semi-transparent background
var background = LK.getAsset('darkSquare', {
anchorX: 0,
anchorY: 0,
alpha: 0.8,
scaleX: 20,
scaleY: 25
});
background.x = 0;
background.y = 0;
winScreen.addChild(background);
// Win text
var winText = new Text2(winningTeam + ' Team Wins!', {
size: 120,
fill: winningTeam === 'White' ? 0xFFFFFF : 0xFF0000
});
winText.anchor.set(0.5, 0.5);
winText.x = 1024;
winText.y = 1366;
winScreen.addChild(winText);
// Animate win text
tween(winText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut
});
// Auto-restart after 1 second
LK.setTimeout(function () {
winScreen.destroy();
actualRestartGame();
}, 1000);
}
function actualRestartGame() {
// Clear all pieces
for (var i = 0; i < pieces.length; i++) {
pieces[i].destroy();
}
pieces = [];
// Clear highlights
clearHighlights();
// Clear king squares
if (kingSquare) {
kingSquare.destroy();
kingSquare = null;
}
if (blackKingSquare) {
blackKingSquare.destroy();
blackKingSquare = null;
}
// Reset game state
currentPlayer = 'white';
selectedPiece = null;
validMoves = [];
dragNode = null;
gameState = 'playing';
whiteKingLives = 4;
blackKingLives = 4;
currentSnakePiece = null;
snakeMovesRemaining = 0;
activeSnakePiece = null; // Reset active snake
// Reset all snake cooldowns
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceType === 'snake') {
pieces[i].snakeOnCooldown = false;
pieces[i].snakeMovesThisTurn = 0;
pieces[i].snakeLastMoveDirection = null;
}
}
updateLivesDisplay();
turnText.setText('Your Turn');
// Clear board
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 16; col++) {
gameBoard[row][col] = null;
}
}
// Recreate pieces with traditional chess layout - 2 snakes replace specific rook and knight positions
var pieceSetup = [['rook', 'knight', 'bishop', 'queen', 'king', 'queen', 'bishop', 'knight', 'rook', 'rook', 'knight', 'bishop', 'queen', 'snake', 'snake', 'rook'], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn']];
// Create black pieces
for (var row = 0; row < 2; row++) {
for (var col = 0; col < 16; col++) {
var piece = new ChessPiece(pieceSetup[row][col], 'black', row, col);
pieces.push(piece);
gameBoard[row][col] = piece;
game.addChild(piece);
piece.updatePosition();
}
}
// Create white pieces
for (var row = 6; row < 8; row++) {
for (var col = 0; col < 16; col++) {
var pieceType = row === 6 ? 'pawn' : pieceSetup[7 - row][col];
var piece = new ChessPiece(pieceType, 'white', row, col);
pieces.push(piece);
gameBoard[row][col] = piece;
game.addChild(piece);
piece.updatePosition();
}
}
// Initialize king square after restart
updateKingSquare();
}
game.down = function (x, y, obj) {
if (gameState !== 'playing' && gameState !== 'check') return;
var square = getSquareFromPosition(x, y);
if (!square) return;
var clickedPiece = getPieceAt(square.row, square.col);
if (selectedPiece) {
// Check if clicked on valid move
var isValidMove = false;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === square.row && validMoves[i].col === square.col) {
isValidMove = true;
break;
}
}
if (isValidMove) {
movePiece(selectedPiece, square.row, square.col);
}
clearHighlights();
selectedPiece = null;
}
// If there's an active snake, only allow that snake to move
if (activeSnakePiece && activeSnakePiece.pieceColor === currentPlayer && currentPlayer === 'white') {
if (clickedPiece === activeSnakePiece) {
selectedPiece = activeSnakePiece;
dragNode = activeSnakePiece;
showValidMoves(activeSnakePiece);
}
} else if (clickedPiece && clickedPiece.pieceColor === currentPlayer && currentPlayer === 'white') {
selectedPiece = clickedPiece;
dragNode = clickedPiece;
showValidMoves(clickedPiece);
}
};
game.move = function (x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
}
};
game.up = function (x, y, obj) {
if (dragNode && selectedPiece) {
var square = getSquareFromPosition(x, y);
if (square) {
var isValidMove = false;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === square.row && validMoves[i].col === square.col) {
isValidMove = true;
break;
}
}
if (isValidMove) {
movePiece(selectedPiece, square.row, square.col);
clearHighlights();
selectedPiece = null;
} else {
selectedPiece.updatePosition(true);
}
} else {
selectedPiece.updatePosition(true);
}
}
dragNode = null;
};
game.update = function () {
// Game logic runs automatically through event handlers
}; ===================================================================
--- original.js
+++ change.js
@@ -539,9 +539,18 @@
gameBoard[capturedPiece.row][capturedPiece.col] = capturedPiece;
capturedPiece.updatePosition(true);
updateKingSquare();
LK.getSound('capture').play();
- turnText.setText(capturedPiece.pieceColor.charAt(0).toUpperCase() + capturedPiece.pieceColor.slice(1) + ' King Counter-Attacks!');
+ // Apply 1 damage to the king's side for escaping
+ if (capturedPiece.pieceColor === 'white') {
+ whiteKingLives--;
+ activateAbility('white', whiteKingLives);
+ } else {
+ blackKingLives--;
+ activateAbility('black', blackKingLives);
+ }
+ updateLivesDisplay();
+ turnText.setText(capturedPiece.pieceColor.charAt(0).toUpperCase() + capturedPiece.pieceColor.slice(1) + ' King Counter-Attacks! 1 Life Lost for Escaping!');
return;
} else {
// Reduce king lives
if (capturedPiece.pieceColor === 'white') {
@@ -739,12 +748,22 @@
gameBoard[capturingPiece.row][capturingPiece.col] = capturingPiece;
capturingPiece.updatePosition(true);
if (capturingPiece.pieceType === 'king') {
updateKingSquare();
+ // Apply 1 damage to king's side for escaping by counter-capture
+ if (capturingPiece.pieceColor === 'white') {
+ whiteKingLives--;
+ activateAbility('white', whiteKingLives);
+ } else {
+ blackKingLives--;
+ activateAbility('black', blackKingLives);
+ }
+ updateLivesDisplay();
}
LK.getSound('capture').play();
var pieceTitle = capturingPiece.pieceType.charAt(0).toUpperCase() + capturingPiece.pieceType.slice(1);
- turnText.setText(capturingPiece.pieceColor.charAt(0).toUpperCase() + capturingPiece.pieceColor.slice(1) + ' ' + pieceTitle + ' Auto-Captures Threatening Piece!');
+ var escapeMessage = capturingPiece.pieceType === 'king' ? ' Auto-Captures Threatening Piece! 1 Life Lost for Escaping!' : ' Auto-Captures Threatening Piece!';
+ turnText.setText(capturingPiece.pieceColor.charAt(0).toUpperCase() + capturingPiece.pieceColor.slice(1) + ' ' + pieceTitle + escapeMessage);
// Continue game - switch turns without losing lives
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
turnText.setText(currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1) + '\'s Turn');
gameState = 'playing';
@@ -988,12 +1007,17 @@
gameBoard[capturingPiece.row][capturingPiece.col] = capturingPiece;
capturingPiece.updatePosition(true);
if (capturingPiece.pieceType === 'king') {
updateKingSquare();
+ // Apply 1 damage to AI king for escaping by counter-capture
+ blackKingLives--;
+ activateAbility('black', blackKingLives);
+ updateLivesDisplay();
}
LK.getSound('capture').play();
var pieceTitle = capturingPiece.pieceType.charAt(0).toUpperCase() + capturingPiece.pieceType.slice(1);
- turnText.setText('Black ' + pieceTitle + ' Auto-Captures Threatening Piece!');
+ var escapeMessage = capturingPiece.pieceType === 'king' ? ' Auto-Captures Threatening Piece! 1 Life Lost for Escaping!' : ' Auto-Captures Threatening Piece!';
+ turnText.setText('Black ' + pieceTitle + escapeMessage);
// Continue game - switch turns without loses
currentPlayer = 'white';
turnText.setText('Your Turn');
gameState = 'playing';
a black chess piece that resembles a chess pawn but is dressed like a jester. In-Game asset. 2d. High contrast. No shadows
Draw a black pawn dressed in a priest's robe and holding two crosses in the air in a divine manner. In-Game asset. 2d. High contrast. No shadows
Draw a white pawn dressed in a priest's robe and holding two crosses in the air in a divine manner. In-Game asset. 2d. High contrast. No shadows