Skip to main content
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)
s
SquareSet
required
The SquareSet to flip vertically
return
SquareSet
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)
s
SquareSet
required
The SquareSet to flip horizontally
return
SquareSet
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)
s
SquareSet
required
The SquareSet to flip diagonally
return
SquareSet
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)
s
SquareSet
required
The SquareSet to rotate
return
SquareSet
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)
squares
SquareSet
required
The SquareSet to shift
return
SquareSet
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)
squares
SquareSet
required
The SquareSet to shift
return
SquareSet
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)
squares
SquareSet
required
The SquareSet to shift
return
SquareSet
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)
squares
SquareSet
required
The SquareSet to shift
return
SquareSet
A new SquareSet with all squares shifted one rank down (with wrapping)

Board Transformation Functions

transformBoard

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)
board
Board
required
The board to transform
f
(s: SquareSet) => SquareSet
required
Transformation function to apply to each piece set
return
Board
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.).

transformSetup

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' }
setup
Setup
required
The position setup to transform
f
(s: SquareSet) => SquareSet
required
Transformation function to apply
return
Setup
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))),
  ];
}

Build docs developers (and LLMs) love