mchess-server/types/coordinate.go
2023-06-27 22:32:24 +02:00

155 lines
4.1 KiB
Go

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
}