#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; }