mchess-server/types/coordinate.go

180 lines
4.9 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 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
}