User prompt
Bring back the knight and rooks, there will be only 2 snakes and they will replace the rook and knight that will not come back. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now, instead of a rook and a knight, let's add a new piece called a snake. This piece makes two moves per turn and moves in a Z-shape. (It moves in a 3x3 grid in a Z-shape.) During these three moves, it eats one piece for each point it stops. It also inflicts poison on the pieces behind it. (The poison effect is a new effect, which turns the piece red and makes it unplayable for three turns. The duration of this poison is written on the piece.) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now, instead of a rook and a knight, let's add a new piece called a snake. This piece makes two moves per turn and moves in a Z-shape. (It moves in a 3x3 grid in a Z-shape.) During these three moves, it eats one piece for each point it stops. It also inflicts poison on the pieces behind it. (The poison effect is a new effect, which turns the piece red and makes it unplayable for three turns. The duration of this poison is written on the piece.) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now, let's add a new piece called the snake, replacing the rook and knight. This piece makes two moves per turn and moves in a Z-shape. (It moves in a 3x3 grid in a Z-shape.) During these three moves, it eats one piece for each point it stops. It also inflicts poison on the pieces behind it. (The poison effect is a new effect, which turns the piece red and makes it unplayable for three turns. The duration of this poison is written on the piece.) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now, let's add a new piece called the snake, replacing the rook and knight. This piece makes two moves per turn and moves in a Z-shape. (It moves in a 3x3 grid in a Z-shape.) During these three moves, it eats one piece for each point it stops. It also inflicts poison on the pieces behind it. (The poison effect is a new effect, which turns the piece red and makes it unplayable for three turns. The duration of this poison is written on the piece.) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
In must escape situations, first of all, it must be checked whether the king and other pieces can capture the king piece, then the game must start from the beginning.
User prompt
Re-arrange the pieces according to your normal chessboard layout. Pieces of the same type are divided into two groups and placed side by side and take their classic places, but the pieces of the same type are placed side by side and around the king, similar to the original chess layout, but the normal extra pieces will be placed side by side and divided on two sides (example: if there are 5 rooks, a1 rook, a2 rook, a3 knight, a3 knight... and a14 rook, a15 rook, etc. synchronization and division by 2. If one side is odd, give 1 extra to a random side).
User prompt
Add assets to the squares showing my remaining lives and add assets to the squares showing the enemy's lives. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Do not add a new 4 life bar, delete the new life bar. The old life bar is 8 (add assets for the first 4 rightful life bars) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add assets to the 4 live life bars, separate life bars for AI and player ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
delete health bar
User prompt
Add player and AI health bars as assets ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
However, if the player cannot escape and can capture a piece that would checkmate them, the game automatically performs the action of capturing that piece instead of the player or AI. The game does not end, and 4 lives are not lost in this situation. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
However, if the player is unable to escape and can capture a piece that would checkmate them, the game automatically performs the capture action on behalf of the player or AI
User prompt
If a side is checkmated (pinned) and there's no escape, the player loses all lives and the game restarts. However, if the king can capture the captured piece, the game automatically captures that piece and the game continues. Remove the scoreboard and prevent your king from being placed on squares where it cannot be protected or can be checkmated.
User prompt
Similarly, when the king is taken, the opponent AI can make yellow moves to escape the king instead of thinking the game is over. However, when one of the two sides runs out of lives, the game starts from the beginning instead of stopping. In other words, if any side runs out of 4 lives, regardless of whether it is black or white, the game starts from the beginning. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the opponent's king's health drops to 1, they attempt to force their king to escape or capture the king by placing a piece between themselves and the king in check. These are also examples of yellow-squared moves. However, the game continues until the player or king has 4 lives; in other words, the opponent wins if they check four times. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
One life has been lost, but no squares have been taken. Once the king is formed, the yellow squares are taken, and the game continues. The yellow square rule ensures that the game continues when the king is captured. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the opponent checks and our health decreases by 1, the game continues, but we only make moves that protect or escape the king. The squares where these moves are made and the squares containing the pieces will be colored yellow. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The game does not end when one side checks. When the other side checks, the player's health decreases by 1. The opponent can only make moves to escape or protect their king. This applies to both sides.
User prompt
Let's put our four rights regarding our right to health behind chess pieces so that everyone can see their own life in front of them and everyone's life is behind their own chess pieces.
User prompt
Add lives to each side, representing the health of that side. You have 4 lives, and each health bar has a unique ability.
User prompt
The square below your opponent's king is also purple. Your opponent primarily plays to capture your chess pieces and attempts to capture your king (while playing aggressively and protecting their king). The king has 4 lives, and each capture reduces by 1. If either side loses, the game starts over from the beginning. Similarly, if either side checkmates, the game starts over from the beginning. When the match ends, it starts over from the beginning. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The square where the king is located is purple, and no matter where the king moves, the purple square will be the square below it. There is only one purple square, and it is always below the king.
User prompt
I straightened the squares in the first row. They look like rectangles, so make them squares too.
/****
* 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 = 2;
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)) {
return true;
}
} 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) {
var rowDiff = targetRow - self.row;
var colDiff = targetCol - self.col;
// Snake moves in Z-shape within 3x3 grid
if (Math.abs(rowDiff) <= 2 && Math.abs(colDiff) <= 2) {
// Z-pattern: specific Z-shape movement in 3x3 grid
var validZPositions = [
// Top horizontal line of Z (row -1)
{
row: -1,
col: -1
}, {
row: -1,
col: 0
}, {
row: -1,
col: 1
},
// Diagonal line of Z (middle diagonal)
{
row: 0,
col: 0
},
// Bottom horizontal line of Z (row +1)
{
row: 1,
col: -1
}, {
row: 1,
col: 0
}, {
row: 1,
col: 1
},
// Extended Z pattern positions for larger range
{
row: -2,
col: -2
}, {
row: -2,
col: -1
}, {
row: -2,
col: 0
}, {
row: 2,
col: 0
}, {
row: 2,
col: 1
}, {
row: 2,
col: 2
}];
for (var i = 0; i < validZPositions.length; i++) {
if (rowDiff === validZPositions[i].row && colDiff === validZPositions[i].col) {
return true;
}
}
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2D1810
});
/****
* Game Code
****/
// Sound effects
// Black pieces
// White pieces
// Chess board squares
// Game dimensions and board setup
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;
// 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();
turnText.setText(capturedPiece.pieceColor.charAt(0).toUpperCase() + capturedPiece.pieceColor.slice(1) + ' King Counter-Attacks!');
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') {
piece.snakeMovesThisTurn++;
snakeMovesRemaining = piece.maxSnakeMoves - piece.snakeMovesThisTurn;
currentSnakePiece = piece;
// Apply poison to pieces behind the snake
applyPoisonBehindSnake(piece, piece.row, piece.col);
// 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 < piece.maxSnakeMoves) {
turnText.setText(piece.pieceColor.charAt(0).toUpperCase() + piece.pieceColor.slice(1) + ' Snake - ' + snakeMovesRemaining + ' moves remaining');
// Clear current selection to allow new move
clearHighlights();
selectedPiece = null;
return; // Don't switch turns
}
// Reset snake moves when turn is complete
piece.snakeMovesThisTurn = 0;
currentSnakePiece = null;
snakeMovesRemaining = 0;
}
// Switch turns
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
// Reduce poison turns for all pieces of the new current player
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === currentPlayer) {
pieces[i].reducePoisonTurns();
}
}
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();
}
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!');
// 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();
}
LK.getSound('capture').play();
var pieceTitle = capturingPiece.pieceType.charAt(0).toUpperCase() + capturingPiece.pieceType.slice(1);
turnText.setText('Black ' + pieceTitle + ' Auto-Captures Threatening Piece!');
// Continue game - switch turns without losing lives
currentPlayer = 'white';
turnText.setText('Your Turn');
gameState = 'playing';
}, 800);
return;
}
}
if (validAIMoves.length === 0) return;
// AI strategy: prioritize capturing pieces, then protect king, then random moves
var captureMoves = [];
var protectMoves = [];
var regularMoves = [];
for (var i = 0; i < validAIMoves.length; i++) {
var move = validAIMoves[i];
var targetPiece = getPieceAt(move.toRow, move.toCol);
// Prioritize captures, especially the king
if (targetPiece) {
if (targetPiece.pieceType === 'king') {
// Highest priority - capture king
captureMoves.unshift(move);
} else {
captureMoves.push(move);
}
} else {
// Check if move protects the black king
var blackKing = findKing('black');
if (blackKing && isMoveThreatening(move.toRow, move.toCol, blackKing.row, blackKing.col)) {
protectMoves.push(move);
} else {
regularMoves.push(move);
}
}
}
// Choose move based on priority
var chosenMove;
if (captureMoves.length > 0) {
chosenMove = captureMoves[0]; // Take first capture (king captures are at front)
} else if (protectMoves.length > 0) {
var randomIndex = Math.floor(Math.random() * protectMoves.length);
chosenMove = protectMoves[randomIndex];
} else {
var randomIndex = Math.floor(Math.random() * regularMoves.length);
chosenMove = regularMoves[randomIndex];
}
// Execute the move after a short delay
LK.setTimeout(function () {
movePiece(chosenMove.piece, chosenMove.toRow, chosenMove.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 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() {
// 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;
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 (clickedPiece && clickedPiece.pieceColor === currentPlayer && currentPlayer === 'white') {
selectedPiece = clickedPiece;
dragNode = clickedPiece;
showValidMoves(clickedPiece);
} else if (currentSnakePiece && currentSnakePiece.pieceColor === currentPlayer && currentPlayer === 'white') {
// Allow continuing snake moves
selectedPiece = currentSnakePiece;
dragNode = currentSnakePiece;
showValidMoves(currentSnakePiece);
}
};
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
@@ -287,10 +287,10 @@
square.y = boardStartY + row * squareSize;
boardContainer.addChild(square);
}
}
-// Initialize pieces with traditional chess layout - snakes replace rooks and knights
-var pieceSetup = [['snake', 'snake', 'snake', 'snake', 'snake', 'snake', 'bishop', 'bishop', 'queen', 'king', 'queen', 'bishop', 'bishop', 'snake', 'snake', 'snake'], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn']];
+// 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);
@@ -1203,10 +1203,10 @@
for (var col = 0; col < 16; col++) {
gameBoard[row][col] = null;
}
}
- // Recreate pieces with traditional chess layout - snakes replace rooks and knights
- var pieceSetup = [['snake', 'snake', 'snake', 'snake', 'snake', 'snake', 'bishop', 'bishop', 'queen', 'king', 'queen', 'bishop', 'bishop', 'snake', 'snake', 'snake'], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn']];
+ // 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);
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