chessmodels

package module
v1.8.0 Latest Latest
Warning

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

Go to latest
Published: Feb 5, 2022 License: MIT Imports: 1 Imported by: 4

README

go-chess-models

GoDoc Go Report Card Build Status codecov

The library that implements checking and generating of chess moves.

Disclaimer: this library was written directly on an Android smartphone with the AnGoIde IDE.

Features

  • representing the board:
    • as an associative array of pieces with their positions as keys;
    • as a plain array of pieces with exact correspondence array indices to piece positions;
  • immutable applicating moves to the board via copying the latter;
  • checkings of moves:
    • universal;
    • individual for all types of pieces;
  • generating moves via filtering from all possible ones;
  • perft function;
  • using an abstraction of a piece;
  • Forsyth–Edwards Notation:
    • parsing:
      • of a position;
      • of a move;
      • of a piece kind;
      • of a piece color;
      • of a board;
    • serialization:
      • of a position;
      • of a move;
      • of a piece kind;
      • of a piece color;
      • of a board;
  • utilities:
    • utility for counting all possible moves (based on the perft function).

Installation

$ go get github.com/thewizardplusplus/go-chess-models

Examples

chessmodels.Board.CheckMove():

package main

import (
	"fmt"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/pieces"
)

func main() {
	board := models.NewBoard(models.Size{Width: 5, Height: 5}, []models.Piece{
		pieces.NewRook(models.Black, models.Position{File: 2, Rank: 2}),
		pieces.NewBishop(models.White, models.Position{File: 3, Rank: 3}),
	})

	moveOne := models.Move{
		Start:  models.Position{File: 2, Rank: 2},
		Finish: models.Position{File: 3, Rank: 3},
	}
	fmt.Printf("%+v: %v\n", moveOne, board.CheckMove(moveOne))

	moveTwo := models.Move{
		Start:  models.Position{File: 3, Rank: 3},
		Finish: models.Position{File: 2, Rank: 2},
	}
	fmt.Printf("%+v: %v\n", moveTwo, board.CheckMove(moveTwo))

	// Output:
	// {Start:{File:2 Rank:2} Finish:{File:3 Rank:3}}: illegal move
	// {Start:{File:3 Rank:3} Finish:{File:2 Rank:2}}: <nil>
}

chessmodels.Board.ApplyMove():

package main

import (
	"fmt"
	"sort"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/pieces"
)

type ByPosition []models.Piece

func (group ByPosition) Len() int {
	return len(group)
}

func (group ByPosition) Swap(i, j int) {
	group[i], group[j] = group[j], group[i]
}

func (group ByPosition) Less(
	i, j int,
) bool {
	a, b := group[i].Position(), group[j].Position()
	if a.File == b.File {
		return a.Rank < b.Rank
	}

	return a.File < b.File
}

func main() {
	board := models.NewBoard(models.Size{Width: 5, Height: 5}, []models.Piece{
		pieces.NewRook(models.Black, models.Position{File: 2, Rank: 2}),
		pieces.NewBishop(models.White, models.Position{File: 3, Rank: 3}),
	})
	pieces := board.Pieces()
	sort.Sort(ByPosition(pieces))
	fmt.Printf("%+v\n", pieces)

	updatedBoard := board.ApplyMove(models.Move{
		Start:  models.Position{File: 3, Rank: 3},
		Finish: models.Position{File: 2, Rank: 2},
	})
	updatedPieces := updatedBoard.Pieces()
	sort.Sort(ByPosition(updatedPieces))
	fmt.Printf("%+v\n", updatedPieces)

	// Output:
	// [{Base:{kind:2 color:0 position:{File:2 Rank:2}}} {Base:{kind:3 color:1 position:{File:3 Rank:3}}}]
	// [{Base:{kind:3 color:1 position:{File:2 Rank:2}}}]
}

chessmodels.MoveGenerator.MovesForColor():

package main

import (
	"fmt"
	"sort"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/pieces"
)

func main() {
	board := models.NewBoard(models.Size{Width: 5, Height: 5}, []models.Piece{
		pieces.NewRook(models.Black, models.Position{File: 2, Rank: 2}),
		pieces.NewKnight(models.White, models.Position{File: 3, Rank: 3}),
		pieces.NewPawn(models.White, models.Position{File: 4, Rank: 3}),
	})

	var generator models.MoveGenerator
	moves, _ := generator.MovesForColor(board, models.White)

	// sorting only by the final point will be sufficient for the reproducibility
	// of this example
	sort.Slice(moves, func(i int, j int) bool {
		a, b := moves[i].Finish, moves[j].Finish
		if a.File == b.File {
			return a.Rank < b.Rank
		}

		return a.File < b.File
	})

	for _, move := range moves {
		fmt.Printf("%+v\n", move)
	}

	// Output:
	// {Start:{File:3 Rank:3} Finish:{File:1 Rank:2}}
	// {Start:{File:3 Rank:3} Finish:{File:1 Rank:4}}
	// {Start:{File:3 Rank:3} Finish:{File:2 Rank:1}}
	// {Start:{File:3 Rank:3} Finish:{File:4 Rank:1}}
	// {Start:{File:4 Rank:3} Finish:{File:4 Rank:4}}
}

uci.DecodeMove():

package main

import (
	"fmt"

	"github.com/thewizardplusplus/go-chess-models/encoding/uci"
)

func main() {
	move, _ := uci.DecodeMove("d4c3")
	fmt.Printf("%+v\n", move)

	// Output: {Start:{File:3 Rank:3} Finish:{File:2 Rank:2}}
}

uci.EncodeMove():

package main

import (
	"fmt"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/encoding/uci"
)

func main() {
	move := uci.EncodeMove(models.Move{
		Start:  models.Position{File: 3, Rank: 3},
		Finish: models.Position{File: 2, Rank: 2},
	})
	fmt.Printf("%v\n", move)

	// Output: d4c3
}

uci.DecodePieceStorage():

package main

import (
	"fmt"
	"sort"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/encoding/uci"
	"github.com/thewizardplusplus/go-chess-models/pieces"
)

type ByPosition []models.Piece

func (group ByPosition) Len() int {
	return len(group)
}

func (group ByPosition) Swap(i, j int) {
	group[i], group[j] = group[j], group[i]
}

func (group ByPosition) Less(
	i, j int,
) bool {
	a, b := group[i].Position(), group[j].Position()
	if a.File == b.File {
		return a.Rank < b.Rank
	}

	return a.File < b.File
}

func main() {
	const fen = "8/8/8/8/3B4/2r5/8/8"
	storage, _ := uci.DecodePieceStorage(fen, pieces.NewPiece, models.NewBoard)
	pieces := storage.Pieces()
	sort.Sort(ByPosition(pieces))
	fmt.Printf("%+v\n", pieces)

	// Output: [{Base:{kind:2 color:0 position:{File:2 Rank:2}}} {Base:{kind:3 color:1 position:{File:3 Rank:3}}}]
}

uci.EncodePieceStorage():

package main

import (
	"fmt"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/encoding/uci"
	"github.com/thewizardplusplus/go-chess-models/pieces"
)

func main() {
	board := models.NewBoard(models.Size{Width: 5, Height: 5}, []models.Piece{
		pieces.NewRook(models.Black, models.Position{File: 2, Rank: 2}),
		pieces.NewBishop(models.White, models.Position{File: 3, Rank: 3}),
	})
	fen := uci.EncodePieceStorage(board)
	fmt.Printf("%v\n", fen)

	// Output: 5/3B1/2r2/5/5
}

Benchmarks

The chessmodels.Perft() function using the chessmodels.MapBoard structure:

BenchmarkPerft/MapBoard/initial/1Ply-8         	     486	   2239365 ns/op	  507723 B/op	   13638 allocs/op
BenchmarkPerft/MapBoard/initial/2Ply-8         	      38	  27071904 ns/op	 6253672 B/op	  165159 allocs/op
BenchmarkPerft/MapBoard/initial/3Ply-8         	       3	 394039297 ns/op	91006645 B/op	 2399815 allocs/op
BenchmarkPerft/MapBoard/kiwipete/1Ply-8        	     150	   7844416 ns/op	 1959120 B/op	   47637 allocs/op
BenchmarkPerft/MapBoard/kiwipete/2Ply-8        	       4	 311539966 ns/op	80169034 B/op	 1892731 allocs/op

The chessmodels.Perft() function used the chessmodels.SliceBoard structure:

BenchmarkPerft/SliceBoard/initial/1Ply-8       	     810	   1419572 ns/op	   684016 B/op	   13646 allocs/op
BenchmarkPerft/SliceBoard/initial/2Ply-8       	      68	  17883575 ns/op	  8331384 B/op	  165074 allocs/op
BenchmarkPerft/SliceBoard/initial/3Ply-8       	       4	 253594389 ns/op	121325578 B/op	 2399248 allocs/op
BenchmarkPerft/SliceBoard/kiwipete/1Ply-8      	     220	   5340912 ns/op	  2583824 B/op	   47672 allocs/op
BenchmarkPerft/SliceBoard/kiwipete/2Ply-8      	       5	 208109435 ns/op	103011680 B/op	 1895999 allocs/op

Utilities

License

The MIT License (MIT)

Copyright © 2019, 2022 thewizardplusplus

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNoMove         = errors.New("no move")
	ErrOutOfSize      = errors.New("out of size")
	ErrNoPiece        = errors.New("no piece")
	ErrFriendlyTarget = errors.New("friendly target")
	ErrIllegalMove    = errors.New("illegal move")
	ErrKingCapture    = errors.New("king capture")
)

...

Functions

func CheckMove

func CheckMove(storage PieceStorage, move Move) error

CheckMove ...

It doesn't check for a check before or after the move.

func Perft

func Perft(
	generator PerftMoveGenerator,
	storage PieceStorage,
	color Color,
	deep int,
	handler PerftHandler,
) int

Perft ...

Types

type BaseBoard added in v1.8.0

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

BaseBoard ...

func NewBaseBoard added in v1.8.0

func NewBaseBoard(size Size) BaseBoard

NewBaseBoard ...

func (BaseBoard) Size added in v1.8.0

func (board BaseBoard) Size() Size

Size ...

type Board

type Board = SliceBoard

Board ...

type Color

type Color int

Color ...

const (
	Black Color = iota
	White
)

...

func (Color) Negative

func (color Color) Negative() Color

Negative ...

type Kind

type Kind int

Kind ...

const (
	King Kind = iota
	Queen
	Rook
	Bishop
	Knight
	Pawn
)

...

type MapBoard added in v1.8.0

type MapBoard struct {
	BaseBoard
	// contains filtered or unexported fields
}

MapBoard ...

func (MapBoard) ApplyMove added in v1.8.0

func (board MapBoard) ApplyMove(move Move) PieceStorage

ApplyMove ...

It doesn't check that the move is correct.

func (MapBoard) CheckMove added in v1.8.0

func (board MapBoard) CheckMove(move Move) error

CheckMove ...

It doesn't check for a check before or after the move.

func (MapBoard) Piece added in v1.8.0

func (board MapBoard) Piece(position Position) (piece Piece, ok bool)

Piece ...

func (MapBoard) Pieces added in v1.8.0

func (board MapBoard) Pieces() []Piece

Pieces ...

type Move

type Move struct {
	Start  Position
	Finish Position
}

Move ...

func (Move) IsEmpty

func (move Move) IsEmpty() bool

IsEmpty ...

It checks that the start of the move equals its finish.

func (Move) IsZero

func (move Move) IsZero() bool

IsZero ...

It checks that all fields of the move are zero.

type MoveGenerator

type MoveGenerator struct{}

MoveGenerator ...

func (MoveGenerator) MovesForColor

func (generator MoveGenerator) MovesForColor(
	storage PieceStorage,
	color Color,
) ([]Move, error)

MovesForColor ...

It doesn't guarantee an order of returned moves.

It doesn't take into account possible checks and can generate such moves.

It returns an error only on a king capture.

Example
package main

import (
	"fmt"
	"sort"

	models "github.com/thewizardplusplus/go-chess-models"
	"github.com/thewizardplusplus/go-chess-models/pieces"
)

func main() {
	board := models.NewBoard(models.Size{Width: 5, Height: 5}, []models.Piece{
		pieces.NewRook(models.Black, models.Position{File: 2, Rank: 2}),
		pieces.NewKnight(models.White, models.Position{File: 3, Rank: 3}),
		pieces.NewPawn(models.White, models.Position{File: 4, Rank: 3}),
	})

	var generator models.MoveGenerator
	moves, _ := generator.MovesForColor(board, models.White)

	// sorting only by the final point will be sufficient for the reproducibility
	// of this example
	sort.Slice(moves, func(i int, j int) bool {
		a, b := moves[i].Finish, moves[j].Finish
		if a.File == b.File {
			return a.Rank < b.Rank
		}

		return a.File < b.File
	})

	for _, move := range moves {
		fmt.Printf("%+v\n", move)
	}

}
Output:

{Start:{File:3 Rank:3} Finish:{File:1 Rank:2}}
{Start:{File:3 Rank:3} Finish:{File:1 Rank:4}}
{Start:{File:3 Rank:3} Finish:{File:2 Rank:1}}
{Start:{File:3 Rank:3} Finish:{File:4 Rank:1}}
{Start:{File:4 Rank:3} Finish:{File:4 Rank:4}}

func (MoveGenerator) MovesForPosition

func (generator MoveGenerator) MovesForPosition(
	storage PieceStorage,
	position Position,
) ([]Move, error)

MovesForPosition ...

It doesn't take into account possible checks and can generate such moves.

It returns an error only on a king capture.

type PerftHandler

type PerftHandler func(move Move, count int, deep int)

PerftHandler ...

type PerftMoveGenerator

type PerftMoveGenerator interface {
	MovesForColor(storage PieceStorage, color Color) ([]Move, error)
}

PerftMoveGenerator ...

type Piece

type Piece interface {
	Kind() Kind
	Color() Color
	Position() Position
	ApplyPosition(position Position) Piece

	// It shouldn't check that move positions is inside the board.
	//
	// It shouldn't check that the move finish position isn't equal
	// to its start position.
	//
	// It shouldn't check that the start move position corresponds
	// to the piece position.
	//
	// It shouldn't check that there isn't a friendly piece
	// on the move finish position.
	//
	// It shouldn't check that there isn't an enemy king
	// on the move finish position.
	//
	// It shouldn't check for a check before or after the move.
	CheckMove(move Move, storage PieceStorage) bool
}

Piece ...

func Pieces added in v1.8.0

func Pieces(storage PieceStorage) []Piece

Pieces ...

type PieceStorage

type PieceStorage interface {
	Size() Size
	Piece(position Position) (piece Piece, ok bool)
	Pieces() []Piece

	// It shouldn't check that the move is correct.
	ApplyMove(move Move) PieceStorage

	// It shouldn't check for a check before or after the move.
	CheckMove(move Move) error
}

PieceStorage ...

func NewBoard

func NewBoard(size Size, pieces []Piece) PieceStorage

NewBoard ...

func NewMapBoard added in v1.8.0

func NewMapBoard(size Size, pieces []Piece) PieceStorage

NewMapBoard ...

func NewSliceBoard added in v1.8.0

func NewSliceBoard(size Size, pieces []Piece) PieceStorage

NewSliceBoard ...

type Position

type Position struct {
	File int // column
	Rank int // row
}

Position ...

type PositionHandler added in v1.8.0

type PositionHandler func(position Position) error

PositionHandler ...

type Size

type Size struct {
	Width  int
	Height int
}

Size ...

func (Size) HasMove

func (size Size) HasMove(move Move) bool

HasMove ...

func (Size) HasPosition

func (size Size) HasPosition(position Position) bool

HasPosition ...

func (Size) IteratePositions added in v1.8.0

func (size Size) IteratePositions(handler PositionHandler) error

IteratePositions ...

func (Size) PositionCount added in v1.8.0

func (size Size) PositionCount() int

PositionCount ...

func (Size) PositionIndex added in v1.8.0

func (size Size) PositionIndex(position Position) int

PositionIndex ...

func (Size) Positions

func (size Size) Positions() []Position

Positions ...

type SliceBoard added in v1.8.0

type SliceBoard struct {
	BaseBoard
	// contains filtered or unexported fields
}

SliceBoard ...

func (SliceBoard) ApplyMove added in v1.8.0

func (board SliceBoard) ApplyMove(move Move) PieceStorage

ApplyMove ...

It doesn't check that the move is correct.

func (SliceBoard) CheckMove added in v1.8.0

func (board SliceBoard) CheckMove(move Move) error

CheckMove ...

It doesn't check for a check before or after the move.

func (SliceBoard) Piece added in v1.8.0

func (board SliceBoard) Piece(position Position) (piece Piece, ok bool)

Piece ...

func (SliceBoard) Pieces added in v1.8.0

func (board SliceBoard) Pieces() []Piece

Pieces ...

Directories

Path Synopsis
cmd
encoding
uci

Jump to

Keyboard shortcuts

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