ref: 03c4b270665987e034d6589d595e4e6b638a02ab
dir: /moves.go/
package main import ( "fmt" "strings" ) // Error type MoveParsingError struct { move string } func (e MoveParsingError) Error() string { return fmt.Sprintf("move '%s' invalid", e.move) } type AmbiguousMoveError struct { move string } func (e AmbiguousMoveError) Error() string { return fmt.Sprintf("move '%s' is ambiguous", e.move) } type PieceParsingError struct { piece string } func (e PieceParsingError) Error() string { return fmt.Sprintf("piece '%s' invalid", e.piece) } type CoordinateParsingError struct { coord string } func (e CoordinateParsingError) Error() string { return fmt.Sprintf("coordinate '%s' invalid", e.coord) } // Chess move types type MoveType uint8 const ( Basic = iota Capture Promotion DrawOffer Castling GenericMove ) // Coordinate type Coordinate struct { X int Y int } // Chess move type Move struct { Tp MoveType Notation string Piece Piece Takes Piece PromotionPiece Piece From *Coordinate To *Coordinate } // Parsing utils func pieceNotation(piece string) (Piece, error) { switch (piece) { case "K": return King, nil case "Q": return Queen, nil case "R": return Rook, nil case "B": return Bishop, nil case "N": return Knight, nil default: return NoPiece, PieceParsingError { piece: piece } } } func coordinateNotation(notation string) (*Coordinate, error) { if len(notation) != 2 { return nil, CoordinateParsingError { coord: notation } } if []byte(notation)[0] < byte(97) || []byte(notation)[0] > byte(122) { return nil, CoordinateParsingError { coord: notation } } if []byte(notation)[1] < byte(48) || []byte(notation)[1] > byte(57) { return nil, CoordinateParsingError { coord: notation } } column := []byte(notation)[0] - 97 row := 7 - ([]byte(notation)[1] - 48 - 1) return &Coordinate { X: int(column), Y: int(row), }, nil } func NewMove(sac string, b *Board) (*Move, error) { var ac = sac var takenPiece Piece = AnyPiece var promotionPiece Piece = NoPiece var piece Piece var to *Coordinate var from *Coordinate var err error var moveType MoveType = Basic acPromote := strings.Split(ac, "=") if len(acPromote) > 2 { return nil, MoveParsingError { move: ac } } if len(acPromote) == 2 { ac = acPromote[0] moveType = Promotion promotionPiece, err = pieceNotation(string(ac[1])) if err != nil { return nil, err } } switch (len(ac)) { case 2: piece = Pawn to, err = coordinateNotation(ac) if err != nil { return nil, err } case 3: piece, err = pieceNotation(ac[0:1]) if err != nil { return nil, err } to, err = coordinateNotation(ac[1:]) if err != nil { return nil, err } case 4: piece = Pawn from, err = coordinateNotation(ac[0:2]) if err != nil { return nil, err } to, err = coordinateNotation(ac[2:4]) if err != nil { return nil, err } case 5: piece, err = pieceNotation(ac[0:1]) if err != nil { return nil, err } from, err = coordinateNotation(ac[1:3]) if err != nil { return nil, err } to, err = coordinateNotation(ac[3:5]) if err != nil { return nil, err } case 6: piece, err = pieceNotation(ac[0:1]) if err != nil { return nil, err } to, err = coordinateNotation(ac[1:3]) if err != nil { return nil, err } from, err = coordinateNotation(ac[3:5]) if err != nil { return nil, err } takenPiece, err = pieceNotation(ac[5:6]) if err != nil { return nil, err } default: return nil, MoveParsingError { move: ac } } if from == nil { from = b.FindSingleMove(piece, to) } if from == nil { return nil, AmbiguousMoveError {} } if takenPiece != AnyPiece { moveType = Capture } move := &Move { Tp: moveType, Notation: sac, Piece: piece, Takes: takenPiece, PromotionPiece: promotionPiece, From: from, To: to, } return move, nil }