chess

package module
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2025 License: MIT Imports: 14 Imported by: 0

README

Chess (Go Edition)

A Go port of the Node Chess engine that focuses on algebraic notation.
It parses and validates moves, tracks rich game state, and exposes an event-driven API that integrates cleanly with Go applications.

Featuring

  • Notation-first game play – list every legal move in algebraic notation, accepts algebraic input and surface promotion choices.
  • Robust state inspection – detect check, checkmate, stalemate, and threefold repetition while keeping a complete capture and move history.
  • Undo-friendly move execution – every applied move returns an undo handle and updates castling rights, en passant targets, and move counters.
  • FEN integration – load games from Forsyth–Edwards Notation, emit FEN snapshots after every move, or explore alternate continuations.
  • Event-driven hooks – subscribe to move, capture, castle, promotion, undo, check, and checkmate notifications from multiple abstraction layers.
  • Opening library - iterable and searchable library of openings, with ECO and FEN

Table of Contents

Installation

go get github.com/brozeph/chess@latest

Import the package in your Go code:

import "github.com/brozeph/chess"

Quickstart

package main

import (
 "fmt"
 "log"

 "github.com/brozeph/chess"
)

func main() {
 client := chess.CreateAlgebraicGameClient()

 status, err := client.Status()
 if err != nil {
  log.Fatal(err)
 }

 fmt.Printf("FEN: %s\n", client.FEN())
 fmt.Printf("Side to move: %s\n", status.Side().Name())

 for notation := range status.NotatedMoves {
  fmt.Println(notation)
 }
}

Using the Opening Library

The package ships with a curated ECO-backed opening database (data/openings.csv). The CSV is embedded into the module... load it once and iterate or search:

ol, err := chess.CreateOpeningsLibrary()
if err != nil {
 log.Fatal(err)
}

// Iterate all openings (10k+ entries) lazily
iter := ol.All()
iter(func(op chess.Opening) bool {
 fmt.Printf("%s %s -> %s\n", op.ECO, op.Name, op.ResultFEN)
 return true
})

// Look up by ECO or by final FEN
if op, ok := ol.FindOpeningByECO("C60"); ok {
 fmt.Println("Found:", op.Name)
}

if op, ok := ol.FindOpeningByFEN("r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3"); ok {
 fmt.Println("Reached via:", op.SequenceMoves)
}

// Explore continuations after a position appears anywhere in the sequence.
if next, ok := ol.FindVariationsByFEN("r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3"); ok {
 fmt.Println("Possible continuations:", next)
}

Each Opening exposes the ECO code, friendly name, raw move text (SequenceMoves), and every intermediate FEN (SequenceFENs), making it easy to link engine positions back to common theory.

Inspecting Valid Moves

Status() returns a *chess.GameStatus that stays in sync with the underlying game:

status, err := client.Status()
if err != nil {
 log.Fatal(err)
}

fmt.Println("Check:", status.IsCheck)
fmt.Println("Checkmate:", status.IsCheckmate)
fmt.Println("Stalemate:", status.IsStalemate)
fmt.Println("Threefold repetition:", status.IsRepetition)

for algebraic, move := range status.NotatedMoves {
 src := fmt.Sprintf("%c%d", move.Src.File, move.Src.Rank)
 dst := fmt.Sprintf("%c%d", move.Dest.File, move.Dest.Rank)
 fmt.Printf("%-5s -> %s -> %s\n", algebraic, src, dst)
}

The NotatedMoves map is keyed by algebraic notation and each entry exposes the source/destination squares through move.Src and move.Dest.

Making and Undoing Moves

result, err := client.Move("e4")
if err != nil {
 log.Fatalf("illegal move: %v", err)
}

fmt.Printf("Played: %s\n", result.Move.Algebraic)
fmt.Printf("Piece: %s\n", result.Move.Piece.Notation)
fmt.Printf("FEN after move: %s\n", client.FEN())

// Undo later if needed.
result.Undo()
  • Promotions can be specified by suffixing the desired piece (e8=Q, exd8N, etc.).
  • result.Move gives full context including castling, en passant, captured piece, and rook movement when appropriate.

Loading Custom Positions

client, err := chess.CreateAlgebraicGameClientFromFEN(
 "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
)
if err != nil {
 log.Fatal(err)
}

status, _ := client.Status()
fmt.Printf("Side to move: %s\n", status.Side().Name())
  • All FEN components (castling availability, en-passant target, half-move clock, full-move number) are respected.
  • Call Status(true) to force recalculation if you have manipulated the underlying board state directly.

Event API

Subscribe to events using On:

client.On("move", func(data interface{}) {
 if mv, ok := data.(*chess.MoveEvent); ok {
  fmt.Printf("%s to %c%d\n", mv.Algebraic, mv.PostSquare.File, mv.PostSquare.Rank)
 }
})

client.On("checkmate", func(data interface{}) {
 if side, ok := data.(chess.Side); ok {
  fmt.Printf("%s was checkmated\n", side.Name())
 }
})
Event Payload type Description
move *chess.MoveEvent Emitted after every legal move.
capture *chess.MoveEvent Fired when a capture occurs.
castle *chess.MoveEvent Fired after a king-side or queen-side castle.
enPassant *chess.MoveEvent Fired when an en passant capture is performed.
promote *chess.Square Triggered after a pawn promotion; the square contains the promoted piece.
undo *chess.MoveEvent Emitted after a move has been reverted.
check chess.Side Indicates which side is currently in check.
checkmate chess.Side Indicates which side has been checkmated.

Events propagate from the board to the game and up to the algebraic client, so you can subscribe at whichever layer you interact with.

Understanding Returned Types

  • *chess.GameStatus – encapsulates the current Game, flags for check/checkmate/stalemate/repetition, and a NotatedMoves map. Use status.Side().Name() to see whose turn it is (or status.Side().Opponent() to get the opposing player).
  • *chess.MoveEvent – describes the move that just executed. Access prior and post squares (PrevSquare, PostSquare), captured pieces, promotion metadata, and rook movement on castling.
  • *chess.Square – exposes File, Rank, and the occupying *chess.Piece.
  • *chess.Piece – contains Type, Side, Notation, and MoveCount.
  • notationMove entries – each value from status.NotatedMoves exposes Src and Dest squares and a FEN(fen string) helper that applies the move to an arbitrary position.

CLI Example

The repository ships with a small CLI that mirrors the quickstart above:

go run ./examples/main.go \
  -fen "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1" \
  -moves "Nc6 Nc3"

Flags:

  • -fen – optional starting FEN (defaults to the initial position).
  • -moves – space separated algebraic moves to apply before printing the board.
  • -pgn – treat castling notation as PGN (O-O) instead of numeric (0-0).

Running without flags prints the initial position and the 20 legal opening moves.

Development

  • Go version: see go.mod (currently Go 1.24).

  • Run tests:

    go test ./...
    
  • Format code with gofmt before submitting patches.

License

MIT © Joshua Thomas. See LICENSE for details.

Documentation

Overview

Package chess provides a chess engine with a focus on algebraic notation, game state management, and move validation.

Index

Constants

View Source
const (
	NeighborAbove            neighbor = 8
	NeighborAboveLeft        neighbor = 7
	NeighborAboveRight       neighbor = 9
	NeighborBelow            neighbor = -8
	NeighborBelowLeft        neighbor = -9
	NeighborBelowRight       neighbor = -7
	NeighborLeft             neighbor = -1
	NeighborRight            neighbor = 1
	NeighborKnightAboveLeft  neighbor = 15
	NeighborKnightAboveRight neighbor = 17
	NeighborKnightBelowLeft  neighbor = -17
	NeighborKnightBelowRight neighbor = -15
	NeighborKnightLeftAbove  neighbor = 6
	NeighborKnightLeftBelow  neighbor = -10
	NeighborKnightRightAbove neighbor = 10
	NeighborKnightRightBelow neighbor = -6
)

Variables

This section is empty.

Functions

func CreateBoardValidator

func CreateBoardValidator(g *Game) *boardValidator

func CreateGameValidator

func CreateGameValidator(g *Game) *gameValidator

func CreateOpeningsLibrary added in v0.1.2

func CreateOpeningsLibrary() (*openingsLibrary, error)

CreateOpeningsLibrary initializes a new openings library by reading from the default openings CSV file. It returns an error if the file cannot be read or parsed.

func CreatePieceValidator

func CreatePieceValidator(pt pieceType, b *Board) *pieceValidator

CreatePieceValidator initializes a new validator for a specific piece type on a given board. It configures movement rules (e.g., diagonal, horizontal) and repetition counts based on the piece type.

Types

type AlgebraicClientOptions

type AlgebraicClientOptions struct {
	PGN bool // PGN specifies whether to use PGN-style notation for castling (O-O) instead of (0-0).
}

AlgebraicClientOptions provides configuration options for an AlgebraicGameClient.

type AlgebraicGameClient

type AlgebraicGameClient struct {
	// contains filtered or unexported fields
}

AlgebraicGameClient provides a client for interacting with a chess game using algebraic notation.

func CreateAlgebraicGameClient

func CreateAlgebraicGameClient(opts ...AlgebraicClientOptions) *AlgebraicGameClient

CreateAlgebraicGameClient creates a new game client with a standard starting board. It accepts optional AlgebraicClientOptions.

func CreateAlgebraicGameClientFromFEN

func CreateAlgebraicGameClientFromFEN(fen string, opts ...AlgebraicClientOptions) (*AlgebraicGameClient, error)

CreateAlgebraicGameClientFromFEN creates a new game client from a FEN string. It returns an error if the FEN string is invalid.

func (*AlgebraicGameClient) CaptureHistory

func (c *AlgebraicGameClient) CaptureHistory() []*Piece

CaptureHistory returns a slice of pieces that have been captured during the game.

func (*AlgebraicGameClient) FEN

func (c *AlgebraicGameClient) FEN() string

FEN returns the Forsyth-Edwards Notation (FEN) string for the current board state.

func (*AlgebraicGameClient) Move

func (c *AlgebraicGameClient) Move(ntn string) (*moveResult, error)

Move attempts to make a move using algebraic notation.

func (*AlgebraicGameClient) On

func (c *AlgebraicGameClient) On(ev string, hndlr func(any))

On registers an event handler for the given event. The client supports the following events:

  • "move": emitted after a piece has been moved. The handler receives a *MoveEvent.
  • "capture": emitted when a piece is captured. The handler receives a *MoveEvent.
  • "castle": emitted when a castling move is performed. The handler receives a *MoveEvent.
  • "enPassant": emitted when an en passant capture occurs. The handler receives a *MoveEvent.
  • "promote": emitted when a pawn is promoted. The handler receives the promoted *Square.
  • "undo": emitted after a move has been undone. The handler receives the undone *MoveEvent.
  • "check": emitted when a player is put in check. The handler receives a *KingThreatEvent.
  • "checkmate": emitted when a player is checkmated. The handler receives a *KingThreatEvent.

func (*AlgebraicGameClient) Status

func (c *AlgebraicGameClient) Status(frc ...bool) (*GameStatus, error)

Status returns the current status of the game. If force is true, it will re-calculate all valid moves and game-end conditions.

type Board

type Board struct {
	// Squares is a slice of 64 squares representing the board.
	Squares []*Square
	// LastMovedPiece points to the piece that was last moved.
	LastMovedPiece *Piece
	// contains filtered or unexported fields
}

Board represents the chess board and its state. It contains all the squares and the last moved piece. It can emit events for moves, captures, promotions, etc.

func (*Board) GetSquare

func (b *Board) GetSquare(f rune, r int) *Square

GetSquare returns the square at the given file and rank.

func (*Board) Move

func (b *Board) Move(src, dst *Square, sim bool, not ...string) (*moveResult, error)

Move performs a move on the board from a source square to a destination square. If simulate is true, the move is not committed to the board's history and no events are emitted. The returned moveResult contains an `undo` function that can be called to revert the move. It returns an error if the move is invalid.

func (*Board) Promote

func (b *Board) Promote(sq *Square, p *Piece) (*Square, error)

Promote replaces the piece on a given square with a new piece. This is used for pawn promotion. It emits a "promote" event.

type Game

type Game struct {
	// Board is the current chessboard state.
	Board *Board
	// CaptureHistory is a list of pieces that have been captured.
	CaptureHistory []*Piece
	// MoveHistory is a chronological record of all moves made in the game.
	MoveHistory []*MoveEvent
	// contains filtered or unexported fields
}

Game represents the state of a single chess game. It manages the board, move history, captured pieces, and turn sequence.

type GameStatus added in v0.0.6

type GameStatus struct {
	Game         *Game                   // The current game state.
	IsCheck      bool                    // True if the current player is in check.
	IsCheckmate  bool                    // True if the current player is in checkmate.
	IsRepetition bool                    // True if the current board state is a result of repetition.
	IsStalemate  bool                    // True if the game is a stalemate.
	NotatedMoves map[string]notationMove // A map of all valid moves in algebraic notation.
}

GameStatus represents the state of the game at a certain point in time.

func (*GameStatus) Side added in v0.0.6

func (s *GameStatus) Side() Side

Side returns the side of the player who made the last move. If no moves have been made, it defaults to sideWhite (unless this state has been overridden for the game).

type KingThreatEvent added in v0.1.0

type KingThreatEvent struct {
	AttackingSquare *Square
	KingSquare      *Square
}

type MoveEvent added in v0.1.0

type MoveEvent struct {
	Algebraic              string
	CapturedPiece          *Piece
	Castle                 bool
	EnPassant              bool
	Piece                  *Piece
	PostSquare             *Square
	PrevSquare             *Square
	Promotion              bool
	RookSource             *Square
	RookDestination        *Square
	EnPassantCaptureSquare *Square
	// contains filtered or unexported fields
}

type Opening added in v0.1.2

type Opening struct {
	// ECO is the Encyclopedia of Chess Openings code (e.g., "A00").
	ECO string
	// Moves is a slice of algebraic notation strings representing the move sequence.
	Moves []string
	// Name is the common name of the opening (e.g., "Ruy Lopez").
	Name string
	// ResultFEN is the Forsyth-Edwards Notation string of the final board position.
	ResultFEN string
	// SequenceFENs is a slice of FEN strings for each board state in the opening sequence.
	SequenceFENs []string
	// SequenceMoves is a string representation of each turn
	SequenceMoves string
}

Opening represents a single chess opening, including its name, move sequence, and the FEN strings for each position in the sequence.

type Piece

type Piece struct {
	// Type is the type of the piece (e.g., Pawn, Rook, King).
	Type pieceType
	// Side is the color of the piece (White or Black).
	Side Side
	// Notation is the standard algebraic notation for the piece (e.g., "R" for Rook).
	// Pawns have an empty string.
	Notation string
	// MoveCount tracks how many times the piece has moved. This is important for castling and pawn's first move.
	MoveCount int
}

Piece represents a single chess piece on the board.

func (*Piece) AlgebraicSymbol

func (p *Piece) AlgebraicSymbol() rune

AlgebraicSymbol returns the rune used to represent the piece in various notations. White pieces are uppercase (e.g., 'P'), and black pieces are lowercase (e.g., 'p').

type Side

type Side int

Side represents a player's color (White or Black).

func (Side) Name added in v0.0.4

func (s Side) Name() string

Name returns the string representation of the side ("white" or "black").

func (Side) Opponent added in v0.0.4

func (s Side) Opponent() Side

Opponent returns the opposing side.

type Square

type Square struct {
	File  rune
	Rank  int
	Piece *Piece
}

Directories

Path Synopsis
tools
openings command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL