import { Chessboard, isEmpty, Square, squareAtPosition } from "./chessboard"; import { Move } from "./movements"; import { equals, left, right, top, bottom } from "./position"; // Fonction de validation des moves function isValidEat(board : Chessboard, move : Move): boolean { let start : Square = squareAtPosition(board, move.from!); let destination : Square = squareAtPosition(board, move.to!); return (start.piece!.isWhite !== destination.piece!.isWhite || !start.piece!.isWhite !== !destination.piece!.isWhite) } /** * Checks whether a Black Pawn can perform a given move. * A pawn can move forward to the unoccupied square immediately in front of * it on the same file, or on its first move it can advance two squares along * the same file, provided both squares are unoccupied (black dots in the * diagram); or the pawn can capture an opponent's piece on a square diagonally * in front of it on an adjacent file, by moving to that square (black "x"s). * * * @param board The chessboard of the current game * @param move */ export function blackPawnMove(board: Chessboard, move: Move): boolean { if (equals(move.to!, bottom(move.from!))) { //console.log("Single forward"); return isEmpty(board, move.to!); } if (move.from!.rank === 6 && equals(move.to!, bottom(bottom(move.from!)))) { //console.log("Double forward"); return isEmpty(board, bottom(move.from!)) && isEmpty(board, move.to!); } if (equals(move.to!, left(bottom(move.from!))) || equals(move.to!, right(bottom(move.from!)))) { let destination: Square = squareAtPosition(board, move.to!); return !(destination.isEmpty || !destination.piece!.isWhite) } return false; } /** * A pawn can move forward to the unoccupied square immediately in front of * it on the same file, or on its first move it can advance two squares along * the same file, provided both squares are unoccupied (black dots in * the diagram); or the pawn can capture an opponent's piece on a square diagonally * in front of it on an adjacent file, by moving to that square (black "x"s). * * * @param board The chessboard of the current game * @param move */ export function whitePawnMove(board: Chessboard, move: Move): boolean { if (equals(move.to!, top(move.from!))) { return isEmpty(board, move.to!); } if (move.from!.rank === 1 && equals(move.to!, top(top(move.from!)))) { return isEmpty(board, top(move.from!)) && isEmpty(board, move.to!); } if (equals(move.to!, left(top(move.from!))) || equals(move.to!, right(top(move.from!)))) { let destination: Square = squareAtPosition(board, move.to!); return !(destination.isEmpty || destination.piece!.isWhite) } return false; } /** * Checks whether a King can perform a given move. * The king moves one square in any direction. * * @param board The chessboard of the current game * @param move */ export function kingMove(board: Chessboard, move: Move): boolean { // Mouvement normal & mangeage de pièce if (equals(move.to!, bottom(move.from!)) || equals(move.to!, right(move.from!)) || equals(move.to!, top(move.from!)) || equals(move.to!, left(move.from!)) || equals(move.to!, left(top(move.from!))) || equals(move.to!, right(top(move.from!))) || equals(move.to!, left(bottom(move.from!))) || equals(move.to!, right(bottom(move.from!)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } return false; } /** * Checks whether a Queen can perform a given move. * The queen combines the power of a rook and bishop and can move any * number of squares along a rank, file, or diagonal, but cannot leap over other pieces. * * @param board The chessboard of the current game * @param move */ export function queenMove(board: Chessboard, move: Move): boolean { // Mouvements de la Tour haut et bas if (move.from!.file == move.to!.file) { // Le déplacement se fait-il sur la même colonne ? let moveRange = Math.abs(move.from!.rank-move.to!.rank!); // combien de cases on veut traverser en haut ou en bas ? let moveFromTop = move.from!; let moveFromBottom = move.from!; for (let i=1; i<=moveRange; i++) { // Si on va en haut if (move.from!.rank!-move.to!.rank! < 0) { if (equals(move.to!, top(moveFromTop))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, top(moveFromTop)); if (!destination.isEmpty) { return false; } } } // Si on va en bas if (move.from!.rank!-move.to!.rank! > 0) { if (equals(move.to!, bottom(moveFromBottom))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, bottom(moveFromBottom)); if (!destination.isEmpty) { return false; } } } moveFromTop = top(moveFromTop); moveFromBottom = bottom(moveFromBottom); } } // Mouvements de la Tour gauche et droite if (move.from!.rank == move.to!.rank) { // Le déplacement se fait-il sur la même ligne ? let moveRange = Math.abs(move.from!.file-move.to!.file!); // combien de cases on veut traverser à gauche ou à droite ? let moveFromRight = move.from!; let moveFromLeft = move.from!; for (let i=1; i<=moveRange; i++) { // Si on va à droite if (move.from!.file!-move.to!.file! < 0) { if (equals(move.to!, right(moveFromRight))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, right(moveFromRight)); if (!destination.isEmpty) { return false; } } } // Si on va à gauche if (move.from!.file!-move.to!.file! > 0) { if (equals(move.to!, left(moveFromLeft))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, left(moveFromLeft)); if (!destination.isEmpty) { return false; } } } moveFromRight = right(moveFromRight); moveFromLeft = left(moveFromLeft); } } // Mouvements du Fou if (Math.abs(move.to!.rank - move.from!.rank) == Math.abs(move.to!.file - move.from!.file)) { let moveRange = Math.abs(move.from!.rank-move.to!.rank); let moveFrom11pm = move.from!; let moveFrom8pm = move.from!; let moveFrom5pm = move.from!; let moveFrom2pm = move.from!; for (let i=1; i<=moveRange; i++) { // Si on va en haut à gauche (11pm) if (move.to!.file < move.from!.file && move.to!.rank > move.from!.rank) { if (equals(move.to!, left(top(moveFrom11pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, left(top(moveFrom11pm))); if (!destination.isEmpty) { return false; } } } // Si on va en haut à droite (2pm) if (move.to!.file > move.from!.file && move.to!.rank > move.from!.rank) { if (equals(move.to!, right(top(moveFrom2pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, right(top(moveFrom2pm))); if (!destination.isEmpty) { return false; } } } // Si on va en bas à gauche (8pm) if (move.to!.file < move.from!.file && move.to!.rank < move.from!.rank) { if (equals(move.to!, left(bottom(moveFrom8pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, left(bottom(moveFrom8pm))); if (!destination.isEmpty) { return false; } } } // Si on va en bas à droite (5pm) if (move.to!.file > move.from!.file && move.to!.rank < move.from!.rank) { if (equals(move.to!, right(bottom(moveFrom5pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, right(bottom(moveFrom5pm))); if (!destination.isEmpty) { return false; } } } moveFrom11pm = left(top(moveFrom11pm)); moveFrom8pm = left(bottom(moveFrom8pm)); moveFrom5pm = right(bottom(moveFrom5pm)); moveFrom2pm = right(top(moveFrom2pm)); } } return false; } /** * Checks whether a Empress can perform a given move. * An Empress can move any number of squares along a rank or file, * but cannot leap over other pieces. * An Empress can also move to any of the closest squares that are not on the * same rank, file, or diagonal. (Thus the move forms an "L"-shape: * two squares vertically and one square horizontally, or two * squares horizontally and one square vertically.) * * @param board The chessboard of the current game * @param move */ export function empressMove(board: Chessboard, move: Move): boolean { /* Comme la Tour mais avec en plus les mouvements du chevalier */ // Mouvements du Chevalier // Mouvement vers le bas if (equals(move.to!, left(bottom(bottom(move.from!)))) || equals(move.to!, right(bottom(bottom(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers le haut if (equals(move.to!, left(top(top(move.from!)))) || equals(move.to!, right(top(top(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers la gauche if (equals(move.to!, bottom(left(left(move.from!)))) || equals(move.to!, top(left(left(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers la droite if (equals(move.to!, bottom(right(right(move.from!)))) || equals(move.to!, top(right(right(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvements de la Tour haut et bas if (move.from!.file == move.to!.file) { // Le déplacement se fait-il sur la même colonne ? let moveRange = Math.abs(move.from!.rank-move.to!.rank!); // combien de cases on veut traverser en haut ou en bas ? let moveFromTop = move.from!; let moveFromBottom = move.from!; for (let i=1; i<=moveRange; i++) { // Si on va en haut if (move.from!.rank!-move.to!.rank! < 0) { if (equals(move.to!, top(moveFromTop))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, top(moveFromTop)); if (!destination.isEmpty) { return false; } } } // Si on va en bas if (move.from!.rank!-move.to!.rank! > 0) { if (equals(move.to!, bottom(moveFromBottom))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, bottom(moveFromBottom)); if (!destination.isEmpty) { return false; } } } moveFromTop = top(moveFromTop); moveFromBottom = bottom(moveFromBottom); } } if (move.from!.rank == move.to!.rank) { // Le déplacement se fait-il sur la même ligne ? let moveRange = Math.abs(move.from!.file-move.to!.file!); // combien de cases on veut traverser à gauche ou à droite ? let moveFromRight = move.from!; let moveFromLeft = move.from!; for (let i=1; i<=moveRange; i++) { // Si on va à droite if (move.from!.file!-move.to!.file! < 0) { if (equals(move.to!, right(moveFromRight))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, right(moveFromRight)); if (!destination.isEmpty) { return false; } } } // Si on va à gauche if (move.from!.file!-move.to!.file! > 0) { if (equals(move.to!, left(moveFromLeft))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, left(moveFromLeft)); if (!destination.isEmpty) { return false; } } } moveFromRight = right(moveFromRight); moveFromLeft = left(moveFromLeft); } } return false; } /** * Checks whether a Princess can perform a given move. * A princess can move any number of squares diagonally, * but cannot leap over other pieces. * A princess can also move to any of the closest squares that are not on the * same rank, file, or diagonal. (Thus the move forms an "L"-shape: * two squares vertically and one square horizontally, or two * squares horizontally and one square vertically.) * * @param board The chessboard of the current game * @param move */ export function princessMove(board: Chessboard, move: Move): boolean { // Mouvements du Chevalier // Mouvement vers le bas if (equals(move.to!, left(bottom(bottom(move.from!)))) || equals(move.to!, right(bottom(bottom(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers le haut if (equals(move.to!, left(top(top(move.from!)))) || equals(move.to!, right(top(top(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers la gauche if (equals(move.to!, bottom(left(left(move.from!)))) || equals(move.to!, top(left(left(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers la droite if (equals(move.to!, bottom(right(right(move.from!)))) || equals(move.to!, top(right(right(move.from!))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvements du Fou if (Math.abs(move.to!.rank - move.from!.rank) == Math.abs(move.to!.file - move.from!.file)) { let moveRange = Math.abs(move.from!.rank-move.to!.rank); let moveFrom11pm = move.from!; let moveFrom8pm = move.from!; let moveFrom5pm = move.from!; let moveFrom2pm = move.from!; for (let i=1; i<=moveRange; i++) { // Si on va en haut à gauche (11pm) if (move.to!.file < move.from!.file && move.to!.rank > move.from!.rank) { if (equals(move.to!, left(top(moveFrom11pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, left(top(moveFrom11pm))); if (!destination.isEmpty) { return false; } } } // Si on va en haut à droite (2pm) if (move.to!.file > move.from!.file && move.to!.rank > move.from!.rank) { if (equals(move.to!, right(top(moveFrom2pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, right(top(moveFrom2pm))); if (!destination.isEmpty) { return false; } } } // Si on va en bas à gauche (8pm) if (move.to!.file < move.from!.file && move.to!.rank < move.from!.rank) { if (equals(move.to!, left(bottom(moveFrom8pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, left(bottom(moveFrom8pm))); if (!destination.isEmpty) { return false; } } } // Si on va en bas à droite (5pm) if (move.to!.file > move.from!.file && move.to!.rank < move.from!.rank) { if (equals(move.to!, right(bottom(moveFrom5pm)))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)); } else { let destination: Square = squareAtPosition(board, right(bottom(moveFrom5pm))); if (!destination.isEmpty) { return false; } } } moveFrom11pm = left(top(moveFrom11pm)); moveFrom8pm = left(bottom(moveFrom8pm)); moveFrom5pm = right(bottom(moveFrom5pm)); moveFrom2pm = right(top(moveFrom2pm)); } } return false; } /** * Checks whether a Camel can perform a given move. * The Camel move forms an "L"-shape: * three squares vertically and one square horizontally, or three * squares horizontally and one square vertically.) * * The camel can leap over other pieces. * * @param board The chessboard of the current game * @param move */ export function camelMove(board: Chessboard, move: Move): boolean { /* Comme Chevalier mais avec une case de plus */ // Mouvement vers le bas if (equals(move.to!, left(bottom(bottom(bottom(move.from!))))) || equals(move.to!, right(bottom(bottom(bottom(move.from!)))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers le haut if (equals(move.to!, left(top(top(top(move.from!))))) || equals(move.to!, right(top(top(top(move.from!)))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers la gauche if (equals(move.to!, bottom(left(left(left(move.from!))))) || equals(move.to!, top(left(left(left(move.from!)))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } // Mouvement vers la droite if (equals(move.to!, bottom(right(right(right(move.from!))))) || equals(move.to!, top(right(right(right(move.from!)))))) { let destination: Square = squareAtPosition(board, move.to!); return (destination.isEmpty || isValidEat(board,move)) } return false; }