many many changes again.

This commit is contained in:
Marco 2023-06-27 22:32:24 +02:00
parent 3d4fee2631
commit f733d9bb08
13 changed files with 269 additions and 160 deletions

View File

@ -1,15 +1,21 @@
package chess package chess
import "mchess_server/types" import (
"mchess_server/types"
)
type Bishop struct { type Bishop struct {
Color types.ChessColor 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 { func (b Bishop) GetColor() types.ChessColor {
return b.Color 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{} return []types.Coordinate{}
} }

View File

@ -1,6 +1,7 @@
package chess package chess
import ( import (
"errors"
"mchess_server/types" "mchess_server/types"
"github.com/samber/lo" "github.com/samber/lo"
@ -78,7 +79,7 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
if !wasSpecialMove { if !wasSpecialMove {
// At the moment, we do not need to check if the correct color is moving, // 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. //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) legal := lo.Contains(allMovesExceptBlocked, move.EndSquare)
if !legal { if !legal {
return false, "not a legal square" return false, "not a legal square"
@ -89,16 +90,12 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
tempBoard.position[move.EndSquare] = pieceAtStartSquare tempBoard.position[move.EndSquare] = pieceAtStartSquare
} }
//Check if king of moving color is in check -> move not allowed kingAttacked, err := tempBoard.isKingOfMovingColorInCheck(move.ColorMoved)
//Do that by checking if the king is in a square attacked by the other color. if err != nil {
ownKingCoordinate := tempBoard.getSquareOfPiece(King{Color: move.ColorMoved}) return false, "something went wrong"
if ownKingCoordinate == nil {
return false, string(move.ColorMoved) + " king not found"
} }
if kingAttacked {
kingIsAttacked := tempBoard.isSquareAttacked(*ownKingCoordinate, move.ColorMoved.Opposite()) return false, "king would be in check after move"
if kingIsAttacked {
return false, "king is attacked after move"
} }
//Check for checkmat&e //Check for checkmat&e
@ -118,10 +115,24 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
b.position = tempBoard.position b.position = tempBoard.position
b.history = tempBoard.history b.history = tempBoard.history
b.appendMoveToHistory(move) b.appendMoveToHistory(move)
return true, "" 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 { func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate {
for k, v := range b.position { for k, v := range b.position {
if v == piece { if v == piece {
@ -135,9 +146,10 @@ func (b Board) isSquareAttacked(square types.Coordinate, byColor types.ChessColo
var attackedSquares []types.Coordinate var attackedSquares []types.Coordinate
for square, piece := range b.position { 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) return lo.Contains(attackedSquares, square)
} }
@ -146,7 +158,6 @@ func (b Board) getPieceAt(coord types.Coordinate) Piece {
if !found { if !found {
return nil return nil
} }
return piece return piece
} }
@ -183,7 +194,7 @@ func (b *Board) handleSpecialMove(move types.Move) bool {
switch pieceAtStartSquare.(type) { switch pieceAtStartSquare.(type) {
case Pawn: case Pawn:
pawn := pieceAtStartSquare.(Pawn) pawn := pieceAtStartSquare.(Pawn)
was = pawn.HandlePossiblePromotion(b, move) was = pawn.HandlePossiblePromotion(b, move)
if !was { if !was {
was = pawn.HandleEnPassant(b, move, b.getLastMove()) was = pawn.HandleEnPassant(b, move, b.getLastMove())
@ -191,5 +202,3 @@ func (b *Board) handleSpecialMove(move types.Move) bool {
} }
return was return was
} }

View File

@ -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: 1, Row: 6}] = King{Color: types.White}
board.position[types.Coordinate{Col: 2, Row: 6}] = Pawn{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{ move := types.Move{
StartSquare: types.Coordinate{Col: 2, Row: 6}, StartSquare: types.Coordinate{Col: 2, Row: 6},
EndSquare: types.Coordinate{Col: 2, Row: 7}, EndSquare: types.Coordinate{Col: 2, Row: 7},
} }
good, _ := board.CheckAndPlay(move) good, _ := board.CheckAndPlay(move)
assert.False(t, good) 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: 7}] = Pawn{Color: types.White}
board.position[types.Coordinate{Col: 1, Row: 1}] = King{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 shortName := types.QueenShortName
move := types.Move{ move := types.Move{

View File

@ -3,26 +3,44 @@ package chess
import "mchess_server/types" import "mchess_server/types"
func (b *Board) GetNonBlockedRowAndColumn(fromSquare types.Coordinate) []types.Coordinate { func (b *Board) GetNonBlockedRowAndColumn(fromSquare types.Coordinate) []types.Coordinate {
squaresLeft := fromSquare.GetAllSquaresLeft() squaresLeft := fromSquare.GetStraightInDirection(types.Coordinate.Left)
squaresRight := fromSquare.GetAllSquaresRight() squaresRight := fromSquare.GetStraightInDirection(types.Coordinate.Right)
squaresAbove := fromSquare.GetAllSquaresAbove() squaresAbove := fromSquare.GetStraightInDirection(types.Coordinate.Up)
squaresBelow := fromSquare.GetAllSquaresBelow() squaresBelow := fromSquare.GetStraightInDirection(types.Coordinate.Down)
nonBlocked := []types.Coordinate{}
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresLeft, fromSquare)...) nonBlocked := b.getNonBlocked(squaresLeft, fromSquare)
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresRight, fromSquare)...) nonBlocked = append(nonBlocked, b.getNonBlocked(squaresRight, fromSquare)...)
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresAbove, fromSquare)...) nonBlocked = append(nonBlocked, b.getNonBlocked(squaresAbove, fromSquare)...)
nonBlocked = append(nonBlocked, b.getNonBlocked(squaresBelow, fromSquare)...) nonBlocked = append(nonBlocked, b.getNonBlocked(squaresBelow, fromSquare)...)
return nonBlocked 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( func (b *Board) getNonBlocked(
squaresToCheck []types.Coordinate, squaresToCheck []types.Coordinate,
sourceSquare types.Coordinate, sourceSquare types.Coordinate,
) []types.Coordinate { ) []types.Coordinate {
pieceOnSourceSquare := b.getPieceAt(sourceSquare) pieceOnSourceSquare := b.getPieceAt(sourceSquare)
nonBlocked := []types.Coordinate{} nonBlocked := []types.Coordinate{}
for _, square := range squaresToCheck { for _, square := range squaresToCheck {
piece := b.getPieceAt(square) piece := b.getPieceAt(square)
@ -37,5 +55,5 @@ func (b *Board) getNonBlocked(
} }
nonBlocked = append(nonBlocked, square) nonBlocked = append(nonBlocked, square)
} }
return nonBlocked return nonBlocked
} }

View File

@ -1,15 +1,21 @@
package chess package chess
import "mchess_server/types" import (
"mchess_server/types"
)
type King struct { 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 { func (k King) GetColor() types.ChessColor {
return k.Color 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{} return []types.Coordinate{}
} }

View File

@ -1,19 +1,21 @@
package chess package chess
import "mchess_server/types" import (
"mchess_server/types"
)
type Knight struct { type Knight struct {
Color types.ChessColor Color types.ChessColor
} }
// AfterMoveAction implements Piece. func (k Knight) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
func (k Knight) AfterMoveAction() { return k.GetAllNonBlockedMoves(board, fromSquare)
} }
func (k Knight) GetColor() types.ChessColor { func (k Knight) GetColor() types.ChessColor {
return k.Color return k.Color
} }
func (k Knight) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate { func (k Knight) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
return []types.Coordinate{} return board.GetNonBlockedKnightMoves(fromSquare)
} }

View File

@ -10,7 +10,18 @@ type Pawn struct {
Color types.ChessColor 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) theoreticalSquares := p.getAllMoves(fromSquare)
legalSquares := p.filterBlockedSquares(board, fromSquare, theoreticalSquares) legalSquares := p.filterBlockedSquares(board, fromSquare, theoreticalSquares)
@ -21,37 +32,37 @@ func (p Pawn) GetColor() types.ChessColor {
return p.Color return p.Color
} }
func (p *Pawn) HandlePossiblePromotion(b *Board ,move types.Move) bool { func (p *Pawn) HandlePossiblePromotion(b *Board, move types.Move) bool {
var isPromotionMove bool var isPromotionMove bool
var promotionToPiece types.PieceShortName 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 //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() messageContainsPromotion := move.IsPromotionMove()
if messageContainsPromotion { if messageContainsPromotion {
promotionToPiece = *move.PromotionToPiece promotionToPiece = *move.PromotionToPiece
} }
switch move.ColorMoved { switch move.ColorMoved {
case types.White: case types.White:
if move.StartSquare.Row == types.RangeLastValid-1 && if move.StartSquare.Row == types.RangeLastValid-1 &&
move.EndSquare.Row == types.RangeLastValid { move.EndSquare.Row == types.RangeLastValid {
isPromotionMove = true isPromotionMove = true
} }
case types.Black: case types.Black:
if move.StartSquare.Row == types.RangeFirstValid+1 && if move.StartSquare.Row == types.RangeFirstValid+1 &&
move.EndSquare.Row == types.RangeFirstValid { move.EndSquare.Row == types.RangeFirstValid {
isPromotionMove = true isPromotionMove = true
} }
} }
if isPromotionMove { if isPromotionMove {
delete(b.position, move.StartSquare) delete(b.position, move.StartSquare)
b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved) b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved)
} }
return isPromotionMove return isPromotionMove
} }
func (p *Pawn) HandleEnPassant(b *Board, move, lastMove types.Move) bool { 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 { switch p.Color {
case types.Black: case types.Black:
firstMove := fromSquare.Row == types.RangeLastValid-1 firstMove := fromSquare.Row == types.RangeLastValid-1
if fromSquare.Down(1) != nil { if fromSquare.Down(1) != nil {
theoreticalMoves = append(theoreticalMoves, *fromSquare.Down(1)) theoreticalMoves = append(theoreticalMoves, *fromSquare.Down(1))
} }
if firstMove && fromSquare.Down(2) != nil { 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) return lo.Intersect(nonBlockedSquares, squaresToBeFiltered)
} }

View File

@ -5,7 +5,8 @@ import (
) )
type Piece interface { 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 GetColor() types.ChessColor
} }

View File

@ -1,15 +1,23 @@
package chess package chess
import "mchess_server/types" import (
"mchess_server/types"
)
type Queen struct { type Queen struct {
Color types.ChessColor 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 { func (q Queen) GetColor() types.ChessColor {
return q.Color return q.Color
} }
func (q Queen) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate { func (q Queen) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
return []types.Coordinate{} squares := board.GetNonBlockedRowAndColumn(fromSquare)
squares = append(squares, board.GetNonBlockedDiagonals(fromSquare)...)
return squares
} }

View File

@ -1,11 +1,17 @@
package chess package chess
import "mchess_server/types" import (
"mchess_server/types"
)
type Rook struct { type Rook struct {
Color types.ChessColor Color types.ChessColor
} }
func (r Rook) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate {
return r.GetAllNonBlockedMoves(board, fromSquare)
}
func (r Rook) AfterMoveAction() { func (r Rook) AfterMoveAction() {
} }
@ -13,6 +19,6 @@ func (r Rook) GetColor() types.ChessColor {
return r.Color return r.Color
} }
func (r Rook) GetAllMovesButBlocked(board Board, fromSquare types.Coordinate) []types.Coordinate { func (r Rook) GetAllNonBlockedMoves(board Board, fromSquare types.Coordinate) []types.Coordinate {
return board.GetNonBlockedRowAndColumn(fromSquare) return board.GetNonBlockedRowAndColumn(fromSquare)
} }

View File

@ -14,9 +14,8 @@ func Test_Rook_GetNonBlockedSquares(t *testing.T) {
rook := Rook{Color: types.Black} rook := Rook{Color: types.Black}
board.position[types.Coordinate{Col: 5, Row: 5}] = rook 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.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) { 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: 5, Row: 6}] = Pawn{Color: types.White}
board.position[types.Coordinate{Col: 6, Row: 5}] = Pawn{Color: types.Black} 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 { squaresOnLeft := lo.Filter(squares, func(square types.Coordinate, _ int) bool {
return square.Row == rookCoordinate.Row && square.Col < rookCoordinate.Col return square.Row == rookCoordinate.Row && square.Col < rookCoordinate.Col

View File

@ -1,5 +1,7 @@
package types package types
import "github.com/samber/lo"
// coordinates starting at 1:1 and end at 8:8 // coordinates starting at 1:1 and end at 8:8
type Coordinate struct { type Coordinate struct {
Col int `json:"col"` Col int `json:"col"`
@ -14,6 +16,65 @@ const (
RangeLowerInvalid = 0 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 { func (c Coordinate) Up(number int) *Coordinate {
check := c.Row + number check := c.Row + number
if check <= RangeLastValid { if check <= RangeLastValid {
@ -45,11 +106,27 @@ func (c Coordinate) Left(number int) *Coordinate {
return nil 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{} squares := []Coordinate{}
i := 1 i := 1
for { for {
if square := c.Left(i); square != nil { if square := dirFn(c, i); square != nil {
squares = append(squares, *square) squares = append(squares, *square)
i += 1 i += 1
} else { } 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{} squares := []Coordinate{}
i := 1 i := 1
for { for {
if square := c.Right(i); square != nil { if squareRight := dirFn1(c, i); squareRight != nil {
squares = append(squares, *square) if square := dirFn2(*squareRight, i); square != nil {
i += 1 squares = append(squares, *square)
i += 1
} else {
break
}
} else { } 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 break
} }
rowToReturn = append(rowToReturn, *squareToAppend)
index = index + 1
} }
return rowToReturn return squares
}
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
} }

View File

@ -6,20 +6,33 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func Test_Coordinate_GetSquaresOfRow(t *testing.T) { func Test_Coordinate_GetSquaresOfRowExcludingStartSquare(t *testing.T) {
t.Run("get row for a coordinate", func(t *testing.T) { t.Run("get row for a coordinate", func(t *testing.T) {
startSquare := Coordinate{Col: 4, Row: 2} startSquare := Coordinate{Col: 4, Row: 2}
row := startSquare.GetSquaresOnRow() row := startSquare.GetStraightInDirection(Coordinate.Left)
assert.Len(t, row, 8) row = append(row, startSquare.GetStraightInDirection(Coordinate.Right)...)
assert.Equal(t,row[0].Col, 1) assert.Len(t, row, 7)
assert.Equal(t,row[7].Col, 8) 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) { t.Run("get column for a coordinate", func(t *testing.T) {
startSquare := Coordinate{Col: 4, Row: 2} startSquare := Coordinate{Col: 4, Row: 2}
column := startSquare.GetSquaresOnColumn() column := startSquare.GetStraightInDirection(Coordinate.Up)
assert.Len(t, column, 8) column = append(column, startSquare.GetStraightInDirection(Coordinate.Down)...)
assert.Equal(t,column[0].Row, 1) assert.Len(t, column, 7)
assert.Equal(t,column[7].Row, 8) 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)
} }