Chess
chess is a set of go packages which provide common chess utilities such as move generation, turn management, checkmate detection, PGN encoding, UCI interoperability, image generation, opening book exploration, and others. It is well tested and optimized for performance.
Install / Use
/learn @CorentinGS/ChessREADME
Chess Library
Introduction
chess is a set of go packages which provide common chess utilities such as move generation, turn management, checkmate detection, PGN encoding, UCI interoperability, image generation, opening book exploration, and others. It is well tested and optimized for performance.

Recent Updates
Comprehensive Move Validation: All move methods now properly validate moves according to chess rules, returning descriptive errors for invalid moves. This ensures consistent game correctness across all move APIs.
Performance Options: Added unsafe variants for high-performance scenarios:
UnsafeMove()- ~1.5x faster thanMove()UnsafePushNotationMove()- ~1.1x faster thanPushNotationMove()
API Consistency: Refactored move methods for clear validation behavior and consistent performance options across all move APIs.
Why I Forked
I forked the original package for several reasons:
- Update Rate: The original package was not being updated at the pace I needed for my projects.
- Pending PRs: There were numerous pull requests that needed to be merged to make the package production-ready for my work.
- Performance and Allocations: I wanted to improve overall performance and reduce memory allocations.
- Customization: I had specific changes in mind that would not be easily integrated into the original package.
Credits
I want to extend my gratitude to the original author of notnil/chess for their amazing work. This fork is not intended to steal or replace their work but to build upon it, providing an alternative for the open-source community and allowing for faster development.
Disclaimer
Breaking Changes: This package is under the /v2 namespace to signify that it might not be backward compatible with
the original package.
While some parts might work as plug-and-play, others might require changes.
Unfortunately, I do not plan to maintain a breaking change list at this time, but I expect in-code comments and the
compiler/linter to assist with migration.
Maintenance: This package is primarily maintained for my current work and projects. It is shared as a respect for the original work and to contribute to the community. My main focus is:
- Rewriting code to reduce allocations
- Replacing strings with more efficient data structures where possible
- Improving performance
- Expanding test coverage and benchmarks
- Rewriting the parser for better performance and more features
- Potential major changes to the game representation to support variations
Contributions
I am open to suggestions, pull requests, and contributions from anyone interested in improving this library. If you have ideas or want to help make this package more robust and widely usable, please feel free to:
- Open issues for bugs or feature requests
- Submit pull requests with improvements or fixes
- Contact me directly for discussions or ideas
Repo Structure
| Package | Docs Link | Description | |-------------|-----------------------------------------------|----------------------------------------------------------------------------------------| | chess | corentings/chess | Move generation, serialization / deserialization, turn management, checkmate detection | | image | corentings/chess/image | SVG chess board image generation | | opening | corentings/chess/opening | Opening book interactivity | | uci | corentings/chess/uci | Universal Chess Interface client |
Installation
chess can be installed using "go get".
go get -u github.com/corentings/chess/v2
Usage
Example Random Game
package main
import (
"fmt"
"math/rand"
"github.com/corentings/chess/v2"
)
func main() {
game := chess.NewGame()
// generate moves until game is over
for game.Outcome() == chess.NoOutcome {
// select a random move
moves := game.ValidMoves()
move := moves[rand.Intn(len(moves))]
if err := game.Move(&move, nil); err != nil {
panic(err) // Should not happen with valid moves
}
}
// print outcome and game PGN
fmt.Println(game.Position().Board().Draw())
fmt.Printf("Game completed. %s by %s.\n", game.Outcome(), game.Method())
fmt.Println(game.String())
/*
Output:
A B C D E F G H
8- - - - - - - -
7- - - - - - ♚ -
6- - - - ♗ - - -
5- - - - - - - -
4- - - - - - - -
3♔ - - - - - - -
2- - - - - - - -
1- - - - - - - -
Game completed. 1/2-1/2 by InsufficientMaterial.
1.Nc3 b6 2.a4 e6 3.d4 Bb7 ...
*/
}
Example Stockfish v. Stockfish
package main
import (
"fmt"
"time"
"github.com/corentings/chess/v2"
"github.com/corentings/chess/v2/uci"
)
func main() {
// set up engine to use stockfish exe
eng, err := uci.New("stockfish")
if err != nil {
panic(err)
}
defer eng.Close()
// initialize uci with new game
if err := eng.Run(uci.CmdUCI, uci.CmdIsReady, uci.CmdUCINewGame); err != nil {
panic(err)
}
// have stockfish play speed chess against itself (10 msec per move)
game := chess.NewGame()
for game.Outcome() == chess.NoOutcome {
cmdPos := uci.CmdPosition{Position: game.Position()}
cmdGo := uci.CmdGo{MoveTime: time.Second / 100}
if err := eng.Run(cmdPos, cmdGo); err != nil {
panic(err)
}
move := eng.SearchResults().BestMove
if err := game.Move(move, nil); err != nil {
panic(err)
}
}
fmt.Println(game.String())
// Output:
// 1.c4 c5 2.Nf3 e6 3.Nc3 Nc6 4.d4 cxd4 5.Nxd4 Nf6 6.a3 d5 7.cxd5 exd5 8.Bf4 Bc5 9.Ndb5 O-O 10.Nc7 d4 11.Na4 Be7 12.Nxa8 Bf5 13.g3 Qd5 14.f3 Rxa8 15.Bg2 Rd8 16.b4 Qe6 17.Nc5 Bxc5 18.bxc5 Nd5 19.O-O Nc3 20.Qd2 Nxe2+ 21.Kh1 d3 22.Bd6 Qd7 23.Rab1 h6 24.a4 Re8 25.g4 Bg6 26.a5 Ncd4 27.Qb4 Qe6 28.Qxb7 Nc2 29.Qxa7 Ne3 30.Rb8 Nxf1 31.Qb6 d2 32.Rxe8+ Qxe8 33.Qb3 Ne3 34.h3 Bc2 35.Qxc2 Nxc2 36.Kh2 d1=Q 37.h4 Qg1+ 38.Kh3 Ne1 39.h5 Qxg2+ 40.Kh4 Nxf3# 0-1
}
Movement
Chess provides multiple ways of making moves: direct move execution, valid move generation, and notation parsing. All move methods include proper validation to ensure game correctness.
Move Methods
The library offers two move execution methods to balance safety and performance:
Move() - Validates moves before execution (recommended for general use):
game := chess.NewGame()
moves := game.ValidMoves()
err := game.Move(&moves[0], nil)
if err != nil {
// Handle invalid move error
}
UnsafeMove() - High-performance move execution without validation:
game := chess.NewGame()
moves := game.ValidMoves()
// Only use when you're certain the move is valid
err := game.UnsafeMove(&moves[0], nil)
if err != nil {
// Handle error (should not occur with valid moves)
}
PushNotationMove() - Validates moves using any notation (recommended for general use):
game := chess.NewGame()
err := game.PushNotationMove("e4", chess.AlgebraicNotation{}, nil)
if err != nil {
// Handle invalid move or notation error
}
UnsafePushNotationMove() - High-performance notation parsing without move validation:
game := chess.NewGame()
// Only use when you're certain the move is valid
err := game.UnsafePushNotationMove("e4", chess.AlgebraicNotation{}, nil)
if err != nil {
// Handle notation parsing error (should not occur with valid notation)
}
Performance Note:
UnsafeMove()provides ~1.5x performance improvement overMove()by skipping validationUnsafePushNotationMove()provides ~1.1x performance improvement overPushNotationMove()by skipping move validation- Use unsafe variants only when moves are pre-validated or known to be legal
Valid Moves
Valid moves generated from the game's current position:
game := chess.NewGame()
moves := game.ValidMoves()
game.Move(&moves[0], nil)
fmt.Println(moves[0]) // b1a3
Parse Notation
PushNotationMove method accepts string input using any supported notation:
game := chess.NewGame()
if err := game.PushNotationMove("e4", chess.AlgebraicNotation{}, nil); err != nil {
// handle error
}
Move Validation
All move methods automatically validate moves according to chess rules. The Move() method validates moves before
execution and returns descriptive errors for invalid moves:
game := chess.NewGame()
// Get valid moves from current position
validMoves := game.ValidMoves()
if len(validMoves) > 0 {
// This will succeed - move is known to be valid
if err := game.Move(&validMoves[0], nil); err != nil {
fmt.Println("Move failed:", err)
} else {
fmt.Println("Move succeeded")
}
}
// Using notation parsing with validation
if err := game.PushNotationMove("e4", chess.AlgebraicNotation{}, nil); err != nil {
fmt.Println("Move failed:", err)
} else {
fmt.Println("e4 move suc
Related Skills
docs-writer
99.1k`docs-writer` skill instructions As an expert technical writer and editor for the Gemini CLI project, you produce accurate, clear, and consistent documentation. When asked to write, edit, or revie
model-usage
336.2kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
Design
Campus Second-Hand Trading Platform \- General Design Document (v5.0 \- React Architecture \- Complete Final Version)1\. System Overall Design 1.1. Project Overview This project aims t
arscontexta
2.9kClaude Code plugin that generates individualized knowledge systems from conversation. You describe how you think and work, have a conversation and get a complete second brain as markdown files you own.
