1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
#include "unittest.h"
#include "board.h"
#include "bitboard.h"
int main() {
testSection("Bitboards"); {
unitTest(popCount(0b01110) == 3, "Pop count of 01110 is 3");
Bitboard bb = 0b1100;
unitTest(bitscanAndReset(&bb) == 2, "Bitscan of 0b1100 is 2");
unitTest(bb == 0b1000, "After bitscan with reset the LS1B is flipped");
}
testSection("Default FEN string"); {
Board board = parseFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
unitTest(popCount(board.pieces[PAWN] | board.pieces[PAWN | BLACK]) == 16, "There are 16 pawns total");
unitTest(popCount(board.pieces[ROOK]) == 2, "There are 2 white rooks");
// TODO
unitTest(board.side == WHITE, "Side to move is white");
unitTest(board.castlingRights == 0, "Both sides can castle");
unitTest(board.enPassantSquare == 0, "No en passant move is avaialble");
}
testSection("Knight attack table"); {
Bitboard attacks[64];
precomputeKnightAttackTable(attacks);
int maxAttacks = 0;
for (int i = 0; i < 64; i++) {
int attackCount = popCount(attacks[i]);
if (attackCount > maxAttacks) maxAttacks = attackCount;
}
unitTest(maxAttacks == 8, "Max amount of knight attacks should be 8");
unitTest(
attacks[b7] == ((BIT << d8) | (BIT << d6) | (BIT << c5) | (BIT << a5)),
"Knight on b7 attacks only d8, d6, c5, a5"
);
}
testSection("King attack table"); {
Bitboard attacks[64];
precomputeKingAttackTable(attacks);
int maxAttacks = 0;
for (int i = 0; i < 64; i++) {
int attackCount = popCount(attacks[i]);
if (attackCount > maxAttacks) maxAttacks = attackCount;
}
unitTest(maxAttacks == 8, "Max amount of king attacks should be 8");
unitTest(
attacks[h2] == ((BIT << h1) | (BIT << g1) | (BIT << g2) | (BIT << g3) | (BIT << h3)),
"King on h2 attacks only h1, g1, g2, g3, h3"
);
}
testSection("Pawn attack table"); {
Bitboard whiteAttacks[64];
Bitboard blackAttacks[64];
precomputePawnAttackTable(whiteAttacks, WHITE);
precomputePawnAttackTable(blackAttacks, BLACK);
int isSame = 0;
int maxAttacks = 0;
for (int i = 0; i < 64; i++) {
int attackCount = popCount(whiteAttacks[i]);
if (attackCount > maxAttacks) maxAttacks = attackCount;
if (whiteAttacks[i] == blackAttacks[i]) isSame = 1;
}
unitTest(maxAttacks == 2, "Max amount of pawn attacks should be 2");
unitTest(isSame == 0, "Black and white pawns always move differently");
unitTest(whiteAttacks[g2] == (BIT << h3 | BIT << f3), "White pawn on g2 attacks only h3 and f3");
}
testSection("Attacks to square in starting position"); {
precomputeKnightAttackTable(KNIGHT_ATTACKS);
precomputePawnAttackTable(WHITE_PAWN_ATTACKS, WHITE);
precomputePawnAttackTable(BLACK_PAWN_ATTACKS, BLACK);
Board board = parseFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
unitTest(attacksToSquare(board, c3) == ((BIT << b1) | (BIT << b2) | (BIT << d2)), "c3 is protected only by b1, b2, d2");
unitTest(attacksToSquare(board, f6) == ((BIT << g8) | (BIT << g7) | (BIT << e7)), "f6 is protected only by g8, g7, e7");
// TODO
unitTest(attacksToSquare(board, d2) == ((BIT << b1) | (BIT << c1) | (BIT << d1) | (BIT << e1)), "d2 is protected only b1, c1, d1, e1");
}
report();
return 0;
}
|