Skip to content

The Board Model

The foundational value types. All are Sendable and presentation-free: colors, glyphs, and asset names are not part of the model and are left to the consuming UI.

PieceColor

public enum PieceColor: Equatable, Hashable, Codable, Sendable {
    case white, black
}
Member Meaning
opposite the other side
persistenceKey stable "white" / "black" storage key
shortKey compact "w" / "b"
init?(persistenceKey:) parse from the stable key
static ofUser(white:black:username:) which side a username played (case-insensitive), or nil

PieceType

public enum PieceType: Equatable, Hashable, Codable, Sendable {
    case king, queen, rook, bishop, knight, pawn
}

Piece

public struct Piece: Equatable, Hashable, Codable, Sendable {
    public let type: PieceType
    public let color: PieceColor
    public init(type: PieceType, color: PieceColor)
    public var fenChar: String        // uppercase for white, e.g. "N" / "n"
}

Square

A board coordinate, file/rank 0...7.

public struct Square: Hashable, Equatable, Codable, Sendable {
    public let file: Int
    public let rank: Int
    public init(file: Int, rank: Int)
    public init?(algebraic: String)   // "e4"
    public var isValid: Bool          // both in 0..<8
    public var fileChar: Character     // 'a'...'h'
    public var algebraic: String       // "e4"
    public var index: Int              // rank * 8 + file (0...63)
    public static func fromIndex(_ index: Int) -> Square
}

CastlingRights

public struct CastlingRights: Equatable, Hashable, Codable, Sendable {
    public var whiteKingside  = true
    public var whiteQueenside = true
    public var blackKingside  = true
    public var blackQueenside = true
    public static let none: CastlingRights   // all false
}

Move

A single move with full disambiguation metadata.

public struct Move: Equatable, Hashable, Sendable {
    public let from: Square
    public let to: Square
    public let piece: PieceType
    public let capturedPiece: PieceType?
    public let promotion: PieceType?
    public let isEnPassant: Bool
    public let isCastling: Bool

    public init(from: Square, to: Square, piece: PieceType,
                capturedPiece: PieceType? = nil, promotion: PieceType? = nil,
                isEnPassant: Bool = false, isCastling: Bool = false)

    public var uci: String   // "e2e4", "e7e8q"
}

MoveRecord

A move paired with its SAN and the position it was played from:

public struct MoveRecord: Sendable {
    public let move: Move
    public let notation: String
    public let positionBefore: Position
}

Piece names

PieceType.knight.displayName         // "knight"
PieceType.queen.displayName          // "queen"

displayName is the English noun the algebraic-notation letter abbreviates, so it is a property of the notation rather than of a user interface. It is not localized: a program presenting piece names in another language should map from the PieceType case rather than from this string. Composing a phrase from it ("White knight", a screen-reader sentence) is the caller's.

MoveAnnotation

The PGN/NAG glyphs. The model covers chess logic only; display name, symbol, and tint are left to the UI:

public enum MoveAnnotation: String, Equatable, Hashable, Sendable, CaseIterable {
    case brilliant = "!!", great, best, excellent
    case good = "!", interesting = "!?", dubious = "?!"
    case miss, mistake = "?", blunder = "??"
}
let (cleaned, annotation) = MoveAnnotation.extract(from: "Nf3!?")  // ("Nf3", .interesting)
let fromNag = MoveAnnotation.from(nag: 1)                          // .good
let suffix  = MoveAnnotation.brilliant.pgnSuffix                   // the PGN suffix

MoveQuality

Engine move-quality classification (display is left to the UI):

public enum MoveQuality: String, CaseIterable, Sendable {
    case best, excellent, good, inaccuracy, mistake, blunder
}

GameState

public enum GameState: Equatable, Sendable {
    case playing, check, checkmate, stalemate
    case draw, insufficientMaterial, repetition
    public var isGameOver: Bool
}

Position

The complete board state, plus FEN parse/serialize and material/EP analysis.

public struct Position: Equatable, Sendable {
    public var board: [Piece?]              // 64 entries
    public var activeColor: PieceColor
    public var castlingRights: CastlingRights
    public var enPassantTarget: Square?
    public var halfmoveClock: Int
    public var fullmoveNumber: Int
    public var whiteKingSquare: Square
    public var blackKingSquare: Square

    public init()                            // empty board, White to move
    public init?(fen: String)                // standard FEN (failable)
    public subscript(square: Square) -> Piece? { get set }  // bounds-safe

    public static func initial() -> Position // standard start

    public var fen: String                   // full FEN incl. counters
    public var positionKey: String           // FEN without counters (the legality/transposition key)
    public var consistentFEN: String      // metadata reconciled with the placement
    public var capturableEnPassantTarget: Square?  // EP only when a capture exists
    public var hasInsufficientMaterial: Bool
}

See FEN for the three FEN-shaped accessors and when to use each.