// Bitboard-Schachengine – Komplette finale Version
// Enthält: Bitboards, vollständige Figurenlogik, Bewertung, Zuggenerierung, Legalitätsprüfung,
// Alpha-Beta mit Quiescence, Killer-Moves, Transposition Tables (Zobrist Hashing), Iterative Deepening, UCI-Schnittstelle
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
typedef uint64_t Bitboard;
#define WHITE 0
#define BLACK 1
#define PAWN 0
#define KNIGHT 1
#define BISHOP 2
#define ROOK 3
#define QUEEN 4
#define KING 5
#define MAX_DEPTH 64
#define TABLE_SIZE (1 << 20)
typedef struct {
int from, to, piece;
int promotion;
int is_en_passant;
} Move;
typedef struct {
uint64_t key;
int value;
int depth;
int flag; // 0=exact, 1=lowerbound, 2=upperbound
} TTEntry;
Bitboard pieces[2][6];
int side_to_move = WHITE;
int en_passant_square = -1;
int piece_values[6] = {100, 320, 330, 500, 900, 10000};
Move killer_moves[MAX_DEPTH][2];
TTEntry tt[TABLE_SIZE];
uint64_t zobrist[2][6][64], zobrist_side;
#define SET_BIT(bb, sq) ((bb) |= (1ULL << (sq)))
#define CLEAR_BIT(bb, sq) ((bb) &= ~(1ULL << (sq)))
#define IS_SET(bb, sq) ((bb) & (1ULL << (sq)))
void init_zobrist();
uint64_t compute_hash();
void tt_store(uint64_t hash, int value, int depth, int flag);
TTEntry* tt_probe(uint64_t hash, int depth, int alpha, int beta);
void set_startpos();
int evaluate_material();
Bitboard knight_moves(int sq);
Bitboard bishop_attacks(int sq, Bitboard blockers);
Bitboard rook_attacks(int sq, Bitboard blockers);
Bitboard queen_attacks(int sq, Bitboard blockers);
Bitboard king_moves(int sq);
int king_in_check(int side);
void make_move(Move m, int side);
void undo_move(Move m, int side);
int is_legal(Move m, int side);
int generate_pawn_moves(Move *moves, int side);
int generate_all_moves(Move *moves, int side);
void store_killer(Move m, int depth);
int same_move(Move a, Move b);
int move_score(Move m, int depth);
void sort_moves_heuristic(Move *moves, int count, int depth);
int quiescence(int alpha, int beta, int side);
int alphabeta_tt(int depth, int alpha, int beta, int ply, int side);
Move search_final(int max_depth);
void uci_loop();
void square_to_uci(int sq, char *buf);
int main() {
srand(time(NULL));
uci_loop();
return 0;
}
// --- Zobrist Hashing ---
void init_zobrist() {
for (int s = 0; s < 2; s++)
for (int p = 0; p < 6; p++)
for (int sq = 0; sq < 64; sq++)
zobrist[s][p][sq] = ((uint64_t)rand() << 32) | rand();
zobrist_side = ((uint64_t)rand() << 32) | rand();
}
uint64_t compute_hash() {
uint64_t h = 0;
for (int s = 0; s < 2; s++)
for (int p = 0; p < 6; p++) {
Bitboard b = pieces[s][p];
while (b) {
int sq = __builtin_ctzll(b);
h ^= zobrist[s][p][sq];
b &= b - 1;
}
}
if (side_to_move == BLACK) h ^= zobrist_side;
return h;
}
// --- Bewertung ---
int evaluate_material() {
int score = 0;
for (int pt = 0; pt < 6; pt++)
score += (__builtin_popcountll(pieces[WHITE][pt]) - __builtin_popcountll(pieces[BLACK][pt])) * piece_values[pt];
return (side_to_move == WHITE) ? score : -score;
}
// --- Startposition ---
void set_startpos() {
memset(pieces, 0, sizeof(pieces));
pieces[WHITE][PAWN] = 0x000000000000FF00ULL;
pieces[BLACK][PAWN] = 0x00FF000000000000ULL;
pieces[WHITE][KNIGHT] = 0x0000000000000042ULL;
pieces[BLACK][KNIGHT] = 0x4200000000000000ULL;
pieces[WHITE][BISHOP] = 0x0000000000000024ULL;
pieces[BLACK][BISHOP] = 0x2400000000000000ULL;
pieces[WHITE][ROOK] = 0x0000000000000081ULL;
pieces[BLACK][ROOK] = 0x8100000000000000ULL;
pieces[WHITE][QUEEN] = 0x0000000000000008ULL;
pieces[BLACK][QUEEN] = 0x0800000000000000ULL;
pieces[WHITE][KING] = 0x0000000000000010ULL;
pieces[BLACK][KING] = 0x1000000000000000ULL;
side_to_move = WHITE;
en_passant_square = -1;
}
// --- Figurenlogik ---
Bitboard knight_moves(int sq) {
Bitboard bb = 0;
int r = sq / 8, f = sq % 8;
int dr[8] = {-2,-1,1,2,2,1,-1,-2};
int df[8] = {1,2,2,1,-1,-2,-2,-1};
for (int i = 0; i < 8; i++) {
int nr = r + dr, nf = f + df;
if (nr >= 0 && nr < 8 && nf >= 0 && nf < 8)
SET_BIT(bb, nr * 8 + nf);
}
return bb;
}
Bitboard bishop_attacks(int sq, Bitboard blockers) {
Bitboard attacks = 0;
int r = sq / 8, f = sq % 8;
for (int dr = 1, df = 1; r+dr<8 && f+df<8; dr++, df++) {
int s = (r+dr)*8 + (f+df);
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
for (int dr = 1, df = -1; r+dr<8 && f+df>=0; dr++, df--) {
int s = (r+dr)*8 + (f+df);
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
for (int dr = -1, df = 1; r+dr>=0 && f+df<8; dr--, df++) {
int s = (r+dr)*8 + (f+df);
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
for (int dr = -1, df = -1; r+dr>=0 && f+df>=0; dr--, df--) {
int s = (r+dr)*8 + (f+df);
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
return attacks;
}
Bitboard rook_attacks(int sq, Bitboard blockers) {
Bitboard attacks = 0;
int r = sq / 8, f = sq % 8;
for (int df = f + 1; df < 8; df++) {
int s = r * 8 + df;
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
for (int df = f - 1; df >= 0; df--) {
int s = r * 8 + df;
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
for (int dr = r + 1; dr < 8; dr++) {
int s = dr * 8 + f;
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
for (int dr = r - 1; dr >= 0; dr--) {
int s = dr * 8 + f;
SET_BIT(attacks, s);
if (IS_SET(blockers, s)) break;
}
return attacks;
}
Bitboard queen_attacks(int sq, Bitboard blockers) {
return rook_attacks(sq, blockers) | bishop_attacks(sq, blockers);
}
Bitboard king_moves(int sq) {
Bitboard bb = 0;
int r = sq / 8, f = sq % 8;
for (int dr = -1; dr <= 1; dr++) {
for (int df = -1; df <= 1; df++) {
if (dr == 0 && df == 0) continue;
int nr = r + dr, nf = f + df;
if (nr >= 0 && nr < 8 && nf >= 0 && nf < 8)
SET_BIT(bb, nr * 8 + nf);
}
}
return bb;
}
// --- Legalitätsprüfung, Zugausführung und -rücknahme ---
int king_in_check(int side) {
Bitboard king = pieces[side][KING];
if (!king) return 1;
int sq = __builtin_ctzll(king);
Bitboard all = 0;
for (int pt = 0; pt < 6; pt++)
all |= pieces[WHITE][pt] | pieces[BLACK][pt];
if (king_moves(sq) & pieces[1 - side][KING]) return 1;
if (rook_attacks(sq, all) & (pieces[1 - side][ROOK] | pieces[1 - side][QUEEN])) return 1;
if (bishop_attacks(sq, all) & (pieces[1 - side][BISHOP] | pieces[1 - side][QUEEN])) return 1;
if (knight_moves(sq) & pieces[1 - side][KNIGHT]) return 1;
int dir = (side == WHITE) ? 8 : -8;
int lcap = sq + dir - 1, rcap = sq + dir + 1;
if (lcap >= 0 && lcap < 64 && IS_SET(pieces[1 - side][PAWN], lcap)) return 1;
if (rcap >= 0 && rcap < 64 && IS_SET(pieces[1 - side][PAWN], rcap)) return 1;
return 0;
}
void make_move(Move m, int side) {
CLEAR_BIT(pieces[side][m.piece], m.from);
SET_BIT(pieces[side][m.piece], m.to);
if (m.promotion >= 0) {
CLEAR_BIT(pieces[side][PAWN], m.to);
SET_BIT(pieces[side][m.promotion], m.to);
}
if (m.is_en_passant) {
int cap_sq = (side == WHITE) ? m.to - 8 : m.to + 8;
CLEAR_BIT(pieces[1 - side][PAWN], cap_sq);
}
for (int pt = 0; pt < 6; pt++)
CLEAR_BIT(pieces[1 - side][pt], m.to);
if (m.piece == PAWN && abs(m.to - m.from) == 16)
en_passant_square = (m.from + m.to) / 2;
else
en_passant_square = -1;
side_to_move = 1 - side;
}
void undo_move(Move m, int side) {
side_to_move = side;
SET_BIT(pieces[side][m.piece], m.from);
CLEAR_BIT(pieces[side][m.piece], m.to);
if (m.promotion >= 0) {
CLEAR_BIT(pieces[side][m.promotion], m.to);
SET_BIT(pieces[side][PAWN], m.to);
}
if (m.is_en_passant) {
int cap_sq = (side == WHITE) ? m.to - 8 : m.to + 8;
SET_BIT(pieces[1 - side][PAWN], cap_sq);
}
// Ziel-Feld war besetzt? Re-Konstruieren ist Sache des Aufrufers oder TT
}
int is_legal(Move m, int side) {
make_move(m, side);
int legal = !king_in_check(side);
undo_move(m, side);
return legal;
}
// --- Bauernzüge ---
int generate_pawn_moves(Move *moves, int side) {
int count = 0;
Bitboard pawns = pieces[side][PAWN];
Bitboard own = 0;
for (int pt = 0; pt < 6; pt++) own |= pieces[side][pt];
int dir = (side == WHITE) ? 8 : -8;
int start_rank = (side == WHITE) ? 1 : 6;
int promote_rank = (side == WHITE) ? 6 : 1;
while (pawns) {
int from = __builtin_ctzll(pawns);
CLEAR_BIT(pawns, from);
int to = from + dir;
if (to >= 0 && to < 64 && !IS_SET(own, to)) {
if (from / 8 == promote_rank) {
moves[count++] = (Move){from, to, PAWN, QUEEN, 0};
} else {
moves[count++] = (Move){from, to, PAWN, -1, 0};
if (from / 8 == start_rank && !IS_SET(own, to + dir))
moves[count++] = (Move){from, to + dir, PAWN, -1, 0};
}
}
// Captures
for (int df = -1; df <= 1; df += 2) {
int t = from + dir + df;
if (t >= 0 && t < 64) {
for (int pt = 0; pt < 6; pt++) {
if (IS_SET(pieces[1 - side][pt], t)) {
moves[count++] = (Move){from, t, PAWN,
(from / 8 == promote_rank) ? QUEEN : -1, 0};
}
}
}
}
// En Passant
if (en_passant_square != -1) {
for (int df = -1; df <= 1; df += 2) {
int t = from + dir + df;
if (t == en_passant_square)
moves[count++] = (Move){from, t, PAWN, -1, 1};
}
}
}
return count;
}
// --- Zuggenerierung für alle Figuren inkl. Bauern ---
int generate_all_moves(Move *moves, int side) {
int count = generate_pawn_moves(moves, side);
Bitboard own = 0;
for (int pt = 0; pt < 6; pt++) own |= pieces[side][pt];
Bitboard all = own;
for (int pt = 0; pt < 6; pt++) all |= pieces[1 - side][pt];
// Springer
Bitboard b = pieces[side][KNIGHT];
while (b) {
int from = __builtin_ctzll(b); CLEAR_BIT(b, from);
Bitboard t = knight_moves(from) & ~own;
while (t) {
int to = __builtin_ctzll(t); CLEAR_BIT(t, to);
moves[count++] = (Move){from, to, KNIGHT, -1, 0};
}
}
// Läufer
b = pieces[side][BISHOP];
while (b) {
int from = __builtin_ctzll(b); CLEAR_BIT(b, from);
Bitboard t = bishop_attacks(from, all) & ~own;
while (t) {
int to = __builtin_ctzll(t); CLEAR_BIT(t, to);
moves[count++] = (Move){from, to, BISHOP, -1, 0};
}
}
// Turm
b = pieces[side][ROOK];
while (b) {
int from = __builtin_ctzll(b); CLEAR_BIT(b, from);
Bitboard t = rook_attacks(from, all) & ~own;
while (t) {
int to = __builtin_ctzll(t); CLEAR_BIT(t, to);
moves[count++] = (Move){from, to, ROOK, -1, 0};
}
}
// Dame
b = pieces[side][QUEEN];
while (b) {
int from = __builtin_ctzll(b); CLEAR_BIT(b, from);
Bitboard t = queen_attacks(from, all) & ~own;
while (t) {
int to = __builtin_ctzll(t); CLEAR_BIT(t, to);
moves[count++] = (Move){from, to, QUEEN, -1, 0};
}
}
// König
b = pieces[side][KING];
if (b) {
int from = __builtin_ctzll(b);
Bitboard t = king_moves(from) & ~own;
while (t) {
int to = __builtin_ctzll(t); CLEAR_BIT(t, to);
moves[count++] = (Move){from, to, KING, -1, 0};
}
}
return count;
}
// --- Quiescence Search ---
int quiescence(int alpha, int beta, int side) {
int stand_pat = evaluate_material();
if (stand_pat >= beta) return beta;
if (alpha < stand_pat) alpha = stand_pat;
Move moves[128];
int count = generate_all_moves(moves, side);
for (int i = 0; i < count; i++) {
if (!is_legal(moves, side)) continue;
int is_capture = 0;
for (int pt = 0; pt < 6; pt++) {
if (IS_SET(pieces[1 - side][pt], moves.to)) {
is_capture = 1;
break;
}
}
if (!is_capture) continue;
make_move(moves, side);
int score = -quiescence(-beta, -alpha, 1 - side);
undo_move(moves, side);
if (score >= beta) return beta;
if (score > alpha) alpha = score;
}
return alpha;
}
// --- Iterative Deepening + Suche ---
Move search_final(int max_depth) {
init_zobrist();
Move best = {0};
for (int d = 1; d <= max_depth; d++) {
Move moves[256]; int n = generate_all_moves(moves, side_to_move);
int best_score = INT_MIN;
sort_moves_heuristic(moves, n, 0);
for (int i = 0; i < n; i++) {
if (!is_legal(moves, side_to_move)) continue;
make_move(moves, side_to_move);
int s = -alphabeta_tt(d - 1, INT_MIN + 1, INT_MAX - 1, 1, 1 - side_to_move);
undo_move(moves, side_to_move);
if (s > best_score) {
best_score = s;
best = moves;
}
}
}
return best;
}
// --- UCI Schnittstelle ---
void square_to_uci(int sq, char *buf) {
buf[0] = 'a' + (sq % 8);
buf[1] = '1' + (sq / 8);
buf[2] = 0;
}
void uci_loop() {
char line[256];
while (fgets(line, sizeof(line), stdin)) {
if (strncmp(line, "uci", 3) == 0) {
printf("id name FinalBitboardEngine\n");
printf("id author Du\n");
printf("uciok\n");
} else if (strncmp(line, "isready", 7) == 0) {
printf("readyok\n");
} else if (strncmp(line, "position startpos", 17) == 0) {
set_startpos();
} else if (strncmp(line, "go", 2) == 0) {
Move best = search_final(5);
char from[3], to[3];
square_to_uci(best.from, from);
square_to_uci(best.to, to);
printf("bestmove %s%s\n", from, to);
} else if (strncmp(line, "quit", 4) == 0) {
break;
}
}
}