User prompt
public class SeaMonsterGame { // Basic piece class static class Piece { boolean isEnemy; public Piece(boolean isEnemy) { this.isEnemy = isEnemy; } } public static class SeaMonster { // The sea is defined as rows 6 and 7 static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; // Checks if the SeaMonster is inside the sea public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } /** * Determines if the SeaMonster can capture a piece at the target position. * - Only attacks enemy pieces * - Cannot attack friendly pieces or empty squares * - Can attack up to 3 squares away (straight) * - Can attack 1-square diagonals * - Can attack L-shapes (2 horizontal + 1 vertical) * - Can attack a special zone: 3 squares to the left, and one above/below it * - Can jump over other pieces (not blocked) */ public static boolean canCapture(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols, Piece[][] board) { // Check if SeaMonster is in sea if (!isInSea(monsterRow)) return false; // Check board boundaries if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; // Target must be an enemy piece Piece targetPiece = board[targetRow][targetCol]; if (targetPiece == null || !targetPiece.isEnemy) { return false; // Cannot attack empty or friendly square } // Calculate movement differences int rowDiff = targetRow - monsterRow; int colDiff = targetCol - monsterCol; int absRow = Math.abs(rowDiff); int absCol = Math.abs(colDiff); // Rule 1: 1-square diagonal if (absRow == 1 && absCol == 1) return true; // Rule 2: straight lines (up to 3 squares) if ((absRow == 0 && absCol >= 1 && absCol <= 3) || (absCol == 0 && absRow >= 1 && absRow <= 3)) { return true; } // Rule 3: horizontal-based L-shapes only (2 left/right + 1 up/down) if (absCol == 2 && absRow == 1) return true; // Rule 4: special left-3 zone if (targetCol == monsterCol - 3 && (targetRow == monsterRow || targetRow == monsterRow - 1 || targetRow == monsterRow + 1)) { return true; } // If none of the conditions are met, cannot capture return false; } } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; Piece[][] board = new Piece[boardRows][boardCols]; int monsterRow = 6; int monsterCol = 4; // Place enemy pieces in valid positions board[6][1] = new Piece(true); // 3 squares left board[5][1] = new Piece(true); // 3 left + 1 up board[7][1] = new Piece(true); // 3 left + 1 down board[5][5] = new Piece(true); // diagonal board[3][4] = new Piece(true); // 3 up board[5][6] = new Piece(true); // right 2 + up 1 (L shape) board[7][6] = new Piece(true); // right 2 + down 1 (L shape) // Place friendly piece that should NOT be captured board[5][2] = new Piece(false); // friendly board[6][5] = new Piece(false); // friendly in straight line // Output System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can capture:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (SeaMonster.canCapture(monsterRow, monsterCol, row, col, boardRows, boardCols, board)) { System.out.println(" → Enemy at (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = targetRow - monsterRow; int colDiff = targetCol - monsterCol; int absRow = Math.abs(rowDiff); int absCol = Math.abs(colDiff); // Diagonal if (absRow == 1 && absCol == 1) return true; // Straight up to 3 if ((absRow == 0 && absCol >= 1 && absCol <= 3) || (absCol == 0 && absRow >= 1 && absRow <= 3)) { return true; } // Wide L-shape: 2 horiz + 1 vert if (absCol == 2 && absRow == 1) return true; // Special Left-3 zone if (targetCol == monsterCol - 3 && (targetRow == monsterRow || targetRow == monsterRow - 1 || targetRow == monsterRow + 1)) { return true; } // All others not allowed return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = targetRow - monsterRow; int colDiff = targetCol - monsterCol; int absRow = Math.abs(rowDiff); int absCol = Math.abs(colDiff); // Diagonal if (absRow == 1 && absCol == 1) return true; // Straight up to 3 if ((absRow == 0 && absCol >= 1 && absCol <= 3) || (absCol == 0 && absRow >= 1 && absRow <= 3)) { return true; } // Wide L-shape: 2 horiz + 1 vert if (absCol == 2 && absRow == 1) return true; // Special Left-3 zone if (targetCol == monsterCol - 3 && (targetRow == monsterRow || targetRow == monsterRow - 1 || targetRow == monsterRow + 1)) { return true; } // All others not allowed return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; // Bounds check if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = targetRow - monsterRow; int colDiff = targetCol - monsterCol; int absRow = Math.abs(rowDiff); int absCol = Math.abs(colDiff); // ✅ 1-square diagonal if (absRow == 1 && absCol == 1) return true; // ✅ Straight lines (up to 3 squares) if ((absRow == 0 && absCol >= 1 && absCol <= 3) || (absCol == 0 && absRow >= 1 && absRow <= 3)) { return true; } // ✅ Wide horizontal-based L-shapes only if (absCol == 2 && absRow == 1) { return true; } // ✅ Special Rule: 3rd left column and its above/below if (targetCol == monsterCol - 3 && (targetRow == monsterRow || targetRow == monsterRow - 1 || targetRow == monsterRow + 1)) { return true; } return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; // Bounds check if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = targetRow - monsterRow; int colDiff = targetCol - monsterCol; int absRow = Math.abs(rowDiff); int absCol = Math.abs(colDiff); // ✅ Diagonal: 1-square if (absRow == 1 && absCol == 1) return true; // ✅ Straight lines (up to 3 squares) if ((absRow == 0 && absCol >= 1 && absCol <= 3) || (absCol == 0 && absRow >= 1 && absRow <= 3)) { return true; } // ✅ Only wide horizontal L-shapes: 2 horizontal + 1 vertical if (absCol == 2 && absRow == 1) { return true; } // ❌ Block 2x2 L-shape (absRow == 2 && absCol == 2) // ❌ Block vertical-based L (1 horiz + 2 vertical) return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; // Check board boundaries if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = targetRow - monsterRow; int colDiff = targetCol - monsterCol; int absRow = Math.abs(rowDiff); int absCol = Math.abs(colDiff); // ✅ 1-square diagonal if (absRow == 1 && absCol == 1) return true; // ✅ Straight lines up to 3 squares if ((absRow == 0 && absCol >= 1 && absCol <= 3) || (absCol == 0 && absRow >= 1 && absRow <= 3)) { return true; } // ✅ Only wide horizontal-based L-shape: // 2 right/left + 1 up/down if (absCol == 2 && absRow == 1) { return true; } // ✅ Long L-shape (2,2) if (absRow == 2 && absCol == 2) { return true; } // ❌ All others (including 1 left/right + 2 up/down) are not allowed return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } /** * Returns true if the target square can be attacked. * L-shapes are only allowed if based on horizontal (left/right) movement. */ public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; // Bounds check if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = Math.abs(targetRow - monsterRow); int colDiff = Math.abs(targetCol - monsterCol); // 1-square diagonal if (rowDiff == 1 && colDiff == 1) return true; // Straight lines (up to 3 squares) if ((rowDiff == 0 && colDiff >= 1 && colDiff <= 3) || (colDiff == 0 && rowDiff >= 1 && rowDiff <= 3)) { return true; } // Short L-shapes - horizontal-based only if ((colDiff == 2 && rowDiff == 1) || (colDiff == 1 && rowDiff == 2)) { // Allow only if movement is to left or right (i.e., col changes) if (targetCol != monsterCol) return true; } // Long L-shape (2,2) if (rowDiff == 2 && colDiff == 2) return true; return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; // Check if SeaMonster is in sea public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } /** * Check if SeaMonster can attack (eat) a piece at the target square. */ public static boolean canAttack(int monsterRow, int monsterCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(monsterRow)) return false; // Check board boundaries if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; // Distance differences int rowDiff = Math.abs(targetRow - monsterRow); int colDiff = Math.abs(targetCol - monsterCol); // Rule 1: Straight lines (horizontal or vertical), up to 3 squares if ((rowDiff == 0 && colDiff >= 1 && colDiff <= 3) || (colDiff == 0 && rowDiff >= 1 && rowDiff <= 3)) { return true; } // Rule 2: 1-square diagonal if (rowDiff == 1 && colDiff == 1) return true; // Rule 3: Short L-shape (knight-like) if ((rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2)) return true; // Rule 4: Long L-shape (2,2) if (rowDiff == 2 && colDiff == 2) return true; return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int monsterRow = 6; int monsterCol = 4; System.out.println("SeaMonster at (" + monsterRow + ", " + monsterCol + ") can attack:"); for (int row = 0; row < boardRows; row++) { for (int col = 0; col < boardCols; col++) { if (row == monsterRow && col == monsterCol) continue; // skip self if (canAttack(monsterRow, monsterCol, row, col, boardRows, boardCols)) { System.out.println(" - Square (" + row + ", " + col + ")"); } } } } }
User prompt
The sea monster can eat peices from three squares in a row, left, right, forward, and backward
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; // Check if the monster is in the sea public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } /** * Determines whether the SeaMonster can attack the target square from its current position. */ public static boolean canAttack(int seaRow, int seaCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(seaRow)) return false; // Must stay within board boundaries if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; int rowDiff = Math.abs(targetRow - seaRow); int colDiff = Math.abs(targetCol - seaCol); // 1-square diagonal if (rowDiff == 1 && colDiff == 1) return true; // Straight line (horizontal or vertical) up to 3 squares if ((rowDiff == 0 && colDiff >= 1 && colDiff <= 3) || (colDiff == 0 && rowDiff >= 1 && rowDiff <= 3)) { return true; } // Short L-shape (knight-style): (2,1) or (1,2) if ((rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2)) { return true; } // Long L-shape (3-square corner): (2,2) if (rowDiff == 2 && colDiff == 2) { return true; } return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int seaRow = 6; int seaCol = 4; // Test all possible positions in 7x7 area around the SeaMonster for (int row = seaRow - 3; row <= seaRow + 3; row++) { for (int col = seaCol - 3; col <= seaCol + 3; col++) { if (row == seaRow && col == seaCol) continue; // Skip self if (canAttack(seaRow, seaCol, row, col, boardRows, boardCols)) { System.out.println("SeaMonster can attack (" + row + ", " + col + ")"); } } } } }
User prompt
public class SeaMonster { static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; // Check if the monster is in the sea public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } /** * SeaMonster attack rules: * - 1-square diagonal * - Short L-shape (2,1) or (1,2) * - Long L-shape (2,2) to left or right */ public static boolean canAttack(int seaRow, int seaCol, int targetRow, int targetCol, int boardRows, int boardCols) { if (!isInSea(seaRow)) return false; int rowDiff = Math.abs(targetRow - seaRow); int colDiff = Math.abs(targetCol - seaCol); // Stay inside board if (targetRow < 0 || targetRow >= boardRows || targetCol < 0 || targetCol >= boardCols) return false; // 1-square diagonal if (rowDiff == 1 && colDiff == 1) return true; // Short L-shape if ((rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2)) { return true; } // Long L-shape (2 right/left and 2 up/down) if (rowDiff == 2 && colDiff == 2) { // Must be horizontal-based (i.e., left/right direction matters) if (targetCol != seaCol) { return true; } } return false; } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; int seaRow = 6; int seaCol = 4; int[][] targets = { {5, 5}, // diagonal ↗ {7, 3}, // diagonal ↙ {5, 6}, // short L right {4, 5}, // short L right {7, 6}, // short L right {5, 2}, // short L left {4, 2}, // long L left {8, 6}, // long L right (invalid - off board) {4, 6}, // long L right ✅ {6, 6} // straight horizontal ❌ }; for (int[] target : targets) { int row = target[0]; int col = target[1]; System.out.print("Can attack (" + row + ", " + col + ")? "); System.out.println(canAttack(seaRow, seaCol, row, col, boardRows, boardCols)); } } }
User prompt
Make it 3 squares
User prompt
public class SeaMonster { // Define sea area rows (inclusive) static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; // Check if a row is inside the sea public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } /** * SeaMonster can attack up to 2 squares to the left or right on the same row, * but only if it is in the sea. */ public static boolean canAttack(int seaRow, int seaCol, int targetRow, int targetCol, int boardCols) { if (!isInSea(seaRow)) { return false; // Monster must be in sea } if (targetRow != seaRow) { return false; // Attack must stay in the same row } int colDiff = targetCol - seaCol; // Can attack 1 or 2 squares left or right return (colDiff == -1 || colDiff == -2 || colDiff == 1 || colDiff == 2) && targetCol >= 0 && targetCol < boardCols; } public static void main(String[] args) { int boardCols = 8; // SeaMonster is at (6, 6) int seaRow = 6; int seaCol = 6; // Example target squares int targetRow = 6; int targetCol = 4; // 2 squares to the left if (canAttack(seaRow, seaCol, targetRow, targetCol, boardCols)) { System.out.println("SeaMonster can attack (" + targetRow + ", " + targetCol + ")"); } else { System.out.println("SeaMonster cannot attack that square."); } } }
User prompt
public class SeaMonster { // Define sea area (only inside this area can the SeaMonster attack) static final int SEA_ROW_START = 6; static final int SEA_ROW_END = 7; // Board dimensions static final int BOARD_ROWS = 8; static final int BOARD_COLS = 8; // Check if a row is in the sea public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } // Determine the direction of attack based on SeaMonster’s location public static String getAttackDirection(int row, int col) { if (col <= 1) { return "RIGHT"; } else if (col >= BOARD_COLS - 2) { return "LEFT"; } else if (row <= 1) { return "DOWN"; } else { return "UP"; } } // Check if the SeaMonster can attack a square public static boolean canAttack(int seaRow, int seaCol, int targetRow, int targetCol) { // Must be in the sea if (!isInSea(seaRow)) { return false; } String direction = getAttackDirection(seaRow, seaCol); switch (direction) { case "UP": return targetCol == seaCol && targetRow < seaRow && targetRow >= seaRow - 3; case "DOWN": return targetCol == seaCol && targetRow > seaRow && targetRow <= seaRow + 3; case "RIGHT": return targetRow == seaRow && targetCol > seaCol && targetCol <= seaCol + 3; case "LEFT": return targetRow == seaRow && targetCol < seaCol && targetCol >= seaCol - 3; default: return false; } } public static void main(String[] args) { // SeaMonster is at (6, 0) — left edge of sea int seaRow = 6; int seaCol = 0; // Target square int targetRow = 6; int targetCol = 2; // should be allowed if (canAttack(seaRow, seaCol, targetRow, targetCol)) { System.out.println("SeaMonster can attack (" + targetRow + ", " + targetCol + ")"); } else { System.out.println("SeaMonster cannot attack that square."); } } }
User prompt
The sea monster moves a maximum of 3 squares on the sea squares, and does not move from its place when it eats the pieces it threatens
User prompt
public class SeaMonster { // Define sea area (rows where the SeaMonster is allowed to move) static final int SEA_ROW_START = 6; // inclusive static final int SEA_ROW_END = 7; // inclusive // Checks if a given square is inside the sea area public static boolean isInSea(int row) { return row >= SEA_ROW_START && row <= SEA_ROW_END; } // Checks if SeaMonster can move to the given square (within sea, max 3 squares) public static boolean canMove(int currentRow, int currentCol, int targetRow, int targetCol, int boardRows, int boardCols) { int rowDiff = Math.abs(targetRow - currentRow); int colDiff = Math.abs(targetCol - currentCol); // Movement must be within 3 squares in one direction (no diagonal movement) boolean isValidDistance = (rowDiff == 0 && colDiff > 0 && colDiff <= 3) || (colDiff == 0 && rowDiff > 0 && rowDiff <= 3); // Both start and target squares must be within the sea rows return isValidDistance && isInSea(currentRow) && isInSea(targetRow); } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; // Current position of SeaMonster int currentRow = 7; int currentCol = 2; // Target square to move to int targetRow = 6; int targetCol = 5; if (canMove(currentRow, currentCol, targetRow, targetCol, boardRows, boardCols)) { System.out.println("SeaMonster can move to (" + targetRow + ", " + targetCol + ")"); } else { System.out.println("SeaMonster cannot move to that square."); } } }
User prompt
public class SeaMonster { public enum Direction { UP, DOWN, LEFT, RIGHT } /** * Determines the SeaMonster's attack direction based on its board position. */ public static Direction determineDirection(int bottomRow, int col, int boardRows, int boardCols) { if (col <= 1) { return Direction.RIGHT; // If on the left edge, attack to the right } else if (col >= boardCols - 2) { return Direction.LEFT; // If on the right edge, attack to the left } else if (bottomRow <= 1) { return Direction.DOWN; // If near the top, attack downward } else { return Direction.UP; // Default: attack upward } } /** * Checks if the SeaMonster can attack the given target square. */ public static boolean canAttack(int bottomRow, int col, int targetRow, int targetCol, int boardRows, int boardCols) { Direction direction = determineDirection(bottomRow, col, boardRows, boardCols); int topRow = bottomRow - 1; // SeaMonster occupies two vertical squares switch (direction) { case UP: return (targetCol == col && targetRow < topRow && targetRow >= topRow - 3); case DOWN: return (targetCol == col && targetRow > bottomRow && targetRow <= bottomRow + 3); case RIGHT: return (targetRow == topRow && targetCol > col && targetCol <= col + 3); case LEFT: return (targetRow == topRow && targetCol < col && targetCol >= col - 3); default: return false; } } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; // SeaMonster occupies bottomRow and bottomRow - 1 int bottomRow = 6; int col = 0; // Placed on the left edge → attacks to the right // Example target square int targetRow = 5; int targetCol = 2; if (canAttack(bottomRow, col, targetRow, targetCol, boardRows, boardCols)) { System.out.println("SeaMonster can attack the square at (" + targetRow + ", " + targetCol + ")"); } else { System.out.println("SeaMonster cannot attack that square."); } } }
User prompt
public class SeaCavara { public enum Direction { UP, DOWN, LEFT, RIGHT } // Determine attack direction based on board position public static Direction determineDirection(int bottomRow, int col, int boardRows, int boardCols) { if (col <= 1) { return Direction.RIGHT; // Sol kenardaysa sağa saldır } else if (col >= boardCols - 2) { return Direction.LEFT; // Sağ kenardaysa sola saldır } else if (bottomRow <= 1) { return Direction.DOWN; // Üstteyse aşağı saldır } else { return Direction.UP; // Varsayılan yukarı saldır } } // Check if the target square is in the 3-square attack zone public static boolean canAttack(int bottomRow, int col, int targetRow, int targetCol, int boardRows, int boardCols) { Direction dir = determineDirection(bottomRow, col, boardRows, boardCols); int topRow = bottomRow - 1; switch (dir) { case UP: return (targetCol == col && targetRow < topRow && targetRow >= topRow - 3); case DOWN: return (targetCol == col && targetRow > bottomRow && targetRow <= bottomRow + 3); case RIGHT: return (targetRow == topRow && targetCol > col && targetCol <= col + 3); case LEFT: return (targetRow == topRow && targetCol < col && targetCol >= col - 3); default: return false; } } public static void main(String[] args) { int boardRows = 8; int boardCols = 8; // Deniz Cavara'nın alt parçası (2 kare yukarıdan oluşur) int bottomRow = 6; int col = 0; // Sol kenardaysa sağa saldırı olur // Hedef kare int targetRow = 5; int targetCol = 2; if (canAttack(bottomRow, col, targetRow, targetCol, boardRows, boardCols)) { System.out.println("Sea Cavara can attack the square at (" + targetRow + ", " + targetCol + ")"); } else { System.out.println("Sea Cavara cannot attack that square."); } } }
User prompt
class Piece { String type; String color; public Piece(String type, String color) { this.type = type; this.color = color; } } public class ChessBoard { Piece[][] board = new Piece[12][12]; // or your board size int seaMonsterRow, seaMonsterCol; int lastDirRow = 1; // Vertical movement direction (-1 up, 1 down, 0 none) int lastDirCol = 0; // Horizontal movement direction (-1 left, 1 right, 0 none) // Call this to set sea monster position and last move direction public void setSeaMonsterPosition(int row, int col, int dirRow, int dirCol) { seaMonsterRow = row; seaMonsterCol = col; lastDirRow = dirRow; lastDirCol = dirCol; } public void seaMonsterAttack(String seaMonsterColor) { // Determine base attack position 3 squares ahead in last move direction int baseRow = seaMonsterRow + 3 * lastDirRow; int baseCol = seaMonsterCol + 3 * lastDirCol; // Determine diagonal attack directions depending on side of board // Default diagonal directions (1 square diagonally left and right) int diagDirRow = lastDirRow; int diagDirCol = 0; // Adjust diagonal attack pattern based on sea monster’s position on board if (seaMonsterCol <= 3) { // Left side of board (example threshold) // Attack pattern changes to 3 squares right and diagonals to right baseRow = seaMonsterRow + 3 * lastDirRow; baseCol = seaMonsterCol + 3 * 1; // 3 right diagDirCol = 1; // diagonal to the right } else if (seaMonsterCol >= board[0].length - 4) { // Right side // Attack pattern changes to 3 squares left and diagonals to left baseRow = seaMonsterRow + 3 * lastDirRow; baseCol = seaMonsterCol + 3 * -1; // 3 left diagDirCol = -1; // diagonal to the left } else if (seaMonsterRow <= 3) { // Top side // Attack pattern changes to 3 squares down-left, diagonal down-left, etc. baseRow = seaMonsterRow + 3 * 1; // 3 down baseCol = seaMonsterCol + 3 * -1; // 3 left diagDirRow = 1; // down diagDirCol = -1; // left diagonal } // else keep diagDirRow and diagDirCol as per last move direction // Define attack positions relative to base point: // 1) 1 square diagonal int attackRow1 = baseRow + diagDirRow; int attackCol1 = baseCol + diagDirCol; // 2) 1 square diagonal + 1 forward (in last move direction) int attackRow2 = attackRow1 + lastDirRow; int attackCol2 = attackCol1 + lastDirCol; // 3) 1 square diagonal + 2 forward int attackRow3 = attackRow1 + 2 * lastDirRow; int attackCol3 = attackCol1 + 2 * lastDirCol; // Positions to check int[][] attackPositions = { {baseRow, baseCol}, {attackRow1, attackCol1}, {attackRow2, attackCol2}, {attackRow3, attackCol3} }; for (int[] pos : attackPositions) { int r = pos[0], c = pos[1]; if (isValidSquare(r, c)) { Piece target = board[r][c]; if (target != null && !target.color.equals(seaMonsterColor)) { System.out.println("Sea Monster attacks and captures at (" + r + ", " + c + ")"); board[r][c] = null; // Capture without moving } } } } boolean isValidSquare(int r, int c) { return r >= 0 && r < board.length && c >= 0 && c < board[0].length; } }
User prompt
Add to sea monster It can eat 3 squares ahead on the board and 1 square diagonally or 1 square diagonally 1 square ahead or 1 square diagonally 2 squares ahead in the direction it last moved. It performs this eating function without leaving the sea, i.e., it does not change its position
User prompt
Add to sea monster It should be counted as 2 squares in size and can move a maximum of 3 squares left, right, forward, or backward. It cannot move outside of the sea squares
User prompt
New Stone = Sea Monster Location = Behind the Guard Special Ability = Can move in water
User prompt
Move the white palace one square to the left.
User prompt
Add white palace back
User prompt
Add one more column to the side of the Black Palaces, and count the newly added columns as “Sea"
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ChessPiece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.pieceType = type;
self.pieceColor = color; // 0 = white, 1 = black
self.boardRow = row;
self.boardCol = col;
self.hasMoved = false;
self.isPromoted = false; // Track permanent promotion status for vizier
self.hasTeleported = false; // Track if pawn's pawn has used teleportation
self.mustExitSaray = false; // Track if piece must exit saray after capture
var pieceGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
if (color === 1) {
pieceGraphics.tint = 0x333333;
}
self.moveTo = function (newRow, newCol) {
self.boardRow = newRow;
self.boardCol = newCol;
self.hasMoved = true;
var boardPos = getBoardPosition(newRow, newCol);
tween(self, {
x: boardPos.x,
y: boardPos.y
}, {
duration: 300
});
};
self.getRawMoves = function () {
var moves = [];
var directions = [];
switch (self.pieceType) {
case 'pawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'rook':
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist < 11; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'bishop':
// Bishop can move one square orthogonally (row/column only)
var oneSquareOrthogonalDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
// Add one square moves in orthogonal directions only
for (var i = 0; i < oneSquareOrthogonalDirections.length; i++) {
var dir = oneSquareOrthogonalDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Bishop can also move as many squares as wanted diagonally (minimum 2) without jumping over friendly pieces
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
for (var dist = 2; dist < 11; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Check if path is blocked by any piece (friendly or enemy)
var pathBlocked = false;
for (var checkDist = 1; checkDist < dist; checkDist++) {
var checkRow = self.boardRow + dir.dr * checkDist;
var checkCol = self.boardCol + dir.dc * checkDist;
var pathPiece = getPieceAt(checkRow, checkCol);
if (pathPiece) {
pathBlocked = true;
break;
}
}
if (pathBlocked) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'queen':
// Vizier: restricted to one square, enhanced to eight squares when promoted
// Diagonal movement is closed at the beginning (only orthogonal moves allowed)
// When promoted, both orthogonal and diagonal moves are allowed
if (self.isPromoted) {
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
} else {
// Only orthogonal moves at the beginning (diagonals closed)
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
}
var maxDistance = self.isPromoted ? 8 : 1;
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist <= maxDistance; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'king':
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'knight':
var knightMoves = [{
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}, {
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
}, {
dr: 1,
dc: 2
}, {
dr: 1,
dc: -2
}, {
dr: -1,
dc: 2
}, {
dr: -1,
dc: -2
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'warElephant':
// Moves 1 or 2 steps row, column, and diagonal with jumping ability
// Elephant cannot be stopped by any pieces (friendly or enemy)
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist <= 2; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Elephant ignores all pieces and can move through them
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
// Continue moving even if there's a piece - elephant cannot be stopped
}
}
break;
case 'siegeTower':
// Must move 1 square in row/column, then 1 square diagonally
// Captures enemy pieces in its path
// siegeTower cannot be stopped by enemies
var orthogonalDirections = [{
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}];
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
// Try L-shaped moves: orthogonal then diagonal
for (var i = 0; i < orthogonalDirections.length; i++) {
var orthDir = orthogonalDirections[i];
var firstRow = self.boardRow + orthDir.dr;
var firstCol = self.boardCol + orthDir.dc;
if (!isValidSquare(firstRow, firstCol)) {
continue;
}
var firstPiece = getPieceAt(firstRow, firstCol);
// siegeTower cannot be stopped by enemies, but friendly pieces still block
if (firstPiece && firstPiece.pieceColor === self.pieceColor) {
// Can't move through friendly piece, skip this direction
continue;
}
// Try diagonal moves from the orthogonal position
for (var j = 0; j < diagonalDirections.length; j++) {
var diagDir = diagonalDirections[j];
var finalRow = firstRow + diagDir.dr;
var finalCol = firstCol + diagDir.dc;
if (!isValidSquare(finalRow, finalCol)) {
continue;
}
var finalPiece = getPieceAt(finalRow, finalCol);
if (!finalPiece || finalPiece.pieceColor !== self.pieceColor) {
var moveData = {
row: finalRow,
col: finalCol,
capturesInPath: []
};
// Add captured pieces in path
if (firstPiece && firstPiece.pieceColor !== self.pieceColor) {
moveData.capturesInPath.push({
row: firstRow,
col: firstCol
});
}
if (finalPiece && finalPiece.pieceColor !== self.pieceColor) {
moveData.capturesInPath.push({
row: finalRow,
col: finalCol
});
}
moves.push(moveData);
}
}
}
// If friendly piece in orthogonal path, allow simple orthogonal move
for (var i = 0; i < orthogonalDirections.length; i++) {
var orthDir = orthogonalDirections[i];
var newRow = self.boardRow + orthDir.dr;
var newCol = self.boardCol + orthDir.dc;
if (!isValidSquare(newRow, newCol)) {
continue;
}
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
break;
case 'minister':
// Minister: 1 square diagonally, when promoted moves like rook and knight with jumping
if (self.isPromoted) {
// Rook-like moves (can jump over pieces when promoted)
var rookDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < rookDirections.length; i++) {
var dir = rookDirections[i];
for (var dist = 1; dist < 11; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// Knight-like moves (can jump over pieces)
var knightMoves = [{
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}, {
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
}, {
dr: 1,
dc: 2
}, {
dr: 1,
dc: -2
}, {
dr: -1,
dc: 2
}, {
dr: -1,
dc: -2
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
} else {
// Standard minister: 1 square diagonally
directions = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
}
break;
case 'royalGuard':
// Up to 3 squares diagonally with blockage of friendly pieces
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
for (var dist = 1; dist <= 3; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// Only 2 squares along rows and columns (no 1-step moves)
var orthogonalDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < orthogonalDirections.length; i++) {
var dir = orthogonalDirections[i];
// Only allow 2-step moves in orthogonal directions
var dist = 2;
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Forward or backward L-shaped moves (no left/right L moves)
var lShapeMoves = [
// Forward L-shapes
{
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
},
// Backward L-shapes
{
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}];
for (var i = 0; i < lShapeMoves.length; i++) {
var move = lShapeMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'giraffe':
// Giraffe: one diagonal move followed by 3-10 straight moves with obstacle checking
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var diagDir = diagonalDirections[i];
var firstRow = self.boardRow + diagDir.dr;
var firstCol = self.boardCol + diagDir.dc;
if (!isValidSquare(firstRow, firstCol)) {
continue;
}
var firstPiece = getPieceAt(firstRow, firstCol);
if (firstPiece) {
continue; // First diagonal square must be empty
}
// Determine straight directions based on diagonal direction
var straightDirections = [];
if (diagDir.dr > 0) {
straightDirections.push({
dr: 1,
dc: 0
}); // downward
}
if (diagDir.dr < 0) {
straightDirections.push({
dr: -1,
dc: 0
}); // upward
}
if (diagDir.dc > 0) {
straightDirections.push({
dr: 0,
dc: 1
}); // rightward
}
if (diagDir.dc < 0) {
straightDirections.push({
dr: 0,
dc: -1
}); // leftward
}
// Try straight moves from 3 to 10 squares in each valid direction
for (var j = 0; j < straightDirections.length; j++) {
var straightDir = straightDirections[j];
for (var step = 3; step <= 10; step++) {
var newRow = firstRow + straightDir.dr * step;
var newCol = firstCol + straightDir.dc * step;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Check if path is clear from diagonal position to target
var pathClear = true;
for (var checkStep = 1; checkStep <= step; checkStep++) {
var checkRow = firstRow + straightDir.dr * checkStep;
var checkCol = firstCol + straightDir.dc * checkStep;
var checkPiece = getPieceAt(checkRow, checkCol);
if (checkPiece) {
if (checkStep === step && checkPiece.pieceColor !== self.pieceColor) {
// Can capture enemy piece at final position
moves.push({
row: newRow,
col: newCol
});
}
pathClear = false;
break;
}
}
if (pathClear) {
moves.push({
row: newRow,
col: newCol
});
}
if (!pathClear) {
break; // Stop checking longer distances in this direction
}
}
}
}
break;
case 'bull':
// Bull can move one column forward or backward
var columnDirections = [{
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < columnDirections.length; i++) {
var colDir = columnDirections[i];
var newRow = self.boardRow + colDir.dr;
var newCol = self.boardCol + colDir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Bull moves one square forward or backward in column, then unlimited diagonal movement in same direction
for (var i = 0; i < columnDirections.length; i++) {
var colDir = columnDirections[i];
var firstRow = self.boardRow + colDir.dr;
var firstCol = self.boardCol + colDir.dc;
if (!isValidSquare(firstRow, firstCol)) {
continue;
}
var firstPiece = getPieceAt(firstRow, firstCol);
if (firstPiece) {
continue; // First square must be empty for bull movement
}
// From the first square, move diagonally unlimited in the forward/backward direction
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var j = 0; j < diagonalDirections.length; j++) {
var diagDir = diagonalDirections[j];
// Only allow diagonal movement in same forward/backward direction as column move
if (colDir.dr > 0 && diagDir.dr <= 0 || colDir.dr < 0 && diagDir.dr >= 0) {
continue; // Skip diagonal directions that don't match column direction
}
// Move unlimited squares diagonally from first position
for (var dist = 1; dist < 11; dist++) {
var finalRow = firstRow + diagDir.dr * dist;
var finalCol = firstCol + diagDir.dc * dist;
if (!isValidSquare(finalRow, finalCol)) {
break;
}
var finalPiece = getPieceAt(finalRow, finalCol);
if (finalPiece) {
if (finalPiece.pieceColor !== self.pieceColor) {
moves.push({
row: finalRow,
col: finalCol
});
}
break;
}
moves.push({
row: finalRow,
col: finalCol
});
}
}
}
// Bull can also jump two squares left and right
var leftRightJumps = [{
dr: 0,
dc: 2
}, {
dr: 0,
dc: -2
}];
for (var i = 0; i < leftRightJumps.length; i++) {
var jump = leftRightJumps[i];
var newRow = self.boardRow + jump.dr;
var newCol = self.boardCol + jump.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'camel':
// 1 square column and row (orthogonal moves)
var orthogonalDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var i = 0; i < orthogonalDirections.length; i++) {
var dir = orthogonalDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// 1 square long L (knight-like moves)
var knightMoves = [{
dr: 3,
dc: 1
}, {
dr: 3,
dc: -1
}, {
dr: -3,
dc: 1
}, {
dr: -3,
dc: -1
}, {
dr: 1,
dc: 3
}, {
dr: 1,
dc: -3
}, {
dr: -1,
dc: 3
}, {
dr: -1,
dc: -3
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = self.boardRow + move.dr;
var newCol = self.boardCol + move.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'lion':
// Lion has three distinct movement patterns:
// 1. Move 3 squares diagonally in one direction
// 2. L-shaped moves (forward/backward 2 + right/left 1)
// 3. Move 2 diagonally + 1 forward/backward
// 1st Move: 3 squares diagonally (similar to original code)
var diagonalDirections = [{
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
var pathBlocked = false;
for (var dist = 1; dist <= 3; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// 2nd Move: L-shaped moves (forward/backward 2 + right/left 1)
var lShapeMoves = [{
dr: -2,
dc: 1
}, {
dr: -2,
dc: -1
}, {
dr: 2,
dc: 1
}, {
dr: 2,
dc: -1
}];
for (var i = 0; i < lShapeMoves.length; i++) {
var move = lShapeMoves[i];
var midRow = self.boardRow + move.dr / 2;
var endRow = self.boardRow + move.dr;
var endCol = self.boardCol + move.dc;
// Check if vertical path is clear (first two squares)
if (!isValidSquare(midRow, self.boardCol) || getPieceAt(midRow, self.boardCol)) {
continue;
}
// Check for diagonal obstacles
var diagonalBlocked = false;
if (move.dr < 0) {
// moving up
if (move.dc == -1 && getPieceAt(self.boardRow - 1, self.boardCol - 1)) {
diagonalBlocked = true;
}
if (move.dc == 1 && getPieceAt(self.boardRow - 1, self.boardCol + 1)) {
diagonalBlocked = true;
}
} else {
// moving down
if (move.dc == -1 && getPieceAt(self.boardRow + 1, self.boardCol - 1)) {
diagonalBlocked = true;
}
if (move.dc == 1 && getPieceAt(self.boardRow + 1, self.boardCol + 1)) {
diagonalBlocked = true;
}
}
if (diagonalBlocked) {
continue;
}
if (isValidSquare(endRow, endCol)) {
var piece = getPieceAt(endRow, endCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: endRow,
col: endCol
});
}
}
}
// 3rd Move: 2 diagonals + 1 forward/backward
for (var i = 0; i < diagonalDirections.length; i++) {
var dir = diagonalDirections[i];
var pathBlocked = false;
// Check if we can move 2 squares diagonally
for (var checkDist = 1; checkDist <= 2; checkDist++) {
var checkRow = self.boardRow + dir.dr * checkDist;
var checkCol = self.boardCol + dir.dc * checkDist;
if (!isValidSquare(checkRow, checkCol)) {
pathBlocked = true;
break;
}
var pathPiece = getPieceAt(checkRow, checkCol);
if (pathPiece) {
pathBlocked = true;
break;
}
}
if (pathBlocked) {
continue;
}
var twoSquareRow = self.boardRow + dir.dr * 2;
var twoSquareCol = self.boardCol + dir.dc * 2;
// Then move 1 square forward or backward
var verticalMoves = [{
dr: -1,
dc: 0
}, {
dr: 1,
dc: 0
}];
for (var j = 0; j < verticalMoves.length; j++) {
var vertMove = verticalMoves[j];
var finalRow = twoSquareRow + vertMove.dr;
var finalCol = twoSquareCol + vertMove.dc;
if (isValidSquare(finalRow, finalCol)) {
var piece = getPieceAt(finalRow, finalCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: finalRow,
col: finalCol
});
}
}
}
}
// Remove side L-shaped moves from the moves list
moves = moves.filter(function (move) {
return !isSideLMove(self.boardRow, self.boardCol, move.row, move.col);
});
break;
case 'pawnOfTheWarMachine':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheWarMachine' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'camelPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'camelPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'ministersPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'ministersPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnOfTheElephant':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheElephant' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'shahsade':
// King-like movement: 1 square in any direction
var kingDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < kingDirections.length; i++) {
var dir = kingDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// 2 squares diagonally, horizontally, vertically
var shahsadeDirections = [{
dr: 0,
dc: 2
}, {
dr: 0,
dc: -2
}, {
dr: 2,
dc: 0
}, {
dr: -2,
dc: 0
}, {
dr: 2,
dc: 2
}, {
dr: 2,
dc: -2
}, {
dr: -2,
dc: 2
}, {
dr: -2,
dc: -2
}];
for (var i = 0; i < shahsadeDirections.length; i++) {
var dir = shahsadeDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
// Check if path is blocked by any piece
var pathBlocked = false;
var stepRow = dir.dr === 0 ? 0 : dir.dr > 0 ? 1 : -1;
var stepCol = dir.dc === 0 ? 0 : dir.dc > 0 ? 1 : -1;
var checkRow = self.boardRow + stepRow;
var checkCol = self.boardCol + stepCol;
var pathPiece = getPieceAt(checkRow, checkCol);
if (pathPiece) {
pathBlocked = true;
}
if (!pathBlocked) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
}
break;
case 'adventurousKing':
// King-like movement: 1 square in any direction
var kingDirections = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < kingDirections.length; i++) {
var dir = kingDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// 2 squares diagonally, horizontally, vertically (adventurous Shah can jump over pieces)
var adventurousKingDirections = [{
dr: 0,
dc: 2
}, {
dr: 0,
dc: -2
}, {
dr: 2,
dc: 0
}, {
dr: -2,
dc: 0
}, {
dr: 2,
dc: 2
}, {
dr: 2,
dc: -2
}, {
dr: -2,
dc: 2
}, {
dr: -2,
dc: -2
}];
for (var i = 0; i < adventurousKingDirections.length; i++) {
var dir = adventurousKingDirections[i];
var newRow = self.boardRow + dir.dr;
var newCol = self.boardCol + dir.dc;
if (isValidSquare(newRow, newCol)) {
// Adventurous Shah can jump over pieces - no path blocking check
var piece = getPieceAt(newRow, newCol);
if (!piece || piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
break;
case 'kingsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 7 : 2;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'kingsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'viziersPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'viziersPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'giraffePawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'giraffePawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'knightPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'knightPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'rookPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'rookPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnOfTheLeader':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheLeader' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'guardsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
// Forward move (no double move for Guard's Pawn)
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'guardsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnOfTheBull':
var direction = self.pieceColor === 0 ? -1 : 1;
// Forward move (no double move for Pawn of the Bull)
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnOfTheBull' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'lionsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
// Forward move (no double move for Lion's Pawn)
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'lionsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'pawnsPawn':
var direction = self.pieceColor === 0 ? -1 : 1;
var startRow = self.pieceColor === 0 ? 8 : 3;
// Forward move
if (isValidSquare(self.boardRow + direction, self.boardCol) && !getPieceAt(self.boardRow + direction, self.boardCol)) {
moves.push({
row: self.boardRow + direction,
col: self.boardCol
});
// Double move from start
if (self.boardRow === startRow && !getPieceAt(self.boardRow + 2 * direction, self.boardCol)) {
moves.push({
row: self.boardRow + 2 * direction,
col: self.boardCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = self.boardRow + direction;
var newCol = self.boardCol + dc;
if (isValidSquare(newRow, newCol)) {
var piece = getPieceAt(newRow, newCol);
if (piece && piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
}
// En passant
if (lastMove && lastMove.piece.pieceType === 'pawnsPawn' && Math.abs(lastMove.fromRow - lastMove.toRow) === 2) {
if (lastMove.toRow === self.boardRow && Math.abs(lastMove.toCol - self.boardCol) === 1) {
moves.push({
row: self.boardRow + direction,
col: lastMove.toCol,
isEnPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
break;
case 'seaMonster':
// Sea Monster can only move on sea squares, maximum 3 squares
directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}, {
dr: 1,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: -1,
dc: 1
}, {
dr: -1,
dc: -1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
for (var dist = 1; dist <= 3; dist++) {
var newRow = self.boardRow + dir.dr * dist;
var newCol = self.boardCol + dir.dc * dist;
if (!isValidSquare(newRow, newCol)) {
break;
}
// Sea Monster can only move to sea squares
if (!isSeaSquare(newRow, newCol)) {
break;
}
var piece = getPieceAt(newRow, newCol);
if (piece) {
if (piece.pieceColor !== self.pieceColor) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
moves.push({
row: newRow,
col: newCol
});
}
}
// Sea Monster attack capability - complex attack pattern
// Only attack if in sea (rows 6-7 based on the constant)
if (self.boardRow >= 6 && self.boardRow <= 7) {
var attackMoves = [];
var monsterRow = self.boardRow;
var monsterCol = self.boardCol;
// Check all possible attack squares based on complex pattern
for (var targetRow = 0; targetRow < BOARD_HEIGHT; targetRow++) {
for (var targetCol = -1; targetCol < BOARD_WIDTH; targetCol++) {
if (!isValidSquare(targetRow, targetCol)) continue;
if (targetRow === monsterRow && targetCol === monsterCol) continue;
var rowDiff = targetRow - monsterRow;
var colDiff = targetCol - monsterCol;
var absRow = Math.abs(rowDiff);
var absCol = Math.abs(colDiff);
var canAttack = false;
// Diagonal attacks (1 square)
if (absRow === 1 && absCol === 1) {
canAttack = true;
}
// Straight line attacks (1-3 squares)
else if (absRow === 0 && absCol >= 1 && absCol <= 3 || absCol === 0 && absRow >= 1 && absRow <= 3) {
canAttack = true;
}
// Wide L-shape: 2 horizontal + 1 vertical
else if (absCol === 2 && absRow === 1) {
canAttack = true;
}
// Special Left-3 zone
else if (targetCol === monsterCol - 3 && (targetRow === monsterRow || targetRow === monsterRow - 1 || targetRow === monsterRow + 1)) {
canAttack = true;
}
if (canAttack) {
var targetPiece = getPieceAt(targetRow, targetCol);
if (!targetPiece || targetPiece.pieceColor !== self.pieceColor) {
attackMoves.push({
row: targetRow,
col: targetCol,
isSeaMonsterAttack: true
});
}
}
}
}
// Add attack moves to regular moves
for (var i = 0; i < attackMoves.length; i++) {
moves.push(attackMoves[i]);
}
}
break;
}
// Filter out sea squares - pieces cannot enter the sea (except sea monster)
var filteredMoves = [];
for (var i = 0; i < moves.length; i++) {
if (!isSeaSquare(moves[i].row, moves[i].col) || self.pieceType === 'seaMonster') {
filteredMoves.push(moves[i]);
}
}
return filteredMoves;
};
self.getValidMoves = function () {
var moves = self.getRawMoves();
// Add castling for king after getting raw moves
if (self.pieceType === 'king' && !self.hasMoved && !isInCheck(self.pieceColor)) {
// Kingside castling - rook is at col + 5 (distance from king to rook)
var kingsideRook = getPieceAt(self.boardRow, self.boardCol + 5);
if (kingsideRook && kingsideRook.pieceType === 'rook' && !kingsideRook.hasMoved) {
var canCastle = true;
// Check squares between king and rook are empty and not attacked
for (var c = self.boardCol + 1; c < self.boardCol + 5; c++) {
if (getPieceAt(self.boardRow, c) || isSquareAttacked(self.boardRow, c, 1 - self.pieceColor)) {
canCastle = false;
break;
}
}
if (canCastle) {
moves.push({
row: self.boardRow,
col: self.boardCol + 2,
isCastling: true,
rookFromCol: self.boardCol + 5,
rookToCol: self.boardCol + 1
});
}
}
// Queenside castling - rook is at col - 5 (distance from king to rook)
var queensideRook = getPieceAt(self.boardRow, self.boardCol - 5);
if (queensideRook && queensideRook.pieceType === 'rook' && !queensideRook.hasMoved) {
var canCastle = true;
// Check squares between king and rook are empty and not attacked
for (var c = self.boardCol - 1; c > self.boardCol - 5; c--) {
if (getPieceAt(self.boardRow, c) || isSquareAttacked(self.boardRow, c, 1 - self.pieceColor)) {
canCastle = false;
break;
}
}
if (canCastle) {
moves.push({
row: self.boardRow,
col: self.boardCol - 2,
isCastling: true,
rookFromCol: self.boardCol - 5,
rookToCol: self.boardCol - 1
});
}
}
}
// Filter moves that would leave the king in check
var validMoves = [];
for (var i = 0; i < moves.length; i++) {
if (isValidMoveConsideringCheck(self, moves[i].row, moves[i].col)) {
// Additional check for sea squares - pieces cannot enter the sea (except sea monster)
if (isSeaSquare(moves[i].row, moves[i].col) && self.pieceType !== 'seaMonster') {
continue; // Skip sea squares
}
// Additional check for palace entry
if (isPalaceSquare(moves[i].row, moves[i].col)) {
if (canEnterPalace(self, moves[i].row, moves[i].col)) {
validMoves.push(moves[i]);
}
} else {
validMoves.push(moves[i]);
}
}
}
return validMoves;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var BOARD_WIDTH = 15;
var BOARD_HEIGHT = 12;
var SQUARE_SIZE = 140;
var BOARD_START_X = (2048 - BOARD_WIDTH * SQUARE_SIZE) / 2;
var BOARD_START_Y = (2732 - BOARD_HEIGHT * SQUARE_SIZE) / 2 + 100;
var boardSquares = [];
var pieces = [];
var selectedPiece = null;
var highlightedSquares = [];
var currentPlayer = 0; // 0 = white, 1 = black
var gameStarted = false;
var lastMove = null;
var shahsadePromoted = [false, false]; // Track if shahsade has been promoted for each player
var pawnsPawnHasUsedSpecialMove = []; // Track which pawn's pawns have used their special move
var pawnsPawnMovementCount = []; // Track how many squares each pawn's pawn has moved
var shahPositionSwapUsed = [false, false]; // Track if Shah position swap has been used for each player
var swapHighlights = []; // Track swap highlight squares
function getBoardPosition(row, col) {
return {
x: BOARD_START_X + (col + 1) * SQUARE_SIZE + SQUARE_SIZE / 2,
y: BOARD_START_Y + row * SQUARE_SIZE + SQUARE_SIZE / 2
};
}
function getBoardCoordinates(x, y) {
var col = Math.floor((x - BOARD_START_X) / SQUARE_SIZE) - 1;
var row = Math.floor((y - BOARD_START_Y) / SQUARE_SIZE);
return {
row: row,
col: col
};
}
function positionToAlgebraic(row, col) {
var files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'];
var ranks = ['10', '9', '8', '7', '6', '5', '4', '3', '2', '1'];
return files[col] + ranks[row];
}
function pieceToNotation(pieceType) {
var notationMap = {
'king': 'K',
'adventurousKing': 'AK',
'queen': 'V',
'rook': 'R',
'bishop': 'F',
'knight': 'N',
'warElephant': 'E',
'siegeTower': 'W',
'minister': 'F',
'royalGuard': 'RG',
'giraffe': 'G',
'bull': 'T',
'camel': 'C',
'lion': 'L',
'shahsade': 'K',
'pawn': 'PPP',
'pawnOfTheWarMachine': 'WP',
'camelPawn': 'CP',
'ministersPawn': 'FP',
'pawnOfTheElephant': 'EP',
'kingsPawn': 'KP',
'viziersPawn': 'VP',
'giraffePawn': 'GP',
'knightPawn': 'NP',
'rookPawn': 'RP',
'pawnOfTheLeader': 'BP',
'guardsPawn': 'RGP',
'pawnOfTheBull': 'TP',
'lionsPawn': 'LP',
'pawnsPawn': 'PP',
'seaMonster': 'SM'
};
return notationMap[pieceType] || '';
}
function isValidSquare(row, col) {
return row >= 0 && row < BOARD_HEIGHT && col >= -1 && col < BOARD_WIDTH;
}
function isSeaSquare(row, col) {
// Column -1 (column -1) squares are all sea (new column to the left of black palace)
// Column A (column 0) squares are sea except for the palace at row 2
// Column M (column 12) squares are all sea
// Column N (column 13) squares are sea except for the palace at row 9
// Column O (column 14) squares are all sea
// Row 0 is sea for all columns
// Row 11 is sea for all columns
return col === -1 || col === 0 && row !== 2 || col === 12 && row !== 9 || col === 13 || col === 14 || row === 0 || row === 11;
}
function getPieceAt(row, col) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].boardRow === row && pieces[i].boardCol === col) {
return pieces[i];
}
}
return null;
}
function createBoard() {
for (var row = 0; row < BOARD_HEIGHT; row++) {
boardSquares[row] = [];
for (var col = -1; col < BOARD_WIDTH; col++) {
// Sea rows: row 0 (above black pieces) and row 11 (below white pieces)
if (row === 0 || row === 11) {
// Create sea squares for top and bottom rows
var isLight = (row + col) % 2 === 0;
var squareAsset = isLight ? 'seaTextureLight' : 'seaTextureDark';
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
square.isSea = true; // Mark as sea square
boardSquares[row][col] = square;
continue;
}
// Column -1 squares - create sea squares for all rows in column -1
if (col === -1) {
// All squares in column -1 are sea
var isLight = (row + col) % 2 === 0;
var squareAsset = isLight ? 'seaTextureLight' : 'seaTextureDark';
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
square.isSea = true; // Mark as sea square
boardSquares[row][col] = square;
continue;
}
// Column A squares - create squares for all valid rows in column 0
if (col === 0) {
// Only row 2 has the black palace, other rows get regular squares
if (row !== 2) {
// Create sea squares for other rows in column A with separate textures
var isLight = (row + col) % 2 === 0;
var squareAsset = isLight ? 'seaTextureLight' : 'seaTextureDark';
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
square.isSea = true; // Mark as sea square
boardSquares[row][col] = square;
continue;
}
}
// Column M squares - create squares for all valid rows in column 12
if (col === 12) {
// Only row 9 has the white palace, other rows get sea squares
if (row !== 9) {
// Create sea squares for other rows in column M with separate textures
var isLight = (row + col) % 2 === 0;
var squareAsset = isLight ? 'seaTextureLight' : 'seaTextureDark';
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
square.isSea = true; // Mark as sea square
boardSquares[row][col] = square;
continue;
}
}
// Column N squares - create sea squares for all rows in column 13
if (col === 13) {
// All squares in column N are sea
var isLight = (row + col) % 2 === 0;
var squareAsset = isLight ? 'seaTextureLight' : 'seaTextureDark';
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
square.isSea = true; // Mark as sea square
boardSquares[row][col] = square;
continue;
}
// Column O squares - create sea squares for all rows in column 14
if (col === 14) {
// All squares in column O are sea
var isLight = (row + col) % 2 === 0;
var squareAsset = isLight ? 'seaTextureLight' : 'seaTextureDark';
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
square.isSea = true; // Mark as sea square
boardSquares[row][col] = square;
continue;
}
// Create squares for all rows in column 12
// Special case: Black Palace at column 0, row 2 (left of a10)
// Special case: White Palace at column 13, row 9 (right of l11)
var squareAsset;
if (col === 0 && row === 2) {
squareAsset = 'blackPalace';
} else if (col === 12 && row === 9) {
squareAsset = 'whitePalace';
} else {
var isLight = (row + col) % 2 === 0;
squareAsset = isLight ? 'lightSquare' : 'darkSquare';
}
var square = game.addChild(LK.getAsset(squareAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
var pos = getBoardPosition(row, col);
square.x = pos.x;
square.y = pos.y;
square.boardRow = row;
square.boardCol = col;
boardSquares[row][col] = square;
}
}
}
function createPieces() {
// Create pieces for both players
var pieceSetup = [
// White pieces (bottom)
{
type: 'rook',
color: 0,
row: 9,
col: 1
}, {
type: 'knight',
color: 0,
row: 9,
col: 2
}, {
type: 'warElephant',
color: 0,
row: 10,
col: 1
}, {
type: 'warElephant',
color: 0,
row: 10,
col: 11
}, {
type: 'bishop',
color: 0,
row: 9,
col: 3
}, {
type: 'minister',
color: 0,
row: 9,
col: 5
}, {
type: 'king',
color: 0,
row: 9,
col: 6
}, {
type: 'bishop',
color: 0,
row: 9,
col: 9
}, {
type: 'siegeTower',
color: 0,
row: 10,
col: 7
}, {
type: 'siegeTower',
color: 0,
row: 10,
col: 5
}, {
type: 'queen',
color: 0,
row: 9,
col: 7
}, {
type: 'giraffe',
color: 0,
row: 9,
col: 4
}, {
type: 'giraffe',
color: 0,
row: 9,
col: 8
}, {
type: 'knight',
color: 0,
row: 9,
col: 10
}, {
type: 'rook',
color: 0,
row: 9,
col: 11
},
// White royal guards
{
type: 'royalGuard',
color: 0,
row: 10,
col: 6
},
// White sea monster (behind royal guard)
{
type: 'seaMonster',
color: 0,
row: 11,
col: 6
},
// White lions
{
type: 'lion',
color: 0,
row: 10,
col: 2
}, {
type: 'lion',
color: 0,
row: 10,
col: 10
},
// White camels
{
type: 'camel',
color: 0,
row: 10,
col: 3
}, {
type: 'camel',
color: 0,
row: 10,
col: 9
},
// White bulls
{
type: 'bull',
color: 0,
row: 10,
col: 4
}, {
type: 'bull',
color: 0,
row: 10,
col: 8
},
// Black pieces (top) - all moved down by 1 row
{
type: 'rook',
color: 1,
row: 2,
col: 1
}, {
type: 'knight',
color: 1,
row: 2,
col: 2
}, {
type: 'warElephant',
color: 1,
row: 1,
col: 1
}, {
type: 'warElephant',
color: 1,
row: 1,
col: 11
}, {
type: 'bishop',
color: 1,
row: 2,
col: 3
}, {
type: 'minister',
color: 1,
row: 2,
col: 7
}, {
type: 'king',
color: 1,
row: 2,
col: 6
}, {
type: 'bishop',
color: 1,
row: 2,
col: 9
}, {
type: 'siegeTower',
color: 1,
row: 1,
col: 7
}, {
type: 'siegeTower',
color: 1,
row: 1,
col: 5
}, {
type: 'queen',
color: 1,
row: 2,
col: 5
}, {
type: 'giraffe',
color: 1,
row: 2,
col: 4
}, {
type: 'giraffe',
color: 1,
row: 2,
col: 8
}, {
type: 'knight',
color: 1,
row: 2,
col: 10
}, {
type: 'rook',
color: 1,
row: 2,
col: 11
},
// Black royal guards
{
type: 'royalGuard',
color: 1,
row: 1,
col: 6
},
// Black sea monster (behind royal guard)
{
type: 'seaMonster',
color: 1,
row: 0,
col: 6
},
// Black lions
{
type: 'lion',
color: 1,
row: 1,
col: 2
}, {
type: 'lion',
color: 1,
row: 1,
col: 10
},
// Black camels
{
type: 'camel',
color: 1,
row: 1,
col: 3
}, {
type: 'camel',
color: 1,
row: 1,
col: 9
},
// Black bulls
{
type: 'bull',
color: 1,
row: 1,
col: 4
}, {
type: 'bull',
color: 1,
row: 1,
col: 8
}];
// Add Pawn of the War Machine for each side
pieceSetup.push({
type: 'pawnOfTheWarMachine',
color: 0,
row: 8,
col: 2
}); // White Pawn of the War Machine
pieceSetup.push({
type: 'pawnOfTheWarMachine',
color: 1,
row: 3,
col: 10
}); // Black Pawn of the War Machine
// Add Camel Pawn for each side
pieceSetup.push({
type: 'camelPawn',
color: 0,
row: 8,
col: 3
}); // White Camel Pawn
pieceSetup.push({
type: 'camelPawn',
color: 1,
row: 3,
col: 9
}); // Black Camel Pawn
// Add Pawn of the Elephant for each side
pieceSetup.push({
type: 'pawnOfTheElephant',
color: 0,
row: 8,
col: 4
}); // White Pawn of the Elephant
pieceSetup.push({
type: 'pawnOfTheElephant',
color: 1,
row: 3,
col: 8
}); // Black Pawn of the Elephant
// Add Minister's Pawn for each side
pieceSetup.push({
type: 'ministersPawn',
color: 0,
row: 8,
col: 5
}); // White Minister's Pawn
pieceSetup.push({
type: 'ministersPawn',
color: 1,
row: 3,
col: 7
}); // Black Minister's Pawn
// Add King's Pawn for each side
pieceSetup.push({
type: 'kingsPawn',
color: 0,
row: 8,
col: 6
}); // White King's Pawn
pieceSetup.push({
type: 'kingsPawn',
color: 1,
row: 3,
col: 6
}); // Black King's Pawn
// Add Vizier's Pawn for each side
pieceSetup.push({
type: 'viziersPawn',
color: 0,
row: 8,
col: 7
}); // White Vizier's Pawn
pieceSetup.push({
type: 'viziersPawn',
color: 1,
row: 3,
col: 5
}); // Black Vizier's Pawn
// Add Giraffe Pawn for each side
pieceSetup.push({
type: 'giraffePawn',
color: 0,
row: 8,
col: 8
}); // White Giraffe Pawn
pieceSetup.push({
type: 'giraffePawn',
color: 1,
row: 3,
col: 4
}); // Black Giraffe Pawn
// Add Knight Pawn for each side
pieceSetup.push({
type: 'knightPawn',
color: 0,
row: 8,
col: 10
}); // White Knight Pawn
pieceSetup.push({
type: 'knightPawn',
color: 1,
row: 3,
col: 2
}); // Black Knight Pawn
// Add Rook Pawn for each side
pieceSetup.push({
type: 'rookPawn',
color: 0,
row: 8,
col: 11
}); // White Rook Pawn
pieceSetup.push({
type: 'rookPawn',
color: 1,
row: 3,
col: 1
}); // Black Rook Pawn
// Add Pawn of the Leader for each side
pieceSetup.push({
type: 'pawnOfTheLeader',
color: 0,
row: 8,
col: 9
}); // White Pawn of the Leader
pieceSetup.push({
type: 'pawnOfTheLeader',
color: 1,
row: 3,
col: 3
}); // Black Pawn of the Leader
// Add Guard's Pawn for each side - in front of the King's Pawn
pieceSetup.push({
type: 'guardsPawn',
color: 0,
row: 7,
col: 6
}); // White Guard's Pawn (in front of White King's Pawn)
pieceSetup.push({
type: 'guardsPawn',
color: 1,
row: 4,
col: 6
}); // Black Guard's Pawn (in front of Black King's Pawn)
// Add Pawn of the Bull for each side - in front of the Pawn of the Leader
pieceSetup.push({
type: 'pawnOfTheBull',
color: 0,
row: 7,
col: 9
}); // White Pawn of the Bull (in front of White Pawn of the Leader)
pieceSetup.push({
type: 'pawnOfTheBull',
color: 1,
row: 4,
col: 3
}); // Black Pawn of the Bull (in front of Black Pawn of the Leader)
// Add Lion's Pawn for each side - in front of the Camel's Pawn
pieceSetup.push({
type: 'lionsPawn',
color: 0,
row: 7,
col: 3
}); // White Lion's Pawn (in front of White Camel Pawn)
pieceSetup.push({
type: 'lionsPawn',
color: 1,
row: 4,
col: 9
}); // Black Lion's Pawn (in front of Black Camel Pawn)
// Add regular pawn for each side
pieceSetup.push({
type: 'pawn',
color: 0,
row: 8,
col: 1
}); // White Pawn
pieceSetup.push({
type: 'pawn',
color: 1,
row: 3,
col: 11
}); // Black Pawn
for (var i = 0; i < pieceSetup.length; i++) {
var setup = pieceSetup[i];
var piece = game.addChild(new ChessPiece(setup.type, setup.color, setup.row, setup.col));
var pos = getBoardPosition(setup.row, setup.col);
piece.x = pos.x;
piece.y = pos.y;
pieces.push(piece);
}
}
function clearHighlights() {
for (var i = 0; i < highlightedSquares.length; i++) {
highlightedSquares[i].destroy();
}
highlightedSquares = [];
}
function clearSwapHighlights() {
for (var i = 0; i < swapHighlights.length; i++) {
swapHighlights[i].destroy();
}
swapHighlights = [];
}
function highlightMoves(moves) {
clearHighlights();
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
var assetName = move.isCastling ? 'castlingSquare' : 'highlightSquare';
var highlight = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
}));
var pos = getBoardPosition(move.row, move.col);
highlight.x = pos.x;
highlight.y = pos.y;
highlightedSquares.push(highlight);
}
}
function highlightSwappablePieces(swappablePieces) {
clearSwapHighlights();
for (var i = 0; i < swappablePieces.length; i++) {
var piece = swappablePieces[i];
var highlight = game.addChild(LK.getAsset('swapSquare', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
}));
var pos = getBoardPosition(piece.boardRow, piece.boardCol);
highlight.x = pos.x;
highlight.y = pos.y;
swapHighlights.push(highlight);
}
}
function selectPiece(piece) {
if (selectedPiece) {
selectedPiece.removeChild(selectedPiece.selectionHighlight);
selectedPiece.selectionHighlight = null;
}
selectedPiece = piece;
if (piece) {
piece.selectionHighlight = piece.addChild(LK.getAsset('selectedSquare', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
}));
var validMoves = piece.getValidMoves();
highlightMoves(validMoves);
// If selecting a Shah (king), also highlight swappable pieces
if (piece.pieceType === 'king') {
var swappablePieces = getSwappablePieces(piece);
highlightSwappablePieces(swappablePieces);
}
} else {
clearHighlights();
clearSwapHighlights();
}
}
function generateMoveNotation(piece, targetRow, targetCol, moveData, capturedPieces) {
var notation = '';
var pieceNotation = pieceToNotation(piece.pieceType);
var targetSquare = positionToAlgebraic(targetRow, targetCol);
// Handle special moves
if (moveData && moveData.isCastling) {
notation = targetCol > piece.boardCol ? 'O-O' : 'O-O-O';
} else {
// Add piece notation
notation += pieceNotation;
// Add capture notation
if (capturedPieces.length > 0) {
if (pieceNotation === '') {
// For pawn captures, add the file of origin
notation += positionToAlgebraic(piece.boardRow, piece.boardCol).charAt(0);
}
notation += 'x';
}
// Add destination square
notation += targetSquare;
}
return notation;
}
function makeMove(piece, targetRow, targetCol, moveData) {
var originalRow = piece.boardRow;
var originalCol = piece.boardCol;
// Check palace entry restrictions
if (isPalaceSquare(targetRow, targetCol)) {
if (!canEnterPalace(piece, targetRow, targetCol)) {
return; // Invalid move, cannot enter palace
}
}
var capturedPiece = null;
var capturedPieces = [];
// Handle special moves
if (moveData && moveData.isCastling) {
// Move the rook for castling
var rook = getPieceAt(originalRow, moveData.rookFromCol);
if (rook) {
rook.moveTo(originalRow, moveData.rookToCol);
}
} else if (moveData && moveData.isEnPassant) {
// Capture the pawn for en passant
capturedPiece = getPieceAt(moveData.captureRow, moveData.captureCol);
if (capturedPiece) {
capturedPieces.push(capturedPiece);
}
} else if (moveData && moveData.capturesInPath) {
// Handle siegeTower path captures
for (var k = 0; k < moveData.capturesInPath.length; k++) {
var capturePos = moveData.capturesInPath[k];
var pathPiece = getPieceAt(capturePos.row, capturePos.col);
if (pathPiece) {
capturedPieces.push(pathPiece);
}
}
} else {
capturedPiece = getPieceAt(targetRow, targetCol);
if (capturedPiece) {
capturedPieces.push(capturedPiece);
// Apply saray capture flag if needed
if (isSaray(targetRow, targetCol)) {
handleSarayCapture(piece, targetRow, targetCol);
}
}
}
// Remove all captured pieces
for (var k = 0; k < capturedPieces.length; k++) {
var capPiece = capturedPieces[k];
var index = pieces.indexOf(capPiece);
if (index > -1) {
pieces.splice(index, 1);
}
capPiece.destroy();
}
if (capturedPieces.length > 0) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
// Store move for en passant detection
lastMove = {
piece: piece,
fromRow: originalRow,
fromCol: originalCol,
toRow: targetRow,
toCol: targetCol
};
// Sea Monster doesn't move when attacking, only when moving to empty squares
if (piece.pieceType === 'seaMonster' && moveData && moveData.isSeaMonsterAttack) {
// Sea Monster stays in place when attacking, don't move the piece
} else {
piece.moveTo(targetRow, targetCol);
}
// Track movement for pawn's pawn
if (piece.pieceType === 'pawnsPawn') {
for (var mc = 0; mc < pawnsPawnMovementCount.length; mc++) {
if (pawnsPawnMovementCount[mc].piece === piece) {
pawnsPawnMovementCount[mc].moves++;
break;
}
}
}
// Check for vizier promotion
if (piece.pieceType === 'queen' && !piece.isPromoted) {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
piece.isPromoted = true;
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
}
}
// Check for minister promotion
if (piece.pieceType === 'minister' && !piece.isPromoted) {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
piece.isPromoted = true;
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x9932CC, 1000); // Flash purple
}
}
// Check for Pawn of the War Machine promotion
if (piece.pieceType === 'pawnOfTheWarMachine') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into siege tower
piece.pieceType = 'siegeTower';
// Change texture to siege tower
piece.removeChildAt(0); // Remove old texture
var siegeTowerGraphics = piece.attachAsset('siegeTower', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
siegeTowerGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x00FF00, 1000); // Flash green
}
}
// Check for Camel Pawn promotion
if (piece.pieceType === 'camelPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into camel
piece.pieceType = 'camel';
// Change texture to camel
piece.removeChildAt(0); // Remove old texture
var camelGraphics = piece.attachAsset('camel', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
camelGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFFF00, 1000); // Flash yellow
}
}
// Check for Minister's Pawn promotion
if (piece.pieceType === 'ministersPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into promoted minister
piece.pieceType = 'minister';
piece.isPromoted = true;
// Change texture to minister
piece.removeChildAt(0); // Remove old texture
var ministerGraphics = piece.attachAsset('minister', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
ministerGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x9932CC, 1000); // Flash purple
}
}
// Check for Pawn of the Elephant promotion
if (piece.pieceType === 'pawnOfTheElephant') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into war elephant
piece.pieceType = 'warElephant';
// Change texture to war elephant
piece.removeChildAt(0); // Remove old texture
var warElephantGraphics = piece.attachAsset('warElephant', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
warElephantGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x8B4513, 1000); // Flash brown
}
}
// Check for King's Pawn promotion
if (piece.pieceType === 'kingsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into shahsade
piece.pieceType = 'shahsade';
// Change texture to shahsade
piece.removeChildAt(0); // Remove old texture
var shahsadeGraphics = piece.attachAsset('shahsade', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
shahsadeGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFF4500, 1000); // Flash orange red
}
}
// Check for Vizier's Pawn promotion
if (piece.pieceType === 'viziersPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into promoted vizier
piece.pieceType = 'queen';
piece.isPromoted = true;
// Change texture to queen
piece.removeChildAt(0); // Remove old texture
var queenGraphics = piece.attachAsset('queen', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
queenGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
}
}
// Check for Giraffe Pawn promotion
if (piece.pieceType === 'giraffePawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into giraffe
piece.pieceType = 'giraffe';
// Change texture to giraffe
piece.removeChildAt(0); // Remove old texture
var giraffeGraphics = piece.attachAsset('giraffe', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
giraffeGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFA500, 1000); // Flash orange
}
}
// Check for Knight Pawn promotion
if (piece.pieceType === 'knightPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into knight
piece.pieceType = 'knight';
// Change texture to knight
piece.removeChildAt(0); // Remove old texture
var knightGraphics = piece.attachAsset('knight', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
knightGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x00CED1, 1000); // Flash dark turquoise
}
}
// Check for Rook Pawn promotion
if (piece.pieceType === 'rookPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into rook
piece.pieceType = 'rook';
// Change texture to rook
piece.removeChildAt(0); // Remove old texture
var rookGraphics = piece.attachAsset('rook', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
rookGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x0000FF, 1000); // Flash blue
}
}
// Check for Pawn of the Leader promotion
if (piece.pieceType === 'pawnOfTheLeader') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into bishop
piece.pieceType = 'bishop';
// Change texture to bishop
piece.removeChildAt(0); // Remove old texture
var bishopGraphics = piece.attachAsset('bishop', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
bishopGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x800080, 1000); // Flash purple
}
}
// Check for Guard's Pawn promotion
if (piece.pieceType === 'guardsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into royalGuard
piece.pieceType = 'royalGuard';
// Change texture to royalGuard
piece.removeChildAt(0); // Remove old texture
var royalGuardGraphics = piece.attachAsset('royalGuard', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
royalGuardGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xCD5C5C, 1000); // Flash indian red
}
}
// Check for Pawn of the Bull promotion
if (piece.pieceType === 'pawnOfTheBull') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into bull
piece.pieceType = 'bull';
// Change texture to bull
piece.removeChildAt(0); // Remove old texture
var bullGraphics = piece.attachAsset('bull', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
bullGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xB8860B, 1000); // Flash dark goldenrod
}
}
// Check for Lion's Pawn promotion
if (piece.pieceType === 'lionsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into lion
piece.pieceType = 'lion';
// Change texture to lion
piece.removeChildAt(0); // Remove old texture
var lionGraphics = piece.attachAsset('lion', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
lionGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFFD700, 1000); // Flash gold
}
}
// Check for regular pawn promotion to pawn's pawn
if (piece.pieceType === 'pawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Transform into pawn's pawn
piece.pieceType = 'pawnsPawn';
// Initialize movement count for this pawn's pawn
pawnsPawnMovementCount.push({
piece: piece,
moves: 0
});
// Change texture to pawn's pawn
piece.removeChildAt(0); // Remove old texture
var pawnsPawnGraphics = piece.attachAsset('pawnsPawn', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
pawnsPawnGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0xFF69B4, 1000); // Flash hot pink
}
}
// Check for Pawn's Pawn promotion
if (piece.pieceType === 'pawnsPawn') {
var opponentLastRow = piece.pieceColor === 0 ? 0 : BOARD_HEIGHT - 1;
if (targetRow === opponentLastRow) {
// Find movement count for this piece
var moveCount = 0;
for (var mc = 0; mc < pawnsPawnMovementCount.length; mc++) {
if (pawnsPawnMovementCount[mc].piece === piece) {
moveCount = pawnsPawnMovementCount[mc].moves;
break;
}
}
// Must move at least 1 square to be promoted
if (moveCount >= 1) {
// Transform into adventurous king
piece.pieceType = 'adventurousKing';
// Change texture to adventurous king
piece.removeChildAt(0); // Remove old texture
var adventurousKingGraphics = piece.attachAsset('adventurousKing', {
anchorX: 0.5,
anchorY: 0.5
});
if (piece.pieceColor === 1) {
adventurousKingGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(piece, 0x00FFFF, 1000); // Flash cyan
}
}
}
// Removed adventurous king promotion to king when entering own saray
// Check for shahsade victory condition - capturing king with shahsade is immediate win
if (piece.pieceType === 'shahsade' && capturedPieces.length > 0) {
for (var k = 0; k < capturedPieces.length; k++) {
if (capturedPieces[k].pieceType === 'king') {
// Shahsade captured the king - immediate victory
LK.setScore(1);
LK.showYouWin();
return;
}
}
}
// Generate and record move notation
var notation = generateMoveNotation(piece, targetRow, targetCol, moveData, capturedPieces);
var moveNumber = Math.floor(moveHistory.length / 2) + 1;
var colorPrefix = currentPlayer === 0 ? moveNumber + '.' : '';
moveHistory.push(colorPrefix + notation);
// Update move history display only if visible
if (moveHistoryVisible) {
var displayText = 'Move History:\n';
for (var i = 0; i < moveHistory.length; i++) {
if (i % 2 === 0) {
displayText += moveHistory[i] + ' ';
} else {
displayText += moveHistory[i] + '\n';
}
}
moveHistoryText.setText(displayText);
}
// Check for draw offer if piece entered opponent's palace
if (isPalaceSquare(targetRow, targetCol)) {
if (offerDraw(piece)) {
return; // Game ended in draw
}
}
// Check if king must exit saray on next turn after move
checkIfKingMustExitNextTurn(currentPlayer);
currentPlayer = 1 - currentPlayer;
selectPiece(null);
// Check for victory conditions
checkGameEnd();
}
function isSquareAttacked(row, col, byColor) {
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor !== byColor) {
continue;
}
var moves = piece.getRawMoves();
for (var j = 0; j < moves.length; j++) {
if (moves[j].row === row && moves[j].col === col) {
return true;
}
}
}
return false;
}
function findKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceType === 'king' && pieces[i].pieceColor === color) {
return pieces[i];
}
}
return null;
}
function isInCheck(color) {
var king = findKing(color);
if (!king) {
return false;
}
// Check if the attacking player has a shahsade
var attackingColor = 1 - color;
var hasShahsade = false;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === attackingColor && pieces[i].pieceType === 'shahsade') {
hasShahsade = true;
break;
}
}
// If attacker has shahsade and it hasn't been promoted, they cannot check the king
if (hasShahsade && !shahsadePromoted[attackingColor]) {
return false;
}
return isSquareAttacked(king.boardRow, king.boardCol, 1 - color);
}
function isValidMoveConsideringCheck(piece, targetRow, targetCol) {
// Simulate the move
var originalRow = piece.boardRow;
var originalCol = piece.boardCol;
var capturedPiece = getPieceAt(targetRow, targetCol);
var capturedIndex = -1;
if (capturedPiece) {
capturedIndex = pieces.indexOf(capturedPiece);
pieces.splice(capturedIndex, 1);
}
piece.boardRow = targetRow;
piece.boardCol = targetCol;
// Convert adventurous king if needed after simulated move
convertAdventurousKingIfNeeded(piece.pieceColor);
var stillInCheck = isInCheck(piece.pieceColor);
var hasImmunity = hasImmunityPiece(piece.pieceColor);
// Restore the position
piece.boardRow = originalRow;
piece.boardCol = originalCol;
if (capturedPiece && capturedIndex > -1) {
pieces.splice(capturedIndex, 0, capturedPiece);
}
// Player can ignore check only if they have immunity piece
if (hasImmunity) return true;
// Otherwise check must be resolved
return !stillInCheck;
}
function hasValidMoves(color) {
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceColor !== color) {
continue;
}
var moves = piece.getRawMoves();
for (var j = 0; j < moves.length; j++) {
if (isValidMoveConsideringCheck(piece, moves[j].row, moves[j].col)) {
return true;
}
}
}
return false;
}
function isSideLMove(fromRow, fromCol, toRow, toCol) {
var rowDiff = Math.abs(toRow - fromRow);
var colDiff = Math.abs(toCol - fromCol);
// Yan L: 2 yatay (col), 1 dikey (row)
if (rowDiff === 1 && colDiff === 2) {
return true; // Bu hareket yan L hareketidir
}
return false;
}
function hasRealKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color && pieces[i].pieceType === 'king') {
return true;
}
}
return false;
}
function hasAdventurousKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color && pieces[i].pieceType === 'adventurousKing') {
return true;
}
}
return false;
}
function hasShahsade(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color && pieces[i].pieceType === 'shahsade') {
return true;
}
}
return false;
}
function convertAdventurousKingIfNeeded(color) {
if (hasRealKing(color) || hasShahsade(color)) {
return;
}
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === color && p.pieceType === 'adventurousKing') {
p.pieceType = 'king';
// Change texture to king
p.removeChildAt(0); // Remove old texture
var kingGraphics = p.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (p.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
// Visual feedback for conversion
LK.effects.flashObject(p, 0xFFD700, 1000); // Flash gold
console.log('AdventurousKing converted to KING at (' + r + ',' + c + ')');
return;
}
}
}
}
function checkGameEnd() {
// Convert adventurous kings if needed for both players
convertAdventurousKingIfNeeded(0);
convertAdventurousKingIfNeeded(1);
var whiteKing = findKing(0);
var blackKing = findKing(1);
// Check if a player who brought shahsade into play loses their king
if (!whiteKing) {
// White king is captured - check if white has shahsade
var whiteShahsade = null;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === 0 && pieces[i].pieceType === 'shahsade') {
whiteShahsade = pieces[i];
break;
}
}
if (whiteShahsade) {
// Promote shahsade to new shah (king)
whiteShahsade.pieceType = 'king';
// Mark that white's shahsade has been promoted
shahsadePromoted[0] = true;
// Change texture to king
whiteShahsade.removeChildAt(0); // Remove old texture
var kingGraphics = whiteShahsade.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (whiteShahsade.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(whiteShahsade, 0xFFD700, 1000); // Flash gold
// Check if player is in checkmate after promotion
if (isInCheck(0) && !hasValidMoves(0)) {
LK.setScore(1);
LK.showGameOver();
return;
}
// Game continues, don't end
return;
} else {
LK.setScore(1);
LK.showGameOver();
return;
}
}
if (!blackKing) {
// Black king is captured - check if black has shahsade
var blackShahsade = null;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === 1 && pieces[i].pieceType === 'shahsade') {
blackShahsade = pieces[i];
break;
}
}
if (blackShahsade) {
// Promote shahsade to new shah (king)
blackShahsade.pieceType = 'king';
// Mark that black's shahsade has been promoted
shahsadePromoted[1] = true;
// Change texture to king
blackShahsade.removeChildAt(0); // Remove old texture
var kingGraphics = blackShahsade.attachAsset('king', {
anchorX: 0.5,
anchorY: 0.5
});
if (blackShahsade.pieceColor === 1) {
kingGraphics.tint = 0x333333;
}
// Visual feedback for promotion
LK.effects.flashObject(blackShahsade, 0xFFD700, 1000); // Flash gold
// Check if player is in checkmate after promotion
if (isInCheck(1) && !hasValidMoves(1)) {
LK.setScore(1);
LK.showGameOver();
return;
}
// Game continues, don't end
return;
} else {
LK.setScore(1);
LK.showGameOver();
return;
}
}
var inCheck = isInCheck(currentPlayer);
var hasValid = hasValidMoves(currentPlayer);
// Check for checkmate using new function that respects check privileges
if (isCheckmate(currentPlayer)) {
// Checkmate
LK.setScore(1);
LK.showGameOver();
} else if (!hasValid) {
// Stalemate
LK.setScore(0);
LK.showGameOver();
}
}
function initializeGame() {
createBoard();
createPieces();
gameStarted = true;
}
// Player turn indicator
var turnText = new Text2('White to move', {
size: 80,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
// Move history display
var moveHistory = [];
var moveHistoryVisible = false;
var moveHistoryTab = new Text2('Move History', {
size: 50,
fill: 0xFFFFFF
});
moveHistoryTab.anchor.set(0, 0);
moveHistoryTab.x = 50;
moveHistoryTab.y = 150;
game.addChild(moveHistoryTab);
var moveHistoryText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
moveHistoryText.anchor.set(0, 0);
moveHistoryText.x = 50;
moveHistoryText.y = 200;
moveHistoryText.visible = false;
game.addChild(moveHistoryText);
game.down = function (x, y, obj) {
if (!gameStarted) {
return;
}
// Check if move history tab was clicked
if (x >= moveHistoryTab.x && x <= moveHistoryTab.x + 300 && y >= moveHistoryTab.y && y <= moveHistoryTab.y + 60) {
moveHistoryVisible = !moveHistoryVisible;
moveHistoryText.visible = moveHistoryVisible;
if (moveHistoryVisible) {
// Update display when showing
var displayText = 'Move History:\n';
for (var i = 0; i < moveHistory.length; i++) {
if (i % 2 === 0) {
displayText += moveHistory[i] + ' ';
} else {
displayText += moveHistory[i] + '\n';
}
}
moveHistoryText.setText(displayText);
}
return;
}
var coords = getBoardCoordinates(x, y);
if (!isValidSquare(coords.row, coords.col)) {
return;
}
var clickedPiece = getPieceAt(coords.row, coords.col);
if (selectedPiece) {
var validMoves = selectedPiece.getValidMoves();
var isValidMove = false;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === coords.row && validMoves[i].col === coords.col) {
isValidMove = true;
break;
}
}
if (isValidMove) {
var moveData = null;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === coords.row && validMoves[i].col === coords.col) {
moveData = validMoves[i];
break;
}
}
makeMove(selectedPiece, coords.row, coords.col, moveData);
return;
}
}
if (clickedPiece && clickedPiece.pieceColor === currentPlayer) {
// Check if this is a Shah position swap
if (selectedPiece && selectedPiece.pieceType === 'king' && clickedPiece !== selectedPiece) {
var swappablePieces = getSwappablePieces(selectedPiece);
var canSwap = false;
for (var i = 0; i < swappablePieces.length; i++) {
if (swappablePieces[i] === clickedPiece) {
canSwap = true;
break;
}
}
if (canSwap) {
performPositionSwap(selectedPiece, clickedPiece);
return;
}
}
selectPiece(clickedPiece);
} else {
selectPiece(null);
}
};
game.update = function () {
if (!gameStarted) {
initializeGame();
}
// Try teleporting pawn of pawns for current player
tryTeleportPawnOfPawns(currentPlayer);
// Enforce saray exit if required
enforceSarayExit(currentPlayer);
var playerText = currentPlayer === 0 ? 'White to move' : 'Black to move';
if (isInCheck(currentPlayer)) {
playerText += ' (Check!)';
}
turnText.setText(playerText);
};
function enforceSarayExit(playerColor) {
// Check if player is mated due to saray exit requirement
if (checkForcedSarayExitOrMate(playerColor)) {
// Player is mated - end game
LK.setScore(1);
LK.showGameOver();
return;
}
for (var row = 0; row < BOARD_HEIGHT; row++) {
for (var col = 0; col < BOARD_WIDTH; col++) {
var p = getPieceAt(row, col);
if (p && p.pieceColor === playerColor && mustMoveFirst(p, row, col)) {
// Highlight the piece that must exit saray
if (selectedPiece !== p) {
selectPiece(p);
}
return;
}
}
}
}
// List of types the pawn_of_pawns cannot threaten
var EXCLUDED_TYPES = ['camelPawn', 'giraffePawn', 'guardsPawn', 'kingsPawn', 'knightPawn', 'lionsPawn', 'ministersPawn', 'pawnOfTheBull', 'pawnOfTheElephant', 'pawnOfTheLeader', 'pawn', 'pawnOfTheWarMachine', 'viziersPawn', 'king'];
function tryTeleportPawnOfPawns(color) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceType === 'pawnsPawn' && p.pieceColor === color && !p.hasTeleported) {
for (var tr = 0; tr < BOARD_HEIGHT; tr++) {
for (var tc = 0; tc < BOARD_WIDTH; tc++) {
if (!isValidSquare(tr, tc)) continue; // Skip invalid squares
if (getPieceAt(tr, tc)) continue; // Square must be empty
var threats = countValidThreats(tr, tc, color);
var blocksImmobilizedEnemy = threatensBlockedEnemy(tr, tc, color);
if (threats >= 2 || blocksImmobilizedEnemy) {
// Teleport the pawn of pawns
p.boardRow = tr;
p.boardCol = tc;
p.hasTeleported = true;
var pos = getBoardPosition(tr, tc);
tween(p, {
x: pos.x,
y: pos.y
}, {
duration: 300
});
console.log('Pawn of Pawns TELEPORTED to (' + tr + ',' + tc + ')');
return;
}
}
}
}
}
}
}
function countValidThreats(row, col, color) {
var count = 0;
var dirs = [[-1, -1], [-1, 1], [1, -1], [1, 1]]; // Diagonals
for (var d = 0; d < dirs.length; d++) {
var dir = dirs[d];
var r = row + dir[0];
var c = col + dir[1];
if (isValidSquare(r, c)) {
var enemy = getPieceAt(r, c);
if (enemy && enemy.pieceColor !== color && EXCLUDED_TYPES.indexOf(enemy.pieceType) === -1) {
// Additional check: pawn of pawns cannot teleport to threaten the king
if (enemy.pieceType === 'king') {
return 0; // Prevent teleportation if it would threaten the king
}
count++;
}
}
}
return count;
}
function threatensBlockedEnemy(row, col, color) {
var dirs = [[-1, -1], [-1, 1], [1, -1], [1, 1]]; // Diagonals
for (var d = 0; d < dirs.length; d++) {
var dir = dirs[d];
var r = row + dir[0];
var c = col + dir[1];
if (isValidSquare(r, c)) {
var enemy = getPieceAt(r, c);
if (enemy && enemy.pieceColor !== color && EXCLUDED_TYPES.indexOf(enemy.pieceType) === -1) {
// Additional check: pawn of pawns cannot teleport to threaten the king
if (enemy.pieceType === 'king') {
return false; // Prevent teleportation if it would threaten the king
}
if (!hasLegalMovesForPiece(enemy, r, c)) {
return true;
}
}
}
}
return false;
}
function hasLegalMovesForPiece(piece, row, col) {
var moves = piece.getRawMoves();
for (var i = 0; i < moves.length; i++) {
if (isValidMoveConsideringCheck(piece, moves[i].row, moves[i].col)) {
return true;
}
}
return false;
}
function hasImmunityPiece(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceColor === color) {
if (pieces[i].pieceType === 'adventurousKing' || pieces[i].pieceType === 'shahsade') {
return true;
}
}
}
return false;
}
function isPieceUnderThreat(piece) {
return isSquareAttacked(piece.boardRow, piece.boardCol, 1 - piece.pieceColor);
}
function hasCheckPrivilege(color) {
return hasAdventurousKing(color) || hasShahsade(color);
}
function getSwappablePieces(shahPiece) {
var swappablePieces = [];
// Check if Shah position swap has already been used
if (shahPositionSwapUsed[shahPiece.pieceColor]) {
return swappablePieces;
}
// Shah must not be under threat
if (isPieceUnderThreat(shahPiece)) {
return swappablePieces;
}
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
// Must be same color but not the Shah itself
if (piece.pieceColor === shahPiece.pieceColor && piece !== shahPiece) {
// Piece must not be under threat
if (!isPieceUnderThreat(piece)) {
swappablePieces.push(piece);
}
}
}
return swappablePieces;
}
function isCheckmate(color) {
if (hasImmunityPiece(color)) {
console.log(color === 0 ? 'White' : 'Black' + ' has immunity — checkmate ignored.');
return false;
}
return isInCheck(color) && !hasValidMoves(color);
}
function isPalaceSquare(row, col) {
return row === 2 && col === 0 || row === 9 && col === 12;
}
function isSaray(row, col) {
return row === 2 && col === 0 || row === 9 && col === 12;
}
function isInOwnSaray(piece, row, col) {
return piece.pieceColor === 0 && row === 9 && col === 12 || piece.pieceColor === 1 && row === 2 && col === 0;
}
function promoteAdventurousKingToKing(row, col) {
// Removed adventurous king promotion to king when entering own saray
}
function mustExitSarayThisTurn(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === playerColor && p.mustExitSaray && isInOwnSaray(p, r, c)) {
return true;
}
}
}
return false;
}
function canEscapeFromSaray(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === playerColor && p.mustExitSaray && isInOwnSaray(p, r, c)) {
// Check 8 surrounding squares (like king movement)
var dr = [-1, -1, -1, 0, 1, 1, 1, 0];
var dc = [-1, 0, 1, 1, 1, 0, -1, -1];
for (var i = 0; i < 8; i++) {
var nr = r + dr[i];
var nc = c + dc[i];
if (isValidSquare(nr, nc) && !getPieceAt(nr, nc)) {
return true; // Found an empty escape square
}
}
return false; // Surrounded, no escape
}
}
}
return true; // No forced exit kings found
}
function checkForcedSarayExitOrMate(playerColor) {
if (mustExitSarayThisTurn(playerColor)) {
if (canEscapeFromSaray(playerColor)) {
console.log((playerColor === 0 ? 'White' : 'Black') + ' must move King out of saray this turn.');
return false; // Not mated, but must move
} else {
console.log((playerColor === 0 ? 'White' : 'Black') + ' cannot escape saray — checkmate.');
return true; // Mated
}
}
return false; // No forced exits pending
}
function checkIfKingMustExitNextTurn(playerColor) {
for (var r = 0; r < BOARD_HEIGHT; r++) {
for (var c = 0; c < BOARD_WIDTH; c++) {
var p = getPieceAt(r, c);
if (p && p.pieceColor === playerColor && p.pieceType === 'king' && isInOwnSaray(p, r, c)) {
p.mustExitSaray = true;
console.log((playerColor === 0 ? 'White' : 'Black') + "'s king must exit saray on next turn.");
}
}
}
}
function handleSarayCapture(attacker, row, col) {
if (isSaray(row, col)) {
attacker.mustExitSaray = true;
}
}
function mustMoveFirst(piece, row, col) {
if (!piece || !piece.mustExitSaray) return false;
if (isSaray(row, col)) {
return true; // still inside → must move out
} else {
piece.mustExitSaray = false; // already out → clear flag
return false;
}
}
function getPlayerPalace(color) {
return color === 1 ? {
row: 2,
col: 0
} : {
row: 9,
col: 12
};
}
function isOpponentPalace(row, col, color) {
if (color === 0) {
return row === 2 && col === 0; // White player, black palace
} else {
return row === 9 && col === 12; // Black player, white palace
}
}
function canEnterPalace(piece, targetRow, targetCol) {
// Coordinates of palace squares
var blackPalace = {
row: 2,
col: 0
}; // Black Palace location
var whitePalace = {
row: 9,
col: 12
}; // White Palace location
if (!piece) return false;
var type = piece.pieceType;
var color = piece.pieceColor === 0 ? 'white' : 'black';
var isWhiteSaray = targetRow === whitePalace.row && targetCol === whitePalace.col;
var isBlackSaray = targetRow === blackPalace.row && targetCol === blackPalace.col;
var target = getPieceAt(targetRow, targetCol);
var isCapturing = target && target.pieceColor !== piece.pieceColor;
// Normal allowed entry
if (type === 'adventurousKing' || isBlackSaray && color === 'white' && (type === 'king' || type === 'shahsade') || isWhiteSaray && color === 'black' && (type === 'king' || type === 'shahsade')) {
return true;
}
// Special rule: capture king/shahsade/adventurousKing in saray if under threat
if (isCapturing && target && (target.pieceType === 'king' || target.pieceType === 'shahsade' || target.pieceType === 'adventurousKing') && isSaray(targetRow, targetCol)) {
return true;
}
return !isSaray(targetRow, targetCol); // deny entry to saray unless allowed
}
function isPieceInPalace(piece) {
return isPalaceSquare(piece.boardRow, piece.boardCol);
}
var drawOfferPending = false;
var drawOfferPiece = null;
function offerDraw(piece) {
// Check if piece is in opponent's palace
if (isOpponentPalace(piece.boardRow, piece.boardCol, piece.pieceColor)) {
var playerName = piece.pieceColor === 0 ? 'White' : 'Black';
drawOfferPending = true;
drawOfferPiece = piece;
// Create draw offer dialog
showDrawOfferDialog(playerName);
return true; // Game is paused for draw offer
}
return false;
}
function showDrawOfferDialog(playerName) {
// Create dialog background
var dialogBg = game.addChild(LK.getAsset('darkSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 3,
alpha: 0.9
}));
dialogBg.x = 2048 / 2;
dialogBg.y = 2732 / 2;
// Create dialog text
var dialogText = new Text2(playerName + ' offers a draw.\nDo you accept?', {
size: 60,
fill: 0xFFFFFF
});
dialogText.anchor.set(0.5, 0.5);
dialogText.x = 2048 / 2;
dialogText.y = 2732 / 2 - 100;
game.addChild(dialogText);
// Create Yes button
var yesButton = game.addChild(LK.getAsset('lightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
}));
yesButton.x = 2048 / 2 - 200;
yesButton.y = 2732 / 2 + 100;
var yesText = new Text2('Yes', {
size: 50,
fill: 0x000000
});
yesText.anchor.set(0.5, 0.5);
yesText.x = yesButton.x;
yesText.y = yesButton.y;
game.addChild(yesText);
// Create No button
var noButton = game.addChild(LK.getAsset('lightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
}));
noButton.x = 2048 / 2 + 200;
noButton.y = 2732 / 2 + 100;
var noText = new Text2('No', {
size: 50,
fill: 0x000000
});
noText.anchor.set(0.5, 0.5);
noText.x = noButton.x;
noText.y = noButton.y;
game.addChild(noText);
// Add click handlers
yesButton.down = function () {
// Accept draw
LK.setScore(0); // Draw
LK.showGameOver();
};
noButton.down = function () {
// Decline draw - clean up dialog and continue game
dialogBg.destroy();
dialogText.destroy();
yesButton.destroy();
yesText.destroy();
noButton.destroy();
noText.destroy();
drawOfferPending = false;
drawOfferPiece = null;
};
}
function determineSeaMonsterAttackDirection(bottomRow, col) {
// Sea Monster occupies bottomRow and bottomRow - 1
if (col <= 1) {
return 'RIGHT'; // If on the left edge, attack to the right
} else if (col >= BOARD_WIDTH - 2) {
return 'LEFT'; // If on the right edge, attack to the left
} else if (bottomRow <= 1) {
return 'DOWN'; // If near the top, attack downward
} else {
return 'UP'; // Default: attack upward
}
}
function getSeaMonsterAttackMoves(bottomRow, col, direction) {
var attackMoves = [];
var topRow = bottomRow - 1; // Sea Monster occupies two vertical squares
switch (direction) {
case 'UP':
for (var i = 1; i <= 3; i++) {
var targetRow = topRow - i;
if (targetRow >= 0) {
attackMoves.push({
row: targetRow,
col: col
});
}
}
break;
case 'DOWN':
for (var i = 1; i <= 3; i++) {
var targetRow = bottomRow + i;
if (targetRow < BOARD_HEIGHT) {
attackMoves.push({
row: targetRow,
col: col
});
}
}
break;
case 'RIGHT':
for (var i = 1; i <= 3; i++) {
var targetCol = col + i;
if (targetCol < BOARD_WIDTH) {
attackMoves.push({
row: topRow,
col: targetCol
});
}
}
break;
case 'LEFT':
for (var i = 1; i <= 3; i++) {
var targetCol = col - i;
if (targetCol >= -1) {
attackMoves.push({
row: topRow,
col: targetCol
});
}
}
break;
}
return attackMoves;
}
function performPositionSwap(shahPiece, targetPiece) {
// Store original positions
var shahRow = shahPiece.boardRow;
var shahCol = shahPiece.boardCol;
var targetRow = targetPiece.boardRow;
var targetCol = targetPiece.boardCol;
// Swap positions
shahPiece.boardRow = targetRow;
shahPiece.boardCol = targetCol;
targetPiece.boardRow = shahRow;
targetPiece.boardCol = shahCol;
// Animate the swap
var shahPos = getBoardPosition(targetRow, targetCol);
var targetPos = getBoardPosition(shahRow, shahCol);
tween(shahPiece, {
x: shahPos.x,
y: shahPos.y
}, {
duration: 300
});
tween(targetPiece, {
x: targetPos.x,
y: targetPos.y
}, {
duration: 300
});
// Mark that position swap has been used
shahPositionSwapUsed[shahPiece.pieceColor] = true;
// Record position swap in move history
var notation = 'K-' + pieceToNotation(targetPiece.pieceType) + ' swap';
var moveNumber = Math.floor(moveHistory.length / 2) + 1;
var colorPrefix = currentPlayer === 0 ? moveNumber + '.' : '';
moveHistory.push(colorPrefix + notation);
// Update move history display only if visible
if (moveHistoryVisible) {
var displayText = 'Move History:\n';
for (var i = 0; i < moveHistory.length; i++) {
if (i % 2 === 0) {
displayText += moveHistory[i] + ' ';
} else {
displayText += moveHistory[i] + '\n';
}
}
moveHistoryText.setText(displayText);
}
// Play move sound
LK.getSound('move').play();
// Change turn
currentPlayer = 1 - currentPlayer;
selectPiece(null);
clearSwapHighlights();
} ===================================================================
--- original.js
+++ change.js
@@ -1951,50 +1951,56 @@
col: newCol
});
}
}
- // Sea Monster attack capability with new pattern rules
- if (isSeaSquare(self.boardRow, self.boardCol)) {
- // Check bounds for attacks
- var canAttack = function canAttack(monsterRow, monsterCol, targetRow, targetCol) {
- if (targetRow < 0 || targetRow >= BOARD_HEIGHT || targetCol < -1 || targetCol >= BOARD_WIDTH) {
- return false;
- }
- var rowDiff = targetRow - monsterRow;
- var colDiff = targetCol - monsterCol;
- var absRow = Math.abs(rowDiff);
- var absCol = Math.abs(colDiff);
- // 1-square diagonal
- if (absRow == 1 && absCol == 1) return true;
- // Straight lines (up to 3 squares)
- if (absRow == 0 && absCol >= 1 && absCol <= 3 || absCol == 0 && absRow >= 1 && absRow <= 3) {
- return true;
- }
- // Wide horizontal-based L-shapes only
- if (absCol == 2 && absRow == 1) {
- return true;
- }
- // Special Rule: 3rd left column and its above/below
- if (targetCol == monsterCol - 3 && (targetRow == monsterRow || targetRow == monsterRow - 1 || targetRow == monsterRow + 1)) {
- return true;
- }
- return false;
- }; // Generate all possible attack targets
- for (var testRow = 0; testRow < BOARD_HEIGHT; testRow++) {
- for (var testCol = -1; testCol < BOARD_WIDTH; testCol++) {
- if (testRow == self.boardRow && testCol == self.boardCol) continue;
- if (canAttack(self.boardRow, self.boardCol, testRow, testCol)) {
- var targetPiece = getPieceAt(testRow, testCol);
+ // Sea Monster attack capability - complex attack pattern
+ // Only attack if in sea (rows 6-7 based on the constant)
+ if (self.boardRow >= 6 && self.boardRow <= 7) {
+ var attackMoves = [];
+ var monsterRow = self.boardRow;
+ var monsterCol = self.boardCol;
+ // Check all possible attack squares based on complex pattern
+ for (var targetRow = 0; targetRow < BOARD_HEIGHT; targetRow++) {
+ for (var targetCol = -1; targetCol < BOARD_WIDTH; targetCol++) {
+ if (!isValidSquare(targetRow, targetCol)) continue;
+ if (targetRow === monsterRow && targetCol === monsterCol) continue;
+ var rowDiff = targetRow - monsterRow;
+ var colDiff = targetCol - monsterCol;
+ var absRow = Math.abs(rowDiff);
+ var absCol = Math.abs(colDiff);
+ var canAttack = false;
+ // Diagonal attacks (1 square)
+ if (absRow === 1 && absCol === 1) {
+ canAttack = true;
+ }
+ // Straight line attacks (1-3 squares)
+ else if (absRow === 0 && absCol >= 1 && absCol <= 3 || absCol === 0 && absRow >= 1 && absRow <= 3) {
+ canAttack = true;
+ }
+ // Wide L-shape: 2 horizontal + 1 vertical
+ else if (absCol === 2 && absRow === 1) {
+ canAttack = true;
+ }
+ // Special Left-3 zone
+ else if (targetCol === monsterCol - 3 && (targetRow === monsterRow || targetRow === monsterRow - 1 || targetRow === monsterRow + 1)) {
+ canAttack = true;
+ }
+ if (canAttack) {
+ var targetPiece = getPieceAt(targetRow, targetCol);
if (!targetPiece || targetPiece.pieceColor !== self.pieceColor) {
- moves.push({
- row: testRow,
- col: testCol,
+ attackMoves.push({
+ row: targetRow,
+ col: targetCol,
isSeaMonsterAttack: true
});
}
}
}
}
+ // Add attack moves to regular moves
+ for (var i = 0; i < attackMoves.length; i++) {
+ moves.push(attackMoves[i]);
+ }
}
break;
}
// Filter out sea squares - pieces cannot enter the sea (except sea monster)