88 lines
1.8 KiB
Go
88 lines
1.8 KiB
Go
// FILE: internal/board/board.go
|
|
package board
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"chess/internal/core"
|
|
)
|
|
|
|
const (
|
|
StartingFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
|
|
)
|
|
|
|
type Board struct {
|
|
squares [8][8]byte
|
|
turn core.Color
|
|
castling string
|
|
enPassant string
|
|
halfmove int
|
|
fullmove int
|
|
}
|
|
|
|
func FEN(fen string) (*Board, error) {
|
|
parts := strings.Fields(fen)
|
|
if len(parts) != 6 {
|
|
return nil, fmt.Errorf("invalid FEN: expected 6 parts, got %d", len(parts))
|
|
}
|
|
|
|
b := &Board{}
|
|
|
|
// Parse board
|
|
ranks := strings.Split(parts[0], "/")
|
|
if len(ranks) != 8 {
|
|
return nil, fmt.Errorf("invalid FEN: expected 8 ranks")
|
|
}
|
|
|
|
for r := 0; r < 8; r++ {
|
|
file := 0
|
|
for _, ch := range ranks[r] {
|
|
if ch >= '1' && ch <= '8' {
|
|
file += int(ch - '0')
|
|
} else {
|
|
if file >= 8 {
|
|
return nil, fmt.Errorf("invalid FEN: too many pieces in rank %d", r+1)
|
|
}
|
|
b.squares[r][file] = byte(ch)
|
|
file++
|
|
}
|
|
}
|
|
if file != 8 {
|
|
return nil, fmt.Errorf("invalid FEN: rank %d has %d files", r+1, file)
|
|
}
|
|
}
|
|
|
|
// Parse game state with validation
|
|
if len(parts[1]) != 1 || (parts[1][0] != 'w' && parts[1][0] != 'b') {
|
|
return nil, fmt.Errorf("invalid FEN: turn must be 'w' or 'b'")
|
|
}
|
|
b.turn = core.Color(parts[1][0])
|
|
b.castling = parts[2]
|
|
b.enPassant = parts[3]
|
|
|
|
if _, err := fmt.Sscanf(parts[4], "%d", &b.halfmove); err != nil {
|
|
return nil, fmt.Errorf("invalid FEN: halfmove counter")
|
|
}
|
|
if _, err := fmt.Sscanf(parts[5], "%d", &b.fullmove); err != nil {
|
|
return nil, fmt.Errorf("invalid FEN: fullmove counter")
|
|
}
|
|
|
|
return b, nil
|
|
}
|
|
|
|
func (b *Board) Turn() core.Color {
|
|
return b.turn
|
|
}
|
|
|
|
func (b *Board) GetPieceAt(square string) byte {
|
|
if len(square) != 2 {
|
|
return 0
|
|
}
|
|
if square[0] < 'a' || square[0] > 'h' || square[1] < '1' || square[1] > '8' {
|
|
return 0
|
|
}
|
|
file := square[0] - 'a'
|
|
rank := '8' - square[1]
|
|
return b.squares[rank][file]
|
|
} |