The transform module provides functions for geometrically transforming board positions, including flips, rotations, and shifts. These are useful for position analysis, endgame tablebases, and symmetry detection.
Flip Functions
flipVertical
Flips a SquareSet vertically (mirrors across the horizontal center).
import { flipVertical } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([0, 1, 2]); // a1, b1, c1
const flipped = flipVertical(squares);
console.log(flipped.has(56)); // true (a8)
console.log(flipped.has(57)); // true (b8)
console.log(flipped.has(58)); // true (c8)
The SquareSet to flip vertically
A new SquareSet with rank 1 mapped to rank 8, rank 2 to rank 7, etc.
flipHorizontal
Flips a SquareSet horizontally (mirrors across the vertical center).
import { flipHorizontal } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([0, 8, 16]); // a1, a2, a3
const flipped = flipHorizontal(squares);
console.log(flipped.has(7)); // true (h1)
console.log(flipped.has(15)); // true (h2)
console.log(flipped.has(23)); // true (h3)
The SquareSet to flip horizontally
A new SquareSet with a-file mapped to h-file, b-file to g-file, etc.
flipDiagonal
Flips a SquareSet across the a1-h8 diagonal.
import { flipDiagonal } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([1]); // b1
const flipped = flipDiagonal(squares);
console.log(flipped.has(8)); // true (a2)
The SquareSet to flip diagonally
A new SquareSet with squares transposed across the a1-h8 diagonal (files become ranks and vice versa)
Rotation Functions
rotate180
Rotates a SquareSet 180 degrees.
import { rotate180 } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([0]); // a1
const rotated = rotate180(squares);
console.log(rotated.has(63)); // true (h8)
A new SquareSet rotated 180 degrees (equivalent to flipVertical + flipHorizontal)
Shift Functions
shiftLeft
Shifts all squares one file to the left (wrapping a-file to h-file).
import { shiftLeft } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([1]); // b1
const shifted = shiftLeft(squares);
console.log(shifted.has(0)); // true (a1)
const aFile = SquareSet.fromSquares([0]); // a1
const wrapped = shiftLeft(aFile);
console.log(wrapped.has(7)); // true (h1, wrapped)
A new SquareSet with all squares shifted one file left (with wrapping)
shiftRight
Shifts all squares one file to the right (wrapping h-file to a-file).
import { shiftRight } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([0]); // a1
const shifted = shiftRight(squares);
console.log(shifted.has(1)); // true (b1)
const hFile = SquareSet.fromSquares([7]); // h1
const wrapped = shiftRight(hFile);
console.log(wrapped.has(0)); // true (a1, wrapped)
A new SquareSet with all squares shifted one file right (with wrapping)
shiftUp
Shifts all squares one rank up (wrapping rank 8 to rank 1).
import { shiftUp } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([0]); // a1
const shifted = shiftUp(squares);
console.log(shifted.has(8)); // true (a2)
const rank8 = SquareSet.fromSquares([56]); // a8
const wrapped = shiftUp(rank8);
console.log(wrapped.has(0)); // true (a1, wrapped)
A new SquareSet with all squares shifted one rank up (with wrapping)
shiftDown
Shifts all squares one rank down (wrapping rank 1 to rank 8).
import { shiftDown } from 'chessops/transform';
import { SquareSet } from 'chessops';
const squares = SquareSet.fromSquares([8]); // a2
const shifted = shiftDown(squares);
console.log(shifted.has(0)); // true (a1)
const rank1 = SquareSet.fromSquares([0]); // a1
const wrapped = shiftDown(rank1);
console.log(wrapped.has(56)); // true (a8, wrapped)
A new SquareSet with all squares shifted one rank down (with wrapping)
Applies a transformation function to all piece sets in a board.
import { transformBoard, flipVertical } from 'chessops/transform';
import { Board } from 'chessops/board';
const board = Board.default();
const flipped = transformBoard(board, flipVertical);
// White pieces are now on rank 8, black pieces on rank 1
console.log(flipped.get(56)); // { role: 'rook', color: 'white' } (was on a1)
f
(s: SquareSet) => SquareSet
required
Transformation function to apply to each piece set
A new Board with the transformation applied to all piece positions
This function transforms the geometric positions but does not change piece colors or update move-related state (castling rights, en passant, etc.).
Applies a transformation function to a complete position setup.
import { transformSetup, flipVertical } from 'chessops/transform';
import { parseFen } from 'chessops/fen';
const setup = parseFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1').unwrap();
const flipped = transformSetup(setup, flipVertical);
// Board is flipped, castling rights and ep square are also transformed
console.log(flipped.board.get(56)); // { role: 'rook', color: 'white' }
The position setup to transform
f
(s: SquareSet) => SquareSet
required
Transformation function to apply
A new Setup with transformed board, castling rights, and en passant square. Turn, pockets, and move counters are preserved.
Usage Examples
Normalizing Positions for Analysis
import { transformSetup, flipVertical } from 'chessops/transform';
import { parseFen, makeFen } from 'chessops/fen';
// Normalize position so white is always on bottom
function normalizePosition(fen: string): string {
const setup = parseFen(fen).unwrap();
if (setup.turn === 'black') {
// Flip the board if it's black to move
const flipped = transformSetup(setup, flipVertical);
flipped.turn = 'white'; // Swap turn
return makeFen(flipped);
}
return fen;
}
Detecting Symmetries
import { transformBoard, flipVertical, flipHorizontal } from 'chessops/transform';
import { Board } from 'chessops/board';
function isSymmetric(board: Board): {
vertical: boolean;
horizontal: boolean;
} {
const vFlipped = transformBoard(board, flipVertical);
const hFlipped = transformBoard(board, flipHorizontal);
return {
vertical: board.equals(vFlipped),
horizontal: board.equals(hFlipped),
};
}
const board = Board.default();
const symmetry = isSymmetric(board);
console.log(symmetry.vertical); // false
console.log(symmetry.horizontal); // true (starting position is horizontally symmetric)
Converting Between Perspectives
import { transformSetup, rotate180 } from 'chessops/transform';
import { parseFen, makeFen } from 'chessops/fen';
// Show position from opponent's perspective
function opponentView(fen: string): string {
const setup = parseFen(fen).unwrap();
const rotated = transformSetup(setup, rotate180);
return makeFen(rotated);
}
const fen = 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1';
const flipped = opponentView(fen);
console.log(flipped);
// Board is now shown from black's perspective
Endgame Tablebase Normalization
import { transformSetup, flipVertical, flipHorizontal } from 'chessops/transform';
import { parseFen, makeFen } from 'chessops/fen';
// Normalize KPvK endgame (king and pawn vs king)
function normalizeKPK(fen: string): string {
let setup = parseFen(fen).unwrap();
// Ensure white king is on queenside
const whiteKing = setup.board.kingOf('white');
if (whiteKing !== undefined && whiteKing % 8 >= 4) {
setup = transformSetup(setup, flipHorizontal);
}
// Ensure it's white to move
if (setup.turn === 'black') {
setup = transformSetup(setup, flipVertical);
setup.turn = 'white';
}
return makeFen(setup);
}
Analyzing Pawn Structures
import { transformBoard, flipVertical } from 'chessops/transform';
import { SquareSet } from 'chessops';
import { Board } from 'chessops/board';
// Get pawn structure (independent of color)
function getPawnStructure(board: Board): {
white: SquareSet;
black: SquareSet;
} {
const whitePawns = board.pieces('white', 'pawn');
const blackPawns = board.pieces('black', 'pawn');
// Normalize black pawns as if they were white
const normalizedBlack = flipVertical(blackPawns);
return {
white: whitePawns,
black: normalizedBlack,
};
}
Creating Position Variants
import { transformBoard, rotate180, flipHorizontal } from 'chessops/transform';
import { Board } from 'chessops/board';
// Generate all symmetric variants of a position
function getSymmetricVariants(board: Board): Board[] {
return [
board,
transformBoard(board, flipHorizontal),
transformBoard(board, rotate180),
transformBoard(board, s => rotate180(flipHorizontal(s))),
];
}