125 lines
2.6 KiB
Go
125 lines
2.6 KiB
Go
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,
|
|
)
|
|
}
|