Skip to content

Commit c9994f6

Browse files
committed
test: add additional castling constraints and pawn movement tests
1 parent 2fa9f86 commit c9994f6

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package dev.tabansi.chess
2+
3+
import dev.tabansi.chess.Board.EMPTY
4+
import dev.tabansi.chess.Board.KING
5+
import dev.tabansi.chess.Board.PLAYER_1
6+
import dev.tabansi.chess.Board.PLAYER_2
7+
import dev.tabansi.chess.Board.ROOK
8+
import dev.tabansi.chess.Board.board
9+
import dev.tabansi.chess.pieces.Rook
10+
import kotlin.test.Test
11+
import kotlin.test.assertFalse
12+
13+
class AdditionalCastlingRulesTest {
14+
15+
private fun clearBoard() {
16+
for (i in 0 until 8) for (j in 0 until 8) board[i][j] = EMPTY
17+
}
18+
19+
@Test
20+
fun white_kingside_castle_disallowed_if_king_has_moved() {
21+
clearBoard()
22+
val p1 = Player(PLAYER_1)
23+
// Place king and rook in starting squares
24+
board[7][4] = KING + PLAYER_1
25+
board[7][7] = ROOK + PLAYER_1
26+
// Mark king as having moved earlier
27+
p1.king.hasMoved = true
28+
val moves = p1.king.getMoves()
29+
assertFalse(moves.contains(BoardSpace(7, 6)), "Castling should be disallowed if the king has moved")
30+
}
31+
32+
@Test
33+
fun white_kingside_castle_disallowed_if_rook_has_moved() {
34+
clearBoard()
35+
val p1 = Player(PLAYER_1)
36+
// Place king and rook in starting squares
37+
board[7][4] = KING + PLAYER_1
38+
board[7][7] = ROOK + PLAYER_1
39+
// Mark rook as having moved earlier
40+
val rook = p1.getPiece(BoardSpace(7, 7)) as Rook
41+
rook.hasMoved = true
42+
val moves = p1.king.getMoves()
43+
assertFalse(moves.contains(BoardSpace(7, 6)), "Castling should be disallowed if the rook has moved")
44+
}
45+
46+
@Test
47+
fun white_queenside_castle_disallowed_if_path_blocked() {
48+
clearBoard()
49+
val p1 = Player(PLAYER_1)
50+
// Place king and rook in starting squares
51+
board[7][4] = KING + PLAYER_1
52+
board[7][0] = ROOK + PLAYER_1
53+
// Block the square next to the king on queen side (7,3)
54+
board[7][3] = ROOK + PLAYER_1
55+
val moves = p1.king.getMoves()
56+
assertFalse(moves.contains(BoardSpace(7, 2)), "Castling should be disallowed if the path is blocked")
57+
}
58+
59+
@Test
60+
fun black_kingside_castle_disallowed_if_king_in_check() {
61+
clearBoard()
62+
val p2 = Player(PLAYER_2)
63+
// Place king and rook in starting squares
64+
board[0][4] = KING + PLAYER_2
65+
board[0][7] = ROOK + PLAYER_2
66+
// Put white rook attacking the king on the same file
67+
board[3][4] = ROOK + PLAYER_1
68+
val moves = p2.king.getMoves()
69+
assertFalse(moves.contains(BoardSpace(0, 6)), "Castling should be disallowed if the king is currently in check")
70+
}
71+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package dev.tabansi.chess
2+
3+
import dev.tabansi.chess.Board.EMPTY
4+
import dev.tabansi.chess.Board.KING
5+
import dev.tabansi.chess.Board.PAWN
6+
import dev.tabansi.chess.Board.PLAYER_1
7+
import dev.tabansi.chess.Board.PLAYER_2
8+
import dev.tabansi.chess.Board.ROOK
9+
import dev.tabansi.chess.Board.board
10+
import dev.tabansi.chess.pieces.Pawn
11+
import kotlin.test.Test
12+
import kotlin.test.assertEquals
13+
import kotlin.test.assertFalse
14+
import kotlin.test.assertTrue
15+
16+
class PawnMovementTest {
17+
18+
private fun clearBoard() {
19+
for (i in 0 until 8) for (j in 0 until 8) board[i][j] = EMPTY
20+
}
21+
22+
@Test
23+
fun white_pawn_initial_two_step_when_clear() {
24+
clearBoard()
25+
// White king somewhere safe
26+
board[7][4] = KING + PLAYER_1
27+
val p1 = Player(PLAYER_1)
28+
val pawn = Pawn(BoardSpace(6, 4), p1)
29+
board[6][4] = PAWN + PLAYER_1
30+
// path clear
31+
val moves = pawn.getMoves()
32+
assertTrue(moves.contains(BoardSpace(5, 4)))
33+
assertTrue(moves.contains(BoardSpace(4, 4)))
34+
}
35+
36+
@Test
37+
fun white_pawn_blocked_forward_cannot_move() {
38+
clearBoard()
39+
board[7][4] = KING + PLAYER_1
40+
val p1 = Player(PLAYER_1)
41+
val pawn = Pawn(BoardSpace(6, 4), p1)
42+
board[6][4] = PAWN + PLAYER_1
43+
// Block immediate square
44+
board[5][4] = ROOK + PLAYER_1
45+
val moves = pawn.getMoves()
46+
assertFalse(moves.contains(BoardSpace(5, 4)))
47+
assertFalse(moves.contains(BoardSpace(4, 4)))
48+
}
49+
50+
@Test
51+
fun white_pawn_two_step_blocked_when_second_square_occupied() {
52+
clearBoard()
53+
board[7][4] = KING + PLAYER_1
54+
val p1 = Player(PLAYER_1)
55+
val pawn = Pawn(BoardSpace(6, 4), p1)
56+
board[6][4] = PAWN + PLAYER_1
57+
// Immediate square empty, second square occupied
58+
board[4][4] = ROOK + PLAYER_2
59+
val moves = pawn.getMoves()
60+
assertTrue(moves.contains(BoardSpace(5, 4)))
61+
assertFalse(moves.contains(BoardSpace(4, 4)))
62+
}
63+
64+
@Test
65+
fun white_pawn_diagonal_capture_allowed() {
66+
clearBoard()
67+
board[7][4] = KING + PLAYER_1
68+
val p1 = Player(PLAYER_1)
69+
val pawn = Pawn(BoardSpace(6, 4), p1)
70+
board[6][4] = PAWN + PLAYER_1
71+
// Enemy on (5,5)
72+
board[5][5] = ROOK + PLAYER_2
73+
val moves = pawn.getMoves()
74+
assertTrue(moves.contains(BoardSpace(5, 5)))
75+
}
76+
77+
@Test
78+
fun black_pawn_initial_two_step_when_clear() {
79+
clearBoard()
80+
// Black king somewhere safe
81+
board[0][4] = KING + PLAYER_2
82+
val p2 = Player(PLAYER_2)
83+
val pawn = Pawn(BoardSpace(1, 3), p2)
84+
board[1][3] = PAWN + PLAYER_2
85+
val moves = pawn.getMoves()
86+
assertTrue(moves.contains(BoardSpace(2, 3)))
87+
assertTrue(moves.contains(BoardSpace(3, 3)))
88+
}
89+
90+
@Test
91+
fun black_pawn_diagonal_capture_allowed() {
92+
clearBoard()
93+
board[0][4] = KING + PLAYER_2
94+
val p2 = Player(PLAYER_2)
95+
val pawn = Pawn(BoardSpace(1, 3), p2)
96+
board[1][3] = PAWN + PLAYER_2
97+
// Enemy on (2,4)
98+
board[2][4] = ROOK + PLAYER_1
99+
val moves = pawn.getMoves()
100+
assertTrue(moves.contains(BoardSpace(2, 4)))
101+
}
102+
103+
@Test
104+
fun pawn_move_disallowed_if_it_exposes_own_king_to_check() {
105+
clearBoard()
106+
// White king on 7,4; enemy rook on 7,0 attacking horizontally if path opens
107+
board[7][4] = KING + PLAYER_1
108+
board[7][0] = ROOK + PLAYER_2
109+
// Place white pawn at 7,2 which currently blocks the rook's path to the king
110+
val p1 = Player(PLAYER_1)
111+
val pawn = Pawn(BoardSpace(7, 2), p1)
112+
board[7][2] = PAWN + PLAYER_1
113+
// Ensure squares (7,1) and (7,3) are empty so moving the pawn would expose the king
114+
// (they are already empty on a clear board)
115+
val moves = pawn.getMoves()
116+
assertFalse(moves.contains(BoardSpace(6, 2)), "Pawn should not be allowed to move if it exposes the king to check")
117+
}
118+
}

0 commit comments

Comments
 (0)