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, ) }