many many changes again.
This commit is contained in:
parent
3d4fee2631
commit
f733d9bb08
@ -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{}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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{
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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{}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
@ -124,7 +135,7 @@ func (p Pawn) getAllMoves(fromSquare types.Coordinate) []types.Coordinate {
|
|||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user