chess

package module
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Dec 24, 2024 License: AGPL-3.0 Imports: 10 Imported by: 0

README

brighamskarda/chess

I used this project to learn GoLang. This library supports all of the following features:

  • FEN parsing and generation
  • PGN parsing and generation
  • Legal move generation
  • Pseudo-legal move generation
  • UCI move parsing and generation
  • SAN move parsing and generation
  • Checks for Checkmate and Stalemate (including three-fold repetition)

All functionality has been thoroughly tested (including parsing and writing over 20,000 PGNs which hits nearly every part of the code base including move generation).

Usage

I recommend taking at look at the docs at https://pkg.go.dev/ as all non-obvious functions should be documented there.

If you are looking to create a chess application I recommend using the Game struct as it keeps track of move history and always ensures that the game is in a valid state.

For engine development I recommend using the Position struct as it allows for quick and easy access and modification of the game state. Using Move on a position does not check for move validity which increases engine speed.

Future Development

I am currently working on version 2.0 of this library. It will feature a fully bitboard based position representation. The hope is that this will speed up the move generating portions of the library.

Contact info

I'm very happy to consider changes to the API to make things feel better. Feel free to email me, or post an issue. I'm even open to pull requests should you feel the urge to contribute.

Documentation

Index

Constants

View Source
const DefaultFen string = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"

Variables

View Source
var (
	NoSquare = Square{}

	A8 = Square{FileA, Rank8}
	B8 = Square{FileB, Rank8}
	C8 = Square{FileC, Rank8}
	D8 = Square{FileD, Rank8}
	E8 = Square{FileE, Rank8}
	F8 = Square{FileF, Rank8}
	G8 = Square{FileG, Rank8}
	H8 = Square{FileH, Rank8}

	A7 = Square{FileA, Rank7}
	B7 = Square{FileB, Rank7}
	C7 = Square{FileC, Rank7}
	D7 = Square{FileD, Rank7}
	E7 = Square{FileE, Rank7}
	F7 = Square{FileF, Rank7}
	G7 = Square{FileG, Rank7}
	H7 = Square{FileH, Rank7}

	A6 = Square{FileA, Rank6}
	B6 = Square{FileB, Rank6}
	C6 = Square{FileC, Rank6}
	D6 = Square{FileD, Rank6}
	E6 = Square{FileE, Rank6}
	F6 = Square{FileF, Rank6}
	G6 = Square{FileG, Rank6}
	H6 = Square{FileH, Rank6}

	A5 = Square{FileA, Rank5}
	B5 = Square{FileB, Rank5}
	C5 = Square{FileC, Rank5}
	D5 = Square{FileD, Rank5}
	E5 = Square{FileE, Rank5}
	F5 = Square{FileF, Rank5}
	G5 = Square{FileG, Rank5}
	H5 = Square{FileH, Rank5}

	A4 = Square{FileA, Rank4}
	B4 = Square{FileB, Rank4}
	C4 = Square{FileC, Rank4}
	D4 = Square{FileD, Rank4}
	E4 = Square{FileE, Rank4}
	F4 = Square{FileF, Rank4}
	G4 = Square{FileG, Rank4}
	H4 = Square{FileH, Rank4}

	A3 = Square{FileA, Rank3}
	B3 = Square{FileB, Rank3}
	C3 = Square{FileC, Rank3}
	D3 = Square{FileD, Rank3}
	E3 = Square{FileE, Rank3}
	F3 = Square{FileF, Rank3}
	G3 = Square{FileG, Rank3}
	H3 = Square{FileH, Rank3}

	A2 = Square{FileA, Rank2}
	B2 = Square{FileB, Rank2}
	C2 = Square{FileC, Rank2}
	D2 = Square{FileD, Rank2}
	E2 = Square{FileE, Rank2}
	F2 = Square{FileF, Rank2}
	G2 = Square{FileG, Rank2}
	H2 = Square{FileH, Rank2}

	A1 = Square{FileA, Rank1}
	B1 = Square{FileB, Rank1}
	C1 = Square{FileC, Rank1}
	D1 = Square{FileD, Rank1}
	E1 = Square{FileE, Rank1}
	F1 = Square{FileF, Rank1}
	G1 = Square{FileG, Rank1}
	H1 = Square{FileH, Rank1}

	AllSquares = [64]Square{
		A8, B8, C8, D8, E8, F8, G8, H8,
		A7, B7, C7, D7, E7, F7, G7, H7,
		A6, B6, C6, D6, E6, F6, G6, H6,
		A5, B5, C5, D5, E5, F5, G5, H5,
		A4, B4, C4, D4, E4, F4, G4, H4,
		A3, B3, C3, D3, E3, F3, G3, H3,
		A2, B2, C2, D2, E2, F2, G2, H2,
		A1, B1, C1, D1, E1, F1, G1, H1,
	}
)

Functions

func ChebyshevDistance

func ChebyshevDistance(s1 Square, s2 Square) uint8

ChebyshevDistance returns the number of king moves between two squares. Returns math.MaxUint8 if either square is invalid.

func GenerateFen

func GenerateFen(p *Position) string

func IsCheck

func IsCheck(p *Position) bool

IsCheck returns true if the side to move is currently in check.

func IsCheckMate

func IsCheckMate(p *Position) bool

IsCheckMate returns true is the side to move is in check and has no legal moves.

func IsStaleMate

func IsStaleMate(p *Position) bool

IsStaleMate does not check the fifty move rule. It only checks if a player is not able to move, and is not in check.

func IsValidPosition

func IsValidPosition(p *Position) bool

IsValidPosition determines if a given position is a legal chess position. It checks the following:

  • There is one king of each color on the board
  • There are no pawns on their last rank
  • Castling rights are logical
  • The enPassant Square is logical
  • Turn is set
  • All pieces are valid chess pieces

func ManhattanDistance

func ManhattanDistance(s1 Square, s2 Square) uint8

ManhattanDistance give the number of non-diagonal king moves to get from s1 to s2. Returns math.MaxUint8 if either square is not a valid chess square.

func WritePgn

func WritePgn(g *Game, w io.Writer) error

WritePgn writes a pgn representation of g to w.

Types

type Color

type Color uint8
const (
	NoColor Color = iota
	White
	Black
)

func (Color) String

func (c Color) String() string

String returns one of NO-COLOR, WHITE, BLACK, or INVALID COLOR

type File

type File uint8
const (
	NoFile File = iota
	FileA
	FileB
	FileC
	FileD
	FileE
	FileF
	FileG
	FileH
)

func (File) String

func (f File) String() string

String returns a single uppercase letter representing the file.

type Game

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

Game is guaranteed to always represent a valid game of chess. Invalid positions are not allowed, but the move history may not represent an entire game (undoing all moves may not lead to the starting chess position). Game can be used to parse and generate PGNs. Additionally Game provides many wrapper methods for functions that normally take position as an argument, increasing convenience and decreasing the need to copy Game's position excessively.

The zero value for Game is not valid and should not be used. Game should always be duplicated using the Game.Copy function.

func NewGame

func NewGame() *Game

NewGame returns a *Game representing the starting position for a game of chess.

func ReadPgn

func ReadPgn(r io.Reader) (*Game, error)

ReadPgn attempts to create a Game from r. Parsing should be improved in the future, but for now only well formatted pgns containing a single game are accepted. Refer to http://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm for specific details of how a pgn should be formatted.

func (*Game) BlackKingSideCastle

func (g *Game) BlackKingSideCastle() bool

func (*Game) BlackQueenSideCastle

func (g *Game) BlackQueenSideCastle() bool

func (*Game) CanClaimDraw

func (g *Game) CanClaimDraw() bool

CanClaimDraw returns true if one of the following conditions is true and the game is not in checkmate

  • The half move counter is >= 100 (indicating that no piece has been taken, nor pawn moved forward for 50 moves)
  • The game contains a three fold repetition (the exact same position has occurred three times in the game)
  • The game is in stalemate

func (*Game) Copy

func (g *Game) Copy() *Game

Returns a copy of current game.

func (*Game) EnPassant

func (g *Game) EnPassant() Square

func (*Game) FullMove

func (g *Game) FullMove() uint16

func (*Game) GetAllTags

func (g *Game) GetAllTags() map[string]string

func (*Game) GetResult

func (g *Game) GetResult() Result

GetResult gets the current result tag for the game. This result should be valid, but there are no calculations being performed in this function.

func (*Game) GetTag

func (g *Game) GetTag(t string) (string, error)

func (*Game) HalfMove

func (g *Game) HalfMove() uint16

func (*Game) HasThreeFoldRepetition

func (g *Game) HasThreeFoldRepetition() bool

HasThreeFoldRepetition returns true if the game has been in the exact same position (including castling rights) At least three times at any point during the entire game.

func (*Game) IsCheckMate

func (g *Game) IsCheckMate() bool

IsCheckMate returns true is the side to move is in check and has no legal moves.

func (*Game) IsStaleMate

func (g *Game) IsStaleMate() bool

IsStaleMate does not check the fifty move rule. It only checks if a player is not able to move, and is not in check.

func (*Game) LegalMoves

func (g *Game) LegalMoves() []Move

func (*Game) Move

func (g *Game) Move(m Move) error

Move performs the given move. If move m is not legal g remains unchanged and an error is returned. If the move is legal the result tag is set to * (NoResult). If the position ends in checkmate or stalemate the result tag is updated accordingly.

func (*Game) MoveSan

func (g *Game) MoveSan(s string) error

MoveSan is a helper function that automatically performs an SAN formatted move. SAN format is specified here: http://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm#c8.2.3

func (*Game) Position

func (g *Game) Position() *Position

Position returns a copy of the game's position.

func (*Game) PrintPosition added in v1.0.2

func (g *Game) PrintPosition()

PrintPosition prints the current position from the point of view for the current player to move.

func (*Game) RemoveTag

func (g *Game) RemoveTag(tag string)

Remove tag will remove any pgn tag except the 7 required tags specified here, and the SetUp and FEN tags specified here. If you wish to remove the SetUp and FEN tags it is best to simply make a new game.

func (*Game) SetPosition

func (g *Game) SetPosition(p *Position) error

SetPosition sets the games position to the given position only if the position is a valid chess position. The result tag is updated to match if the game is in mate, or could still be going. Move history is cleared, and the pgn tags "SetUp" and "FEN" are set accordingly.

func (*Game) SetResult

func (g *Game) SetResult(r Result)

func (*Game) SetTag

func (g *Game) SetTag(tag string, value string)

SetTag sets any tag for the game so that it will show up in the pgn file. The Result, SetUp, and FEN tags cannot be set with this function. Please use the Game.SetResult function to set the result, and the Game.SetPosition function to set the other two tags.

func (*Game) String

func (g *Game) String() string

String returns the games current position as a string..

func (*Game) Turn

func (g *Game) Turn() Color

func (*Game) WhiteKingSideCastle

func (g *Game) WhiteKingSideCastle() bool

func (*Game) WhiteQueenSideCastle

func (g *Game) WhiteQueenSideCastle() bool

type Move

type Move struct {
	FromSquare Square
	ToSquare   Square
	Promotion  PieceType
}

func GenerateLegalMoves

func GenerateLegalMoves(p *Position) []Move

GenerateLegalMoves expects a valid position. Behavior is undefined for invalid positions. This is to improve performance since move generation is a vital part to engine development.

func GeneratePseudoLegalMoves

func GeneratePseudoLegalMoves(p *Position) []Move

GeneratePseudoLegalMoves expects a valid position. Behavior is undefined for invalid positions. This is to improve performance since move generation is a vital part to engine development.

func ParseSANMove

func ParseSANMove(p *Position, s string) (Move, error)

ParseSANMove returns a move given a position and an SAN formatted move. SAN format defined here: http://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm#c8.2.3

func ParseUCIMove

func ParseUCIMove(s string) (Move, error)

ParseUCIMove expects a UCI compatible move string. Format should be Square1Square2Promotion, where promotion is optional.

func (Move) SanString

func (m Move) SanString(p *Position) string

SanString converts a move to standard algebraic notation. It needs position information to do this. The position provided should be the position just before the move was made. Expects that move and position are valid. Results are undefined otherwise.

func (Move) String

func (m Move) String() string

String returns a UCI-compatible string representation of the move. Format is Square1Square2Promotion

type Piece

type Piece struct {
	Color Color
	Type  PieceType
}
var (
	NoPiece Piece = Piece{NoColor, NoPieceType}

	WhitePawn   Piece = Piece{White, Pawn}
	WhiteRook   Piece = Piece{White, Rook}
	WhiteKnight Piece = Piece{White, Knight}
	WhiteBishop Piece = Piece{White, Bishop}
	WhiteQueen  Piece = Piece{White, Queen}
	WhiteKing   Piece = Piece{White, King}

	BlackPawn   Piece = Piece{Black, Pawn}
	BlackRook   Piece = Piece{Black, Rook}
	BlackKnight Piece = Piece{Black, Knight}
	BlackBishop Piece = Piece{Black, Bishop}
	BlackQueen  Piece = Piece{Black, Queen}
	BlackKing   Piece = Piece{Black, King}
)

func ParsePiece

func ParsePiece(r rune) (Piece, error)

ParsePiece attempts to parse a piece from a given rune. Currently only supports ascii characters (no piece symbols). Uppercase is white, lowercase is black.

func (Piece) String

func (p Piece) String() string

String gives a one letter ascii character representing the piece. " " for no piece. INVALID PIECE otherwise.

type PieceType

type PieceType uint8
const (
	NoPieceType PieceType = iota
	Pawn
	Rook
	Knight
	Bishop
	Queen
	King
)

func (PieceType) String

func (pt PieceType) String() string

String returns the uppercase ascii letter representation of the piece. NO-PIECE-TYPE, or INVALID PIECE TYPE otherwise.

type Position

type Position struct {
	Board                [64]Piece
	Turn                 Color
	WhiteKingSideCastle  bool
	WhiteQueenSideCastle bool
	BlackKingSideCastle  bool
	BlackQueenSideCastle bool
	EnPassant            Square
	HalfMove             uint16
	FullMove             uint16
}

Position represents a chess position as described by Forsyth-Edwards Notation (FEN). Board is the actual representation of the pieces on the squares. It starts at A8 and moves left to right, top to bottom all the way to H1.

func ParseFen

func ParseFen(fen string) (*Position, error)

ParseFen take only fully formed valid FEN strings. All parts of the FEN must be present, though the position need not necessarily be valid.

func (*Position) FormatString added in v1.0.1

func (p *Position) FormatString(blacksPerspective bool) string

FormatString returns a representation of the board. No other information from the position is printed. blacksPerspective should be true if you which to print the board as if you were on black's side.

func (*Position) Move

func (p *Position) Move(m Move)

Position.Move does no checking of move legality. For checked moves use Game.Move, or check that your move is in the list provided by GenerateLegalMoves. All parts of the position are updated including en passant and castling rights based how the the move interacts with the board.

func (*Position) PieceAt

func (p *Position) PieceAt(s Square) Piece

func (*Position) SetPieceAt

func (p *Position) SetPieceAt(s Square, piece Piece)

func (*Position) String

func (p *Position) String() string

String returns a representation of the board from white's perspective. No other information from the position is printed. It is recommended to use Position.FormatString to print from black's perspective.

type Rank

type Rank uint8
const (
	NoRank Rank = iota
	Rank1
	Rank2
	Rank3
	Rank4
	Rank5
	Rank6
	Rank7
	Rank8
)

func (Rank) String

func (r Rank) String() string

String returns either a single number, INVALID RANK, or NO RANK.

type Result

type Result byte
const (
	NoResult Result = iota
	WhiteWins
	BlackWins
	Draw
)

func (Result) String

func (r Result) String() string

String returns

type Square

type Square struct {
	File File
	Rank Rank
}

func ParseSquare

func ParseSquare(s string) (Square, error)

ParseSquare parses a two letter string for a square. "-" returns NoSquare without an error.

func (Square) String

func (s Square) String() string

String returns a two letter uppercase representation of a square. "-" will be returned for NoSquare and INVALID SQUARE will be returned for all other squares that can't be found on a chess board.

Jump to

Keyboard shortcuts

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