## Low-level handling of squares, board indeces and pieces import std/strutils import std/strformat type Square* = distinct int8 ## A square PieceColor* = enum ## A piece color enumeration None = 0'i8, White, Black PieceKind* = enum ## A chess piece enumeration Empty = 0'i8, # No piece Bishop = 'b', King = 'k' Knight = 'n', Pawn = 'p', Queen = 'q', Rook = 'r', Piece* = object ## A chess piece color*: PieceColor kind*: PieceKind func nullPiece*: Piece {.inline.} = Piece(kind: Empty, color: None) func nullSquare*: Square {.inline.} = Square(-1'i8) func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White) func isValid*(a: Square): bool {.inline.} = a.int8 in 0..63 func isLightSquare*(a: Square): bool {.inline.} = (a.int8 and 2) == 0 func `==`*(a, b: Square): bool {.inline.} = a.int8 == b.int8 func `!=`*(a, b: Square): bool {.inline.} = a.int8 != b.int8 func `-`*(a, b: Square): Square {.inline.} = Square(a.int8 - b.int8) func `-`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 - b.int8) func `-`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 - b.int8) func colFromSquare*(square: Square): int8 = square.int8 mod 8 + 1 func rowFromSquare*(square: Square): int8 = square.int8 div 8 + 1 func makeSquare*(rank, file: SomeInteger): Square = Square(rank * 8 + file) proc toSquare*(s: string): Square {.discardable.} = ## Converts a square square from algebraic ## notation to its corresponding row and column ## in the chess grid (0 indexed) if len(s) != 2: raise newException(ValueError, "algebraic position must be of length 2") var s = s.toLowerAscii() if s[0] notin 'a'..'h': raise newException(ValueError, &"algebraic position has invalid first character ('{s[0]}')") if s[1] notin '1'..'8': raise newException(ValueError, &"algebraic position has invalid second character ('{s[1]}')") return Square((s[0].uint8 - uint8('a')) + ((s[1].uint8 - uint8('1')) xor 7) * 8) proc toAlgebraic*(square: Square): string {.inline.} = ## Converts a square from our internal rank/file ## notation to a square in algebraic notation let file = char('a'.uint8 + (square.uint64 and 7)) rank = char('1'.uint8 + ((square.uint64 div 8) xor 7)) return &"{file}{rank}" proc `$`*(square: Square): string = square.toAlgebraic()