✨ FEN
This commit is contained in:
parent
c21a117a23
commit
80e9a0d890
1 changed files with 124 additions and 0 deletions
124
pkg/fen/fen.go
Normal file
124
pkg/fen/fen.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package fen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.c-base.org/gochess/libchess/pkg/board"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultSetup holds the FEN to the default board setup.
|
||||||
|
const DefaultSetup = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
|
||||||
|
|
||||||
|
// Import returns
|
||||||
|
func Import(fen string) (*board.Board, error) {
|
||||||
|
var (
|
||||||
|
parts = strings.Split(fen, " ")
|
||||||
|
pieces = map[board.Square]board.Piece{}
|
||||||
|
fullMove uint64
|
||||||
|
halfMove uint64
|
||||||
|
ep *board.Square
|
||||||
|
cr *board.CastleRights
|
||||||
|
turn board.Color
|
||||||
|
position string
|
||||||
|
expandedFEN string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if len(parts) != 6 {
|
||||||
|
return nil, fmt.Errorf("invalid fields in FEN: %s", fen)
|
||||||
|
}
|
||||||
|
if fullMove, err = strconv.ParseUint(parts[5], 10, 64); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if halfMove, err = strconv.ParseUint(parts[4], 10, 64); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if parts[3] != "-" {
|
||||||
|
if square, ok := board.StrToSquareMap[strings.ToLower(parts[3])]; ok {
|
||||||
|
ep = &square
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unable to parse e.p. square: %s", parts[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parts[2] != "-" {
|
||||||
|
cr, err = board.NewCastleRights(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch strings.ToLower(parts[1]) {
|
||||||
|
case board.White.String():
|
||||||
|
turn = board.White
|
||||||
|
case board.Black.String():
|
||||||
|
turn = board.Black
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unable to parse turn: %s", parts[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
position = parts[0]
|
||||||
|
expandedFEN = expandFEN(position)
|
||||||
|
parts = strings.Split(expandedFEN, "/")
|
||||||
|
if len(parts) != 8 {
|
||||||
|
return nil, fmt.Errorf("unable to parse position: %s", position)
|
||||||
|
}
|
||||||
|
for r := len(parts) - 1; r >= 0; r-- {
|
||||||
|
for f := 0; f < 8; f++ {
|
||||||
|
square := board.NewSquare(board.File(f), board.Rank(7-r))
|
||||||
|
piece := board.NewPieceByFEN(rune(parts[r][f]))
|
||||||
|
if piece != board.NoPiece {
|
||||||
|
pieces[square] = piece
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := board.NewBoard(pieces, turn, *cr, ep, halfMove, fullMove)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandFEN(s string) string {
|
||||||
|
out := ""
|
||||||
|
for _, c := range s {
|
||||||
|
switch c {
|
||||||
|
case 'K', 'Q', 'R', 'B', 'N', 'P', 'k', 'q', 'r', 'b', 'n', 'p', '/':
|
||||||
|
out += string(c)
|
||||||
|
case '1':
|
||||||
|
out += "1"
|
||||||
|
case '2':
|
||||||
|
out += "11"
|
||||||
|
case '3':
|
||||||
|
out += "111"
|
||||||
|
case '4':
|
||||||
|
out += "1111"
|
||||||
|
case '5':
|
||||||
|
out += "11111"
|
||||||
|
case '6':
|
||||||
|
out += "111111"
|
||||||
|
case '7':
|
||||||
|
out += "1111111"
|
||||||
|
case '8':
|
||||||
|
out += "11111111"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export returns the FEN string of the given *board.Board{}.
|
||||||
|
func Export(b *board.Board) string {
|
||||||
|
ep := "-"
|
||||||
|
if b.EnPassent != nil {
|
||||||
|
ep = b.EnPassent.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s %s %s %s %d %d",
|
||||||
|
b.String(),
|
||||||
|
b.Turn.String(),
|
||||||
|
b.CastleRights.String(),
|
||||||
|
ep,
|
||||||
|
b.HalfMove,
|
||||||
|
b.FullMove,
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue