many many changes again.
This commit is contained in:
parent
3d4fee2631
commit
f733d9bb08
@ -1,15 +1,21 @@
|
||||
package chess
|
||||
|
||||
import "mchess_server/types"
|
||||
import (
|
||||
"mchess_server/types"
|
||||
)
|
||||
|
||||
type Bishop struct {
|
||||
Color types.ChessColor
|
||||
}
|
||||
|
||||
func (b Bishop) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return b.GetAllNonBlockedMoves(board, fromSquare)
|
||||
}
|
||||
|
||||
func (b Bishop) GetColor() types.ChessColor {
|
||||
return b.Color
|
||||
}
|
||||
|
||||
func (b Bishop) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
func (b Bishop) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return []types.Coordinate{}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package chess
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"mchess_server/types"
|
||||
|
||||
"github.com/samber/lo"
|
||||
@ -78,7 +79,7 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
|
||||
if !wasSpecialMove {
|
||||
// At the moment, we do not need to check if the correct color is moving,
|
||||
//since we are only reading moves from the player whose turn it is.
|
||||
allMovesExceptBlocked := pieceAtStartSquare.GetAllMovesButBlocked(tempBoard, move.StartSquare)
|
||||
allMovesExceptBlocked := pieceAtStartSquare.GetAllNonBlockedMoves(tempBoard, move.StartSquare)
|
||||
legal := lo.Contains(allMovesExceptBlocked, move.EndSquare)
|
||||
if !legal {
|
||||
return false, "not a legal square"
|
||||
@ -89,16 +90,12 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
|
||||
tempBoard.position[move.EndSquare] = pieceAtStartSquare
|
||||
}
|
||||
|
||||
//Check if king of moving color is in check -> move not allowed
|
||||
//Do that by checking if the king is in a square attacked by the other color.
|
||||
ownKingCoordinate := tempBoard.getSquareOfPiece(King{Color: move.ColorMoved})
|
||||
if ownKingCoordinate == nil {
|
||||
return false, string(move.ColorMoved) + " king not found"
|
||||
kingAttacked, err := tempBoard.isKingOfMovingColorInCheck(move.ColorMoved)
|
||||
if err != nil {
|
||||
return false, "something went wrong"
|
||||
}
|
||||
|
||||
kingIsAttacked := tempBoard.isSquareAttacked(*ownKingCoordinate, move.ColorMoved.Opposite())
|
||||
if kingIsAttacked {
|
||||
return false, "king is attacked after move"
|
||||
if kingAttacked {
|
||||
return false, "king would be in check after move"
|
||||
}
|
||||
|
||||
//Check for checkmat&e
|
||||
@ -118,10 +115,24 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
|
||||
b.position = tempBoard.position
|
||||
b.history = tempBoard.history
|
||||
b.appendMoveToHistory(move)
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (b Board) isKingOfMovingColorInCheck(color types.ChessColor) (bool, error) {
|
||||
//Check if king of moving color is in check -> move not allowed
|
||||
//Do that by checking if the king is in a square attacked by the other color.
|
||||
ownKingCoordinate := b.getSquareOfPiece(King{Color: color})
|
||||
if ownKingCoordinate == nil {
|
||||
return false, errors.New("no king found")
|
||||
}
|
||||
|
||||
kingIsAttacked := b.isSquareAttacked(*ownKingCoordinate, color.Opposite())
|
||||
if kingIsAttacked {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate {
|
||||
for k, v := range b.position {
|
||||
if v == piece {
|
||||
@ -135,9 +146,10 @@ func (b Board) isSquareAttacked(square types.Coordinate, byColor types.ChessColo
|
||||
var attackedSquares []types.Coordinate
|
||||
|
||||
for square, piece := range b.position {
|
||||
attackedSquares = append(attackedSquares, piece.GetAllMovesButBlocked(b, square)...)
|
||||
if piece.GetColor() == byColor {
|
||||
attackedSquares = append(attackedSquares, piece.GetAllAttackedSquares(b, square)...)
|
||||
}
|
||||
}
|
||||
|
||||
return lo.Contains(attackedSquares, square)
|
||||
}
|
||||
|
||||
@ -146,7 +158,6 @@ func (b Board) getPieceAt(coord types.Coordinate) Piece {
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
return piece
|
||||
}
|
||||
|
||||
@ -183,7 +194,7 @@ func (b *Board) handleSpecialMove(move types.Move) bool {
|
||||
|
||||
switch pieceAtStartSquare.(type) {
|
||||
case Pawn:
|
||||
pawn := pieceAtStartSquare.(Pawn)
|
||||
pawn := pieceAtStartSquare.(Pawn)
|
||||
was = pawn.HandlePossiblePromotion(b, move)
|
||||
if !was {
|
||||
was = pawn.HandleEnPassant(b, move, b.getLastMove())
|
||||
@ -191,5 +202,3 @@ func (b *Board) handleSpecialMove(move types.Move) bool {
|
||||
}
|
||||
return was
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,14 +122,18 @@ func Test_CheckMove_invalidPawnMoves(t *testing.T) {
|
||||
|
||||
board.position[types.Coordinate{Col: 1, Row: 6}] = King{Color: types.White}
|
||||
board.position[types.Coordinate{Col: 2, Row: 6}] = Pawn{Color: types.White}
|
||||
board.position[types.Coordinate{Col: 8, Row: 6}] = King{Color: types.Black}
|
||||
board.position[types.Coordinate{Col: 7, Row: 6}] = Rook{Color: types.Black}
|
||||
board.position[types.Coordinate{Col: 8, Row: 8}] = King{Color: types.Black}
|
||||
boardBeforeMove := board
|
||||
|
||||
move := types.Move{
|
||||
StartSquare: types.Coordinate{Col: 2, Row: 6},
|
||||
EndSquare: types.Coordinate{Col: 2, Row: 7},
|
||||
}
|
||||
StartSquare: types.Coordinate{Col: 2, Row: 6},
|
||||
EndSquare: types.Coordinate{Col: 2, Row: 7},
|
||||
}
|
||||
good, _ := board.CheckAndPlay(move)
|
||||
|
||||
assert.False(t, good)
|
||||
assert.Equal(t, boardBeforeMove, board)
|
||||
})
|
||||
}
|
||||
|
||||
@ -139,7 +143,7 @@ func Test_CheckMove_validPromotion(t *testing.T) {
|
||||
board.position[types.Coordinate{Col: 1, Row: 7}] = Pawn{Color: types.White}
|
||||
board.position[types.Coordinate{Col: 1, Row: 1}] = King{Color: types.White}
|
||||
|
||||
board.position[types.Coordinate{Col: 8, Row: 7}] = King{Color: types.Black}
|
||||
board.position[types.Coordinate{Col: 7, Row: 7}] = King{Color: types.Black}
|
||||
|
||||
shortName := types.QueenShortName
|
||||
move := types.Move{
|
||||
|
@ -3,26 +3,44 @@ package chess
|
||||
import "mchess_server/types"
|
||||
|
||||
func (b *Board) GetNonBlockedRowAndColumn(fromSquare types.Coordinate) []types.Coordinate {
|
||||
squaresLeft := fromSquare.GetAllSquaresLeft()
|
||||
squaresRight := fromSquare.GetAllSquaresRight()
|
||||
squaresAbove := fromSquare.GetAllSquaresAbove()
|
||||
squaresBelow := fromSquare.GetAllSquaresBelow()
|
||||
nonBlocked := []types.Coordinate{}
|
||||
squaresLeft := fromSquare.GetStraightInDirection(types.Coordinate.Left)
|
||||
squaresRight := fromSquare.GetStraightInDirection(types.Coordinate.Right)
|
||||
squaresAbove := fromSquare.GetStraightInDirection(types.Coordinate.Up)
|
||||
squaresBelow := fromSquare.GetStraightInDirection(types.Coordinate.Down)
|
||||
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresLeft, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresRight, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresAbove, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresBelow, fromSquare)...)
|
||||
nonBlocked := b.getNonBlocked(squaresLeft, fromSquare)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresRight, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresAbove, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresBelow, fromSquare)...)
|
||||
|
||||
return nonBlocked
|
||||
}
|
||||
|
||||
func (b *Board) GetNonBlockedDiagonals(fromSquare types.Coordinate) []types.Coordinate {
|
||||
rightUp := fromSquare.GetDiagonalInDirection(types.Coordinate.Right, types.Coordinate.Up)
|
||||
leftUp := fromSquare.GetDiagonalInDirection(types.Coordinate.Left, types.Coordinate.Up)
|
||||
leftDown := fromSquare.GetDiagonalInDirection(types.Coordinate.Left, types.Coordinate.Down)
|
||||
rightDown := fromSquare.GetDiagonalInDirection(types.Coordinate.Right, types.Coordinate.Down)
|
||||
|
||||
nonBlocked := b.getNonBlocked(rightUp, fromSquare)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(leftUp, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(leftDown, fromSquare)...)
|
||||
nonBlocked = append(nonBlocked, b.getNonBlocked(rightDown, fromSquare)...)
|
||||
|
||||
return nonBlocked
|
||||
}
|
||||
|
||||
func (b *Board) GetNonBlockedKnightMoves(fromSquare types.Coordinate) []types.Coordinate {
|
||||
allKnightMoves := fromSquare.GetAllKnightMoves()
|
||||
return b.getNonBlocked(allKnightMoves, fromSquare)
|
||||
}
|
||||
|
||||
func (b *Board) getNonBlocked(
|
||||
squaresToCheck []types.Coordinate,
|
||||
sourceSquare types.Coordinate,
|
||||
squaresToCheck []types.Coordinate,
|
||||
sourceSquare types.Coordinate,
|
||||
) []types.Coordinate {
|
||||
pieceOnSourceSquare := b.getPieceAt(sourceSquare)
|
||||
nonBlocked := []types.Coordinate{}
|
||||
nonBlocked := []types.Coordinate{}
|
||||
|
||||
for _, square := range squaresToCheck {
|
||||
piece := b.getPieceAt(square)
|
||||
@ -37,5 +55,5 @@ func (b *Board) getNonBlocked(
|
||||
}
|
||||
nonBlocked = append(nonBlocked, square)
|
||||
}
|
||||
return nonBlocked
|
||||
return nonBlocked
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
package chess
|
||||
|
||||
import "mchess_server/types"
|
||||
import (
|
||||
"mchess_server/types"
|
||||
)
|
||||
|
||||
type King struct {
|
||||
Color types.ChessColor
|
||||
Color types.ChessColor
|
||||
}
|
||||
|
||||
func (k King) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return k.GetAllNonBlockedMoves(board, fromSquare)
|
||||
}
|
||||
|
||||
func (k King) GetColor() types.ChessColor {
|
||||
return k.Color
|
||||
}
|
||||
|
||||
func (k King) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
func (k King) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return []types.Coordinate{}
|
||||
}
|
||||
|
@ -1,19 +1,21 @@
|
||||
package chess
|
||||
|
||||
import "mchess_server/types"
|
||||
import (
|
||||
"mchess_server/types"
|
||||
)
|
||||
|
||||
type Knight struct {
|
||||
Color types.ChessColor
|
||||
}
|
||||
|
||||
// AfterMoveAction implements Piece.
|
||||
func (k Knight) AfterMoveAction() {
|
||||
func (k Knight) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return k.GetAllNonBlockedMoves(board, fromSquare)
|
||||
}
|
||||
|
||||
func (k Knight) GetColor() types.ChessColor {
|
||||
return k.Color
|
||||
}
|
||||
|
||||
func (k Knight) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return []types.Coordinate{}
|
||||
func (k Knight) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return board.GetNonBlockedKnightMoves(fromSquare)
|
||||
}
|
||||
|
@ -10,7 +10,18 @@ type Pawn struct {
|
||||
Color types.ChessColor
|
||||
}
|
||||
|
||||
func (p Pawn) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
func (p Pawn) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
attackingMoves := make([]types.Coordinate,0,2)
|
||||
allMoves := p.GetAllNonBlockedMoves(board, fromSquare)
|
||||
for _,move := range allMoves {
|
||||
if move.Col != fromSquare.Col {
|
||||
attackingMoves = append(attackingMoves, move)
|
||||
}
|
||||
}
|
||||
return attackingMoves
|
||||
}
|
||||
|
||||
func (p Pawn) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
theoreticalSquares := p.getAllMoves(fromSquare)
|
||||
legalSquares := p.filterBlockedSquares(board, fromSquare, theoreticalSquares)
|
||||
|
||||
@ -21,37 +32,37 @@ func (p Pawn) GetColor() types.ChessColor {
|
||||
return p.Color
|
||||
}
|
||||
|
||||
func (p *Pawn) HandlePossiblePromotion(b *Board ,move types.Move) bool {
|
||||
var isPromotionMove bool
|
||||
var promotionToPiece types.PieceShortName
|
||||
func (p *Pawn) HandlePossiblePromotion(b *Board, move types.Move) bool {
|
||||
var isPromotionMove bool
|
||||
var promotionToPiece types.PieceShortName
|
||||
|
||||
//TODO(m): What if message does not contain a promotion, but should be because a pawn is moved to the end square
|
||||
messageContainsPromotion := move.IsPromotionMove()
|
||||
//TODO(m): What if message does not contain a promotion, but should be because a pawn is moved to the end square
|
||||
messageContainsPromotion := move.IsPromotionMove()
|
||||
|
||||
if messageContainsPromotion {
|
||||
promotionToPiece = *move.PromotionToPiece
|
||||
}
|
||||
if messageContainsPromotion {
|
||||
promotionToPiece = *move.PromotionToPiece
|
||||
}
|
||||
|
||||
switch move.ColorMoved {
|
||||
case types.White:
|
||||
if move.StartSquare.Row == types.RangeLastValid-1 &&
|
||||
move.EndSquare.Row == types.RangeLastValid {
|
||||
isPromotionMove = true
|
||||
}
|
||||
switch move.ColorMoved {
|
||||
case types.White:
|
||||
if move.StartSquare.Row == types.RangeLastValid-1 &&
|
||||
move.EndSquare.Row == types.RangeLastValid {
|
||||
isPromotionMove = true
|
||||
}
|
||||
|
||||
case types.Black:
|
||||
if move.StartSquare.Row == types.RangeFirstValid+1 &&
|
||||
move.EndSquare.Row == types.RangeFirstValid {
|
||||
isPromotionMove = true
|
||||
}
|
||||
}
|
||||
case types.Black:
|
||||
if move.StartSquare.Row == types.RangeFirstValid+1 &&
|
||||
move.EndSquare.Row == types.RangeFirstValid {
|
||||
isPromotionMove = true
|
||||
}
|
||||
}
|
||||
|
||||
if isPromotionMove {
|
||||
delete(b.position, move.StartSquare)
|
||||
b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved)
|
||||
}
|
||||
if isPromotionMove {
|
||||
delete(b.position, move.StartSquare)
|
||||
b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved)
|
||||
}
|
||||
|
||||
return isPromotionMove
|
||||
return isPromotionMove
|
||||
}
|
||||
|
||||
func (p *Pawn) HandleEnPassant(b *Board, move, lastMove types.Move) bool {
|
||||
@ -123,8 +134,8 @@ func (p Pawn) getAllMoves(fromSquare types.Coordinate) []types.Coordinate {
|
||||
switch p.Color {
|
||||
case types.Black:
|
||||
firstMove := fromSquare.Row == types.RangeLastValid-1
|
||||
|
||||
if fromSquare.Down(1) != nil {
|
||||
|
||||
if fromSquare.Down(1) != nil {
|
||||
theoreticalMoves = append(theoreticalMoves, *fromSquare.Down(1))
|
||||
}
|
||||
if firstMove && fromSquare.Down(2) != nil {
|
||||
@ -176,4 +187,3 @@ func (p Pawn) filterBlockedSquares(board Board, fromSquare types.Coordinate, squ
|
||||
}
|
||||
return lo.Intersect(nonBlockedSquares, squaresToBeFiltered)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@ import (
|
||||
)
|
||||
|
||||
type Piece interface {
|
||||
GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate
|
||||
GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate
|
||||
GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate
|
||||
GetColor() types.ChessColor
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,23 @@
|
||||
package chess
|
||||
|
||||
import "mchess_server/types"
|
||||
import (
|
||||
"mchess_server/types"
|
||||
)
|
||||
|
||||
type Queen struct {
|
||||
Color types.ChessColor
|
||||
}
|
||||
|
||||
func (q Queen) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return q.GetAllNonBlockedMoves(board, fromSquare)
|
||||
}
|
||||
|
||||
func (q Queen) GetColor() types.ChessColor {
|
||||
return q.Color
|
||||
}
|
||||
|
||||
func (q Queen) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return []types.Coordinate{}
|
||||
func (q Queen) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
squares := board.GetNonBlockedRowAndColumn(fromSquare)
|
||||
squares = append(squares, board.GetNonBlockedDiagonals(fromSquare)...)
|
||||
return squares
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package chess
|
||||
|
||||
import "mchess_server/types"
|
||||
import (
|
||||
"mchess_server/types"
|
||||
)
|
||||
|
||||
type Rook struct {
|
||||
Color types.ChessColor
|
||||
}
|
||||
|
||||
func (r Rook) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return r.GetAllNonBlockedMoves(board, fromSquare)
|
||||
}
|
||||
|
||||
func (r Rook) AfterMoveAction() {
|
||||
}
|
||||
|
||||
@ -13,6 +19,6 @@ func (r Rook) GetColor() types.ChessColor {
|
||||
return r.Color
|
||||
}
|
||||
|
||||
func (r Rook) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return board.GetNonBlockedRowAndColumn(fromSquare)
|
||||
func (r Rook) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
|
||||
return board.GetNonBlockedRowAndColumn(fromSquare)
|
||||
}
|
||||
|
@ -14,9 +14,8 @@ func Test_Rook_GetNonBlockedSquares(t *testing.T) {
|
||||
rook := Rook{Color: types.Black}
|
||||
|
||||
board.position[types.Coordinate{Col: 5, Row: 5}] = rook
|
||||
squares := rook.GetAllMovesButBlocked(board, types.Coordinate{Col: 5, Row: 5})
|
||||
squares := rook.GetAllNonBlockedMoves(board, types.Coordinate{Col: 5, Row: 5})
|
||||
assert.Len(t, squares, 14)
|
||||
assert.Equal(t, types.Coordinate{Col: 4, Row: 5}, squares[0])
|
||||
})
|
||||
|
||||
t.Run("free row and column", func(t *testing.T) {
|
||||
@ -29,7 +28,7 @@ func Test_Rook_GetNonBlockedSquares(t *testing.T) {
|
||||
board.position[types.Coordinate{Col: 5, Row: 6}] = Pawn{Color: types.White}
|
||||
board.position[types.Coordinate{Col: 6, Row: 5}] = Pawn{Color: types.Black}
|
||||
|
||||
squares := rook.GetAllMovesButBlocked(board, types.Coordinate{Col: 5, Row: 5})
|
||||
squares := rook.GetAllNonBlockedMoves(board, rookCoordinate)
|
||||
|
||||
squaresOnLeft := lo.Filter(squares, func(square types.Coordinate, _ int) bool {
|
||||
return square.Row == rookCoordinate.Row && square.Col < rookCoordinate.Col
|
||||
|
@ -1,5 +1,7 @@
|
||||
package types
|
||||
|
||||
import "github.com/samber/lo"
|
||||
|
||||
// coordinates starting at 1:1 and end at 8:8
|
||||
type Coordinate struct {
|
||||
Col int `json:"col"`
|
||||
@ -14,6 +16,65 @@ const (
|
||||
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 {
|
||||
@ -45,11 +106,27 @@ func (c Coordinate) Left(number int) *Coordinate {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Coordinate) GetAllSquaresLeft() []Coordinate {
|
||||
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 := c.Left(i); square != nil {
|
||||
if square := dirFn(c, i); square != nil {
|
||||
squares = append(squares, *square)
|
||||
i += 1
|
||||
} else {
|
||||
@ -58,70 +135,20 @@ func (c Coordinate) GetAllSquaresLeft() []Coordinate {
|
||||
}
|
||||
}
|
||||
|
||||
func (c Coordinate) GetAllSquaresRight() []Coordinate {
|
||||
func (c Coordinate) GetDiagonalInDirection(dirFn1, dirFn2 func(Coordinate, int) *Coordinate) []Coordinate {
|
||||
squares := []Coordinate{}
|
||||
i := 1
|
||||
for {
|
||||
if square := c.Right(i); square != nil {
|
||||
squares = append(squares, *square)
|
||||
i += 1
|
||||
if squareRight := dirFn1(c, i); squareRight != nil {
|
||||
if square := dirFn2(*squareRight, i); square != nil {
|
||||
squares = append(squares, *square)
|
||||
i += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
return squares
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c Coordinate) GetAllSquaresAbove() []Coordinate {
|
||||
squares := []Coordinate{}
|
||||
i := 1
|
||||
for {
|
||||
if square := c.Up(i); square != nil {
|
||||
squares = append(squares, *square)
|
||||
i += 1
|
||||
} else {
|
||||
return squares
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c Coordinate) GetAllSquaresBelow() []Coordinate {
|
||||
squares := []Coordinate{}
|
||||
i := 1
|
||||
for {
|
||||
if square := c.Down(i); square != nil {
|
||||
squares = append(squares, *square)
|
||||
i += 1
|
||||
} else {
|
||||
return squares
|
||||
}
|
||||
}
|
||||
}
|
||||
func (c Coordinate) GetSquaresOnRow() []Coordinate {
|
||||
rowToReturn := []Coordinate{}
|
||||
leftMostSquareOnRow := Coordinate{Col: RangeFirstValid, Row: c.Row}
|
||||
index := 0
|
||||
for {
|
||||
squareToAppend := leftMostSquareOnRow.Right(index)
|
||||
if squareToAppend == nil {
|
||||
break
|
||||
}
|
||||
rowToReturn = append(rowToReturn, *squareToAppend)
|
||||
index = index + 1
|
||||
}
|
||||
return rowToReturn
|
||||
}
|
||||
|
||||
func (c Coordinate) GetSquaresOnColumn() []Coordinate {
|
||||
columnToReturn := []Coordinate{}
|
||||
bottomSquareOnColumn := Coordinate{Col: c.Col, Row: RangeFirstValid}
|
||||
index := 0
|
||||
for {
|
||||
squareToAppend := bottomSquareOnColumn.Up(index)
|
||||
if squareToAppend == nil {
|
||||
break
|
||||
}
|
||||
columnToReturn = append(columnToReturn, *squareToAppend)
|
||||
index = index + 1
|
||||
}
|
||||
return columnToReturn
|
||||
return squares
|
||||
}
|
||||
|
@ -6,20 +6,33 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Coordinate_GetSquaresOfRow(t *testing.T) {
|
||||
t.Run("get row for a coordinate", func(t *testing.T) {
|
||||
startSquare := Coordinate{Col: 4, Row: 2}
|
||||
row := startSquare.GetSquaresOnRow()
|
||||
assert.Len(t, row, 8)
|
||||
assert.Equal(t,row[0].Col, 1)
|
||||
assert.Equal(t,row[7].Col, 8)
|
||||
})
|
||||
func Test_Coordinate_GetSquaresOfRowExcludingStartSquare(t *testing.T) {
|
||||
t.Run("get row for a coordinate", func(t *testing.T) {
|
||||
startSquare := Coordinate{Col: 4, Row: 2}
|
||||
row := startSquare.GetStraightInDirection(Coordinate.Left)
|
||||
row = append(row, startSquare.GetStraightInDirection(Coordinate.Right)...)
|
||||
assert.Len(t, row, 7)
|
||||
assert.Equal(t, row[0], Coordinate{Col: 3, Row: 2})
|
||||
assert.Equal(t, row[1], Coordinate{Col: 2, Row: 2})
|
||||
})
|
||||
|
||||
t.Run("get column for a coordinate", func(t *testing.T) {
|
||||
startSquare := Coordinate{Col: 4, Row: 2}
|
||||
column := startSquare.GetSquaresOnColumn()
|
||||
assert.Len(t, column, 8)
|
||||
assert.Equal(t,column[0].Row, 1)
|
||||
assert.Equal(t,column[7].Row, 8)
|
||||
})
|
||||
t.Run("get column for a coordinate", func(t *testing.T) {
|
||||
startSquare := Coordinate{Col: 4, Row: 2}
|
||||
column := startSquare.GetStraightInDirection(Coordinate.Up)
|
||||
column = append(column, startSquare.GetStraightInDirection(Coordinate.Down)...)
|
||||
assert.Len(t, column, 7)
|
||||
assert.Equal(t, column[0], Coordinate{Col: 4, Row: 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetDiagonals(t *testing.T) {
|
||||
square := Coordinate{Col: 5, Row: 5}
|
||||
diagonal := square.GetDiagonalInDirection(Coordinate.Right, Coordinate.Up)
|
||||
|
||||
assert.Len(t, diagonal, 3)
|
||||
assert.Equal(t, []Coordinate{
|
||||
{Col: 6, Row: 6},
|
||||
{Col: 7, Row: 7},
|
||||
{Col: 8, Row: 8},
|
||||
}, diagonal)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user