package types import ( "github.com/samber/lo" ) // coordinates starting at 1:1 and end at 8:8 type Coordinate struct { Col int `json:"col"` Row int `json:"row"` } const ( RangeLastValid = 8 RangeFirstValid = 1 RangeUpperInvalid = 9 RangeLowerInvalid = 0 ) type CoordinateBuilder struct { coordinate Coordinate } func newCoordinateBuilder(c Coordinate) *CoordinateBuilder { return &CoordinateBuilder{ coordinate: c, } } func (b *CoordinateBuilder) Up(number int) *CoordinateBuilder { b.coordinate.Row += number return b } func (b *CoordinateBuilder) Down(number int) *CoordinateBuilder { b.coordinate.Row -= number return b } func (b *CoordinateBuilder) Left(number int) *CoordinateBuilder { b.coordinate.Col -= number return b } func (b *CoordinateBuilder) Right(number int) *CoordinateBuilder { b.coordinate.Col += number return b } func (b *CoordinateBuilder) Resolve() *Coordinate { c := b.coordinate if c.Row <= RangeLastValid && c.Row >= RangeFirstValid && c.Col <= RangeLastValid && c.Col >= RangeFirstValid { return &c } return nil } func (c *Coordinate) GetAllKingMoves() []Coordinate { squares := make([]*Coordinate, 0, 8) squares = append(squares, c.Up(1)) squares = append(squares, c.Down(1)) squares = append(squares, c.Left(1)) squares = append(squares, c.Right(1)) squares = append(squares, newCoordinateBuilder(*c).Up(1).Right(1).Resolve()) squares = append(squares, newCoordinateBuilder(*c).Up(1).Left(1).Resolve()) squares = append(squares, newCoordinateBuilder(*c).Down(1).Right(1).Resolve()) squares = append(squares, newCoordinateBuilder(*c).Down(1).Left(1).Resolve()) return filterNilSquares(squares) } func (c *Coordinate) GetAllKnightMoves() []Coordinate { unfilteredMoves := make([]*Coordinate, 0, 8) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Up(2).Right(1).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Up(1).Right(2).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Down(1).Right(2).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Down(2).Right(1).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Down(2).Left(1).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Down(1).Left(2).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Up(1).Left(2).Resolve()) unfilteredMoves = append(unfilteredMoves, newCoordinateBuilder(*c).Up(2).Left(1).Resolve()) return filterNilSquares(unfilteredMoves) } func filterNilSquares(squares []*Coordinate) []Coordinate { return lo.FilterMap(squares, func(square *Coordinate, _ int) (Coordinate, bool) { if square != nil { return *square, true } return Coordinate{}, false }) } func (c Coordinate) Up(number int) *Coordinate { check := c.Row + number if check <= RangeLastValid { return &Coordinate{Row: check, Col: c.Col} } return nil } func (c Coordinate) Down(number int) *Coordinate { check := c.Row - number if check >= RangeFirstValid { return &Coordinate{Row: check, Col: c.Col} } return nil } // Right and left is seen from a board where row 1 is on the bottom func (c Coordinate) Right(number int) *Coordinate { check := c.Col + number if check <= RangeLastValid { return &Coordinate{Row: c.Row, Col: check} } return nil } func (c Coordinate) Left(number int) *Coordinate { check := c.Col - number if check >= RangeFirstValid { return &Coordinate{Row: c.Row, Col: check} } return nil } func (c Coordinate) GetAllSquaresOnStraights() []Coordinate { squares := c.GetStraightInDirection(Coordinate.Up) squares = append(squares, c.GetStraightInDirection(Coordinate.Down)...) squares = append(squares, c.GetStraightInDirection(Coordinate.Left)...) squares = append(squares, c.GetStraightInDirection(Coordinate.Right)...) return squares } func (c Coordinate) GetAllSquaresOnDiagonals() []Coordinate { squares := c.GetDiagonalInDirection(Coordinate.Up, Coordinate.Right) squares = append(squares, c.GetDiagonalInDirection(Coordinate.Down, Coordinate.Right)...) squares = append(squares, c.GetDiagonalInDirection(Coordinate.Down, Coordinate.Left)...) squares = append(squares, c.GetDiagonalInDirection(Coordinate.Up, Coordinate.Left)...) return squares } func (c Coordinate) GetStraightInDirection(dirFn func(Coordinate, int) *Coordinate) []Coordinate { squares := []Coordinate{} i := 1 for { if square := dirFn(c, i); square != nil { squares = append(squares, *square) i += 1 } else { return squares } } } func (c Coordinate) GetDiagonalInDirection(dirFn1, dirFn2 func(Coordinate, int) *Coordinate) []Coordinate { squares := []Coordinate{} i := 1 for { if squareRight := dirFn1(c, i); squareRight != nil { if square := dirFn2(*squareRight, i); square != nil { squares = append(squares, *square) i += 1 } else { break } } else { break } } return squares }