feat: NCS-25 Add linters to keep quality up (#27)
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
Reviewed-on: #27 Reviewed-by: Leon Hermann <lq@blackhole.local> Co-authored-by: Janis <janis.e.20@gmx.de> Co-committed-by: Janis <janis.e.20@gmx.de>
This commit was merged in pull request #27.
This commit is contained in:
+26
-30
@@ -65,7 +65,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove clears en passant square for non double pawn push"):
|
||||
val context = contextFromFen("4k3/8/8/8/8/8/4P3/4K3 w - d6 3 1")
|
||||
val move = Move(sq("e2"), sq("e3"))
|
||||
val move = Move(sq("e2"), sq("e3"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -73,7 +73,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove resets halfMoveClock on pawn move"):
|
||||
val context = contextFromFen("4k3/8/8/8/8/8/4P3/4K3 w - - 12 1")
|
||||
val move = Move(sq("e2"), sq("e4"))
|
||||
val move = Move(sq("e2"), sq("e4"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -81,7 +81,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove increments halfMoveClock on quiet non pawn move"):
|
||||
val context = contextFromFen("4k3/8/8/8/8/8/8/4K1N1 w - - 7 1")
|
||||
val move = Move(sq("g1"), sq("f3"))
|
||||
val move = Move(sq("g1"), sq("f3"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -89,7 +89,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove resets halfMoveClock on capture"):
|
||||
val context = contextFromFen("r3k3/8/8/8/8/8/8/R3K3 w Qq - 9 1")
|
||||
val move = Move(sq("a1"), sq("a8"), MoveType.Normal(isCapture = true))
|
||||
val move = Move(sq("a1"), sq("a8"), MoveType.Normal(isCapture = true))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -98,7 +98,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove updates castling rights after king move"):
|
||||
val context = contextFromFen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")
|
||||
val move = Move(sq("e1"), sq("e2"))
|
||||
val move = Move(sq("e1"), sq("e2"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -109,7 +109,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove updates castling rights after rook move from h1"):
|
||||
val context = contextFromFen("r3k2r/8/8/8/8/8/8/4K2R w KQkq - 0 1")
|
||||
val move = Move(sq("h1"), sq("h2"))
|
||||
val move = Move(sq("h1"), sq("h2"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -118,7 +118,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove revokes opponent castling right when rook on starting square is captured"):
|
||||
val context = contextFromFen("r3k3/8/8/8/8/8/8/R3K3 w Qq - 2 1")
|
||||
val move = Move(sq("a1"), sq("a8"), MoveType.Normal(isCapture = true))
|
||||
val move = Move(sq("a1"), sq("a8"), MoveType.Normal(isCapture = true))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -126,7 +126,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove executes kingside castling and repositions king and rook"):
|
||||
val context = contextFromFen("4k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1")
|
||||
val move = Move(sq("e1"), sq("g1"), MoveType.CastleKingside)
|
||||
val move = Move(sq("e1"), sq("g1"), MoveType.CastleKingside)
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -137,7 +137,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove executes queenside castling and repositions king and rook"):
|
||||
val context = contextFromFen("r3k3/8/8/8/8/8/8/R3K2R w KQq - 0 1")
|
||||
val move = Move(sq("e1"), sq("c1"), MoveType.CastleQueenside)
|
||||
val move = Move(sq("e1"), sq("c1"), MoveType.CastleQueenside)
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -148,7 +148,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove executes en passant and removes captured pawn"):
|
||||
val context = contextFromFen("k7/8/8/3pP3/8/8/8/7K w - d6 0 1")
|
||||
val move = Move(sq("e5"), sq("d6"), MoveType.EnPassant)
|
||||
val move = Move(sq("e5"), sq("d6"), MoveType.EnPassant)
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -158,7 +158,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove executes promotion with selected piece type"):
|
||||
val context = contextFromFen("4k3/P7/8/8/8/8/8/4K3 w - - 0 1")
|
||||
val move = Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Knight))
|
||||
val move = Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Knight))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -179,7 +179,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove preserves black castling rights after white kingside castling"):
|
||||
val context = contextFromFen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")
|
||||
val move = Move(sq("e1"), sq("g1"), MoveType.CastleKingside)
|
||||
val move = Move(sq("e1"), sq("g1"), MoveType.CastleKingside)
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -190,16 +190,18 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove can revoke both white castling rights when both rooks are captured"):
|
||||
val context = GameContext(
|
||||
board = contextFromFen("4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1").board.updated(sq("a8"), Piece(Color.Black, PieceType.Queen)),
|
||||
board =
|
||||
contextFromFen("4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1").board.updated(sq("a8"), Piece(Color.Black, PieceType.Queen)),
|
||||
turn = Color.Black,
|
||||
castlingRights = CastlingRights(true, true, false, false),
|
||||
enPassantSquare = None,
|
||||
halfMoveClock = 0,
|
||||
moves = List.empty
|
||||
moves = List.empty,
|
||||
)
|
||||
|
||||
val afterA1Capture = DefaultRules.applyMove(context)(Move(sq("a8"), sq("a1"), MoveType.Normal(isCapture = true)))
|
||||
val afterH1Capture = DefaultRules.applyMove(afterA1Capture)(Move(sq("a1"), sq("h1"), MoveType.Normal(isCapture = true)))
|
||||
val afterH1Capture =
|
||||
DefaultRules.applyMove(afterA1Capture)(Move(sq("a1"), sq("h1"), MoveType.Normal(isCapture = true)))
|
||||
|
||||
afterH1Capture.castlingRights.whiteKingSide shouldBe false
|
||||
afterH1Capture.castlingRights.whiteQueenSide shouldBe false
|
||||
@@ -233,7 +235,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove executes black kingside castling and repositions pieces on rank 8"):
|
||||
val context = contextFromFen("r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1")
|
||||
val move = Move(sq("e8"), sq("g8"), MoveType.CastleKingside)
|
||||
val move = Move(sq("e8"), sq("g8"), MoveType.CastleKingside)
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -244,7 +246,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove revokes black castling rights when black rook moves from h8"):
|
||||
val context = contextFromFen("r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1")
|
||||
val move = Move(sq("h8"), sq("h7"))
|
||||
val move = Move(sq("h8"), sq("h7"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -253,7 +255,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove revokes black queenside castling right when black rook moves from a8"):
|
||||
val context = contextFromFen("r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1")
|
||||
val move = Move(sq("a8"), sq("a7"))
|
||||
val move = Move(sq("a8"), sq("a7"))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -262,7 +264,7 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("applyMove revokes black kingside castling right when rook on h8 is captured"):
|
||||
val context = contextFromFen("4k2r/8/8/8/8/8/8/4K2R w Kk - 0 1")
|
||||
val move = Move(sq("h1"), sq("h8"), MoveType.Normal(isCapture = true))
|
||||
val move = Move(sq("h1"), sq("h8"), MoveType.Normal(isCapture = true))
|
||||
|
||||
val next = DefaultRules.applyMove(context)(move)
|
||||
|
||||
@@ -270,31 +272,25 @@ class DefaultRulesStateTransitionsTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("candidateMoves creates all promotion move variants for black pawn"):
|
||||
val context = contextFromFen("4k3/8/8/8/8/8/p7/4K3 b - - 0 1")
|
||||
val to = sq("a1")
|
||||
val to = sq("a1")
|
||||
|
||||
val pawnMoves = DefaultRules.candidateMoves(context)(sq("a2"))
|
||||
val pawnMoves = DefaultRules.candidateMoves(context)(sq("a2"))
|
||||
val promotions = pawnMoves.collect { case Move(_, `to`, MoveType.Promotion(piece)) => piece }
|
||||
|
||||
promotions.toSet shouldBe Set(
|
||||
PromotionPiece.Queen,
|
||||
PromotionPiece.Rook,
|
||||
PromotionPiece.Bishop,
|
||||
PromotionPiece.Knight
|
||||
PromotionPiece.Knight,
|
||||
)
|
||||
|
||||
test("applyMove promotion supports queen rook and bishop targets"):
|
||||
val base = contextFromFen("4k3/P7/8/8/8/8/8/4K3 w - - 0 1")
|
||||
|
||||
val queen = DefaultRules.applyMove(base)(Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Queen)))
|
||||
val rook = DefaultRules.applyMove(base)(Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Rook)))
|
||||
val queen = DefaultRules.applyMove(base)(Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Queen)))
|
||||
val rook = DefaultRules.applyMove(base)(Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Rook)))
|
||||
val bishop = DefaultRules.applyMove(base)(Move(sq("a7"), sq("a8"), MoveType.Promotion(PromotionPiece.Bishop)))
|
||||
|
||||
queen.board.pieceAt(sq("a8")) shouldBe Some(Piece(Color.White, PieceType.Queen))
|
||||
rook.board.pieceAt(sq("a8")) shouldBe Some(Piece(Color.White, PieceType.Rook))
|
||||
bishop.board.pieceAt(sq("a8")) shouldBe Some(Piece(Color.White, PieceType.Bishop))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package de.nowchess.rule
|
||||
|
||||
import de.nowchess.api.board.{Board, Color, File, Rank, Square, Piece, PieceType, CastlingRights}
|
||||
import de.nowchess.api.board.{Board, CastlingRights, Color, File, Piece, PieceType, Rank, Square}
|
||||
import de.nowchess.api.game.GameContext
|
||||
import de.nowchess.api.move.{Move, MoveType}
|
||||
import de.nowchess.io.fen.FenParser
|
||||
@@ -15,31 +15,31 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
// ── Pawn moves ──────────────────────────────────────────────────
|
||||
|
||||
test("pawn can move forward one square"):
|
||||
val fen = "8/8/8/8/8/8/4P3/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val fen = "8/8/8/8/8/8/4P3/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val pawnMoves = moves.filter(m => m.from == Square(File.E, Rank.R2))
|
||||
pawnMoves.exists(m => m.to == Square(File.E, Rank.R3)) shouldBe true
|
||||
|
||||
test("pawn can move forward two squares from starting position"):
|
||||
val context = GameContext.initial
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val e2Moves = moves.filter(m => m.from == Square(File.E, Rank.R2))
|
||||
e2Moves.exists(m => m.to == Square(File.E, Rank.R4)) shouldBe true
|
||||
|
||||
test("pawn can capture diagonally"):
|
||||
// FEN: white pawn e4, black pawn d5
|
||||
val fen = "8/8/8/3p4/4P3/8/8/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val fen = "8/8/8/3p4/4P3/8/8/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val captures = moves.filter(m => m.from == Square(File.E, Rank.R4) && m.moveType.isInstanceOf[MoveType.Normal])
|
||||
captures.exists(m => m.to == Square(File.D, Rank.R5)) shouldBe true
|
||||
|
||||
test("pawn cannot move backward"):
|
||||
// FEN: white pawn on e4
|
||||
val fen = "8/8/8/8/4P3/8/8/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val fen = "8/8/8/8/4P3/8/8/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val pawnMoves = moves.filter(m => m.from == Square(File.E, Rank.R4))
|
||||
pawnMoves.exists(m => m.to == Square(File.E, Rank.R3)) shouldBe false
|
||||
|
||||
@@ -47,18 +47,18 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("moving king out of check removes it from legal moves if king stays in check"):
|
||||
// FEN: white king e1, black rook e8, white tries to move away
|
||||
val fen = "4r3/8/8/8/8/8/8/4K3 w - - 0 1"
|
||||
val fen = "4r3/8/8/8/8/8/8/4K3 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
// King must move; e2 should be valid but d1 might be blocked by rook if still on same file
|
||||
moves.exists(m => m.from == Square(File.E, Rank.R1)) shouldBe true
|
||||
|
||||
test("king cannot move to square attacked by opponent"):
|
||||
// FEN: white king e1, black rook e2 defended by black king e3
|
||||
val fen = "8/8/8/8/8/4k3/4r3/4K3 w - - 0 1"
|
||||
val fen = "8/8/8/8/8/4k3/4r3/4K3 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
// King cannot move to e2 (occupied and attacked)
|
||||
val kingMovesToE2 = moves.filter(m => m.from == Square(File.E, Rank.R1) && m.to == Square(File.E, Rank.R2))
|
||||
@@ -67,64 +67,67 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
// ── Castling legality ────────────────────────────────────────────
|
||||
|
||||
test("castling kingside is legal when king and rook unmoved and path clear"):
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 1"
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val castles = moves.filter(m => m.moveType == MoveType.CastleKingside)
|
||||
castles.nonEmpty shouldBe true
|
||||
|
||||
test("castling queenside is legal when king and rook unmoved and path clear"):
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1"
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val castles = moves.filter(m => m.moveType == MoveType.CastleQueenside)
|
||||
castles.nonEmpty shouldBe true
|
||||
|
||||
test("castling is illegal when castling rights are false"):
|
||||
// FEN: king and rook in position, but castling rights disabled
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w - - 0 1"
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val castles = moves.filter(m => m.moveType == MoveType.CastleKingside)
|
||||
castles.isEmpty shouldBe true
|
||||
|
||||
test("castling is illegal when king is in check"):
|
||||
// FEN: white king e1 in check from black rook e8
|
||||
val fen = "4r3/8/8/8/8/8/8/R3K2R w KQ - 0 1"
|
||||
val fen = "4r3/8/8/8/8/8/8/R3K2R w KQ - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val castles = moves.filter(m => m.moveType == MoveType.CastleKingside || m.moveType == MoveType.CastleQueenside)
|
||||
castles.isEmpty shouldBe true
|
||||
|
||||
test("castling is illegal when path has piece in the way"):
|
||||
// FEN: white king e1, white rook h1, white bishop f1 (blocks f-file)
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBR1 w KQkq - 0 1"
|
||||
val fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBR1 w KQkq - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val castles = moves.filter(m => m.moveType == MoveType.CastleKingside)
|
||||
castles.isEmpty shouldBe true
|
||||
|
||||
test("castling queenside is illegal when knight blocks on b8"):
|
||||
// Black king e8, black rook a8, black knight b8 (blocks queenside path)
|
||||
val board = Board(Map(
|
||||
Square(File.A, Rank.R8) -> Piece(Color.Black, PieceType.Rook),
|
||||
Square(File.B, Rank.R8) -> Piece(Color.Black, PieceType.Knight),
|
||||
Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King),
|
||||
Square(File.A, Rank.R1) -> Piece(Color.White, PieceType.Rook),
|
||||
Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King)
|
||||
))
|
||||
val board = Board(
|
||||
Map(
|
||||
Square(File.A, Rank.R8) -> Piece(Color.Black, PieceType.Rook),
|
||||
Square(File.B, Rank.R8) -> Piece(Color.Black, PieceType.Knight),
|
||||
Square(File.E, Rank.R8) -> Piece(Color.Black, PieceType.King),
|
||||
Square(File.A, Rank.R1) -> Piece(Color.White, PieceType.Rook),
|
||||
Square(File.E, Rank.R1) -> Piece(Color.White, PieceType.King),
|
||||
),
|
||||
)
|
||||
val context = GameContext(
|
||||
board = board,
|
||||
turn = Color.Black,
|
||||
castlingRights = CastlingRights(whiteKingSide = true, whiteQueenSide = true, blackKingSide = true, blackQueenSide = true),
|
||||
castlingRights =
|
||||
CastlingRights(whiteKingSide = true, whiteQueenSide = true, blackKingSide = true, blackQueenSide = true),
|
||||
enPassantSquare = None,
|
||||
halfMoveClock = 0,
|
||||
moves = List.empty
|
||||
moves = List.empty,
|
||||
)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
@@ -135,18 +138,18 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("en passant is legal when en passant square is set"):
|
||||
// FEN: white pawn e5, black pawn d5 (just double-pushed), en passant square d6
|
||||
val fen = "k7/8/8/3pP3/8/8/8/7K w - d6 0 1"
|
||||
val fen = "k7/8/8/3pP3/8/8/8/7K w - d6 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val epMoves = moves.filter(m => m.moveType == MoveType.EnPassant)
|
||||
epMoves.exists(m => m.to == Square(File.D, Rank.R6)) shouldBe true
|
||||
|
||||
test("en passant is illegal when en passant square is none"):
|
||||
// FEN: white pawn e5, black pawn d5, but no en passant square
|
||||
val fen = "k7/8/8/3pP3/8/8/8/7K w - - 0 1"
|
||||
val fen = "k7/8/8/3pP3/8/8/8/7K w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
val epMoves = moves.filter(m => m.moveType == MoveType.EnPassant)
|
||||
epMoves.isEmpty shouldBe true
|
||||
@@ -155,9 +158,9 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("pinned piece cannot move and expose king to check"):
|
||||
// FEN: white king e1, white bishop d2 (pinned), black rook a2
|
||||
val fen = "8/8/8/8/8/8/r1B1K3/8 w - - 0 1"
|
||||
val fen = "8/8/8/8/8/8/r1B1K3/8 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
// Bishop on d2 is pinned by rook on a2; it cannot move
|
||||
val bishopMoves = moves.filter(m => m.from == Square(File.C, Rank.R2))
|
||||
@@ -166,9 +169,9 @@ class DefaultRulesTest extends AnyFunSuite with Matchers:
|
||||
test("piece blocking a check is legal"):
|
||||
// FEN: white king e1, white rook d1, black bishop a4 attacking e1 via d2
|
||||
// Actually, this is complex. Let's use: white king e1, black rook e8, white pawn blocks on e2
|
||||
val fen = "4r3/8/8/8/8/8/4P3/4K3 w - - 0 1"
|
||||
val fen = "4r3/8/8/8/8/8/4P3/4K3 w - - 0 1"
|
||||
val context = FenParser.parseFen(fen).fold(_ => fail(), identity)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
val moves = rules.allLegalMoves(context)
|
||||
|
||||
// White is in check; only moves that block or move the king are legal
|
||||
moves.nonEmpty shouldBe true
|
||||
|
||||
Reference in New Issue
Block a user