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 (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 >= RangeLastValid { return nil } return &c } func (c *Coordinate) GetAllKnightMoves() []Coordinate { unfilteredMoves := make([]*Coordinate, 0, 8) builder := CoordinateBuilder{coordinate: *c} unfilteredMoves = append(unfilteredMoves, builder.Up(2).Right(1).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Up(1).Right(2).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Down(1).Right(2).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Down(2).Right(1).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Down(2).Left(1).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Down(1).Left(2).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Up(1).Left(2).Resolve()) unfilteredMoves = append(unfilteredMoves, builder.Up(2).Left(1).Resolve()) return lo.FilterMap(unfilteredMoves, func(unfilteredMove *Coordinate, _ int) (Coordinate, bool) { if unfilteredMove != nil { return *unfilteredMove, 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 }