Delete mistake
This commit is contained in:
parent
628b9fcc42
commit
ca75fa6d61
28 changed files with 0 additions and 3744 deletions
7
ChessEngine/.gitignore
vendored
7
ChessEngine/.gitignore
vendored
|
|
@ -1,7 +0,0 @@
|
||||||
/target
|
|
||||||
/.idea
|
|
||||||
/src/replace.py
|
|
||||||
/scripts
|
|
||||||
/Cargo.lock
|
|
||||||
/src/benchmark/stockfish
|
|
||||||
uci_log.txt
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "chess_engine"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Moritz Eigenauer <moritz.eigenauer@gmail.com>"]
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# ChessEngine
|
|
||||||
My own UCI chess engine in Rust
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
def generate_king_attacks():
|
|
||||||
"""
|
|
||||||
Generates a list of 64 u64 bitboards, where each bitboard represents
|
|
||||||
the squares a king can attack from a given source square.
|
|
||||||
Uses Little-Endian File-Rank (LEFR) mapping: A1=0, H1=7, A2=8, ..., H8=63.
|
|
||||||
"""
|
|
||||||
all_attacks = []
|
|
||||||
|
|
||||||
# All 8 possible king move offsets (delta_file, delta_rank)
|
|
||||||
king_moves = [
|
|
||||||
(0, 1), (0, -1), (1, 0), (-1, 0), # Orthogonal
|
|
||||||
(1, 1), (1, -1), (-1, 1), (-1, -1) # Diagonal
|
|
||||||
]
|
|
||||||
|
|
||||||
for sq in range(64):
|
|
||||||
attacks_bb = 0
|
|
||||||
|
|
||||||
# Calculate rank and file for the source square
|
|
||||||
rank = sq // 8
|
|
||||||
file = sq % 8
|
|
||||||
|
|
||||||
for df, dr in king_moves:
|
|
||||||
target_rank = rank + dr
|
|
||||||
target_file = file + df
|
|
||||||
|
|
||||||
# Check if the target square is on the board
|
|
||||||
if 0 <= target_rank <= 7 and 0 <= target_file <= 7:
|
|
||||||
# Convert target rank and file back to a square index
|
|
||||||
target_sq = target_rank * 8 + target_file
|
|
||||||
# Set the corresponding bit in the bitboard
|
|
||||||
attacks_bb |= (1 << target_sq)
|
|
||||||
|
|
||||||
all_attacks.append(attacks_bb)
|
|
||||||
|
|
||||||
return all_attacks
|
|
||||||
|
|
||||||
def print_rust_array(attacks, const_name):
|
|
||||||
"""
|
|
||||||
Prints the list of attack bitboards as a Rust array.
|
|
||||||
"""
|
|
||||||
print(f"pub const {const_name}: [u64; 64] = [")
|
|
||||||
|
|
||||||
for i, attacks_bb in enumerate(attacks):
|
|
||||||
# Format as 64-bit zero-padded binary string
|
|
||||||
raw_binary_string = f"{attacks_bb:064b}"
|
|
||||||
|
|
||||||
# Insert underscores every 8 bits for readability
|
|
||||||
chunks = [raw_binary_string[i:i+8] for i in range(0, 64, 8)]
|
|
||||||
binary_string = f"0b{'_'.join(chunks)}"
|
|
||||||
|
|
||||||
# Correctly index the string 'ABCDEFGH'
|
|
||||||
print(f" {binary_string}, // Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})")
|
|
||||||
|
|
||||||
print("];")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
attacks = generate_king_attacks()
|
|
||||||
print_rust_array(attacks, "KING_ATTACKS")
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
def generate_knight_attacks():
|
|
||||||
"""
|
|
||||||
Generates a list of 64 u64 bitboards, where each bitboard represents
|
|
||||||
the squares a knight can attack from a given source square.
|
|
||||||
Uses Little-Endian File-Rank (LEFR) mapping: A1=0, H1=7, A2=8, ..., H8=63.
|
|
||||||
"""
|
|
||||||
all_attacks = []
|
|
||||||
|
|
||||||
# All 8 possible knight move offsets (delta_file, delta_rank)
|
|
||||||
knight_moves = [
|
|
||||||
(1, 2), (1, -2), (-1, 2), (-1, -2),
|
|
||||||
(2, 1), (2, -1), (-2, 1), (-2, -1)
|
|
||||||
]
|
|
||||||
|
|
||||||
for sq in range(64):
|
|
||||||
attacks_bb = 0
|
|
||||||
|
|
||||||
# Calculate rank and file for the source square
|
|
||||||
rank = sq // 8
|
|
||||||
file = sq % 8
|
|
||||||
|
|
||||||
for df, dr in knight_moves:
|
|
||||||
target_rank = rank + dr
|
|
||||||
target_file = file + df
|
|
||||||
|
|
||||||
# Check if the target square is on the board
|
|
||||||
if 0 <= target_rank <= 7 and 0 <= target_file <= 7:
|
|
||||||
# Convert target rank and file back to a square index
|
|
||||||
target_sq = target_rank * 8 + target_file
|
|
||||||
# Set the corresponding bit in the bitboard
|
|
||||||
attacks_bb |= (1 << target_sq)
|
|
||||||
|
|
||||||
all_attacks.append(attacks_bb)
|
|
||||||
|
|
||||||
return all_attacks
|
|
||||||
|
|
||||||
def print_rust_array(attacks):
|
|
||||||
"""
|
|
||||||
Prints the list of attack bitboards as a Rust array.
|
|
||||||
"""
|
|
||||||
print("pub const KNIGHT_ATTACKS: [u64; 64] = [")
|
|
||||||
|
|
||||||
for i, attacks_bb in enumerate(attacks):
|
|
||||||
# Format as 64-bit zero-padded binary string
|
|
||||||
raw_binary_string = f"{attacks_bb:064b}"
|
|
||||||
|
|
||||||
# Insert underscores every 8 bits for readability
|
|
||||||
chunks = [raw_binary_string[i:i+8] for i in range(0, 64, 8)]
|
|
||||||
binary_string = f"0b{'_'.join(chunks)}"
|
|
||||||
|
|
||||||
# Correctly index the string 'ABCDEFGH'
|
|
||||||
print(f" {binary_string}, // Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})")
|
|
||||||
|
|
||||||
print("];")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
attacks = generate_knight_attacks()
|
|
||||||
print_rust_array(attacks)
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
def generate_pawn_attacks():
|
|
||||||
"""
|
|
||||||
Generates a list of 64 u64 bitboards for each color (White, Black),
|
|
||||||
where each bitboard represents the squares a pawn can attack from
|
|
||||||
a given source square.
|
|
||||||
Uses Little-Endian File-Rank (LEFR) mapping: A1=0, H1=7, A2=8, ..., H8=63.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
[[u64; 64]; 2] (represented as a list of two lists)
|
|
||||||
Index 0: White attacks
|
|
||||||
Index 1: Black attacks
|
|
||||||
"""
|
|
||||||
|
|
||||||
# all_attacks[0] = White, all_attacks[1] = Black
|
|
||||||
all_attacks = [[], []]
|
|
||||||
|
|
||||||
for sq in range(64):
|
|
||||||
rank = sq // 8
|
|
||||||
file = sq % 8
|
|
||||||
|
|
||||||
white_attacks_bb = 0
|
|
||||||
black_attacks_bb = 0
|
|
||||||
|
|
||||||
# --- White Attacks (Index 0) ---
|
|
||||||
# Pawns attack "up" the board (increasing square index)
|
|
||||||
# We only generate attacks if the pawn is not on the 8th rank
|
|
||||||
if rank < 7:
|
|
||||||
# Attack Up-Left (e.g., B2 -> A3)
|
|
||||||
# Not possible if pawn is on the A-file
|
|
||||||
if file > 0:
|
|
||||||
white_attacks_bb |= (1 << (sq + 7))
|
|
||||||
|
|
||||||
# Attack Up-Right (e.g., B2 -> C3)
|
|
||||||
# Not possible if pawn is on the H-file
|
|
||||||
if file < 7:
|
|
||||||
white_attacks_bb |= (1 << (sq + 9))
|
|
||||||
|
|
||||||
# --- Black Attacks (Index 1) ---
|
|
||||||
# Pawns attack "down" the board (decreasing square index)
|
|
||||||
# We only generate attacks if the pawn is not on the 1st rank
|
|
||||||
if rank > 0:
|
|
||||||
# Attack Down-Left (e.g., G7 -> F6)
|
|
||||||
# Not possible if pawn is on the A-file
|
|
||||||
if file > 0:
|
|
||||||
black_attacks_bb |= (1 << (sq - 9))
|
|
||||||
|
|
||||||
# Attack Down-Right (e.g., G7 -> H6)
|
|
||||||
# Not possible if pawn is on the H-file
|
|
||||||
if file < 7:
|
|
||||||
black_attacks_bb |= (1 << (sq - 7))
|
|
||||||
|
|
||||||
all_attacks[0].append(white_attacks_bb)
|
|
||||||
all_attacks[1].append(black_attacks_bb)
|
|
||||||
|
|
||||||
return all_attacks
|
|
||||||
|
|
||||||
def print_rust_array(attacks_by_color, const_name):
|
|
||||||
"""
|
|
||||||
Prints the list of attack bitboards as a nested Rust array.
|
|
||||||
"""
|
|
||||||
print(f"pub const {const_name}: [[u64; 64]; 2] = [")
|
|
||||||
|
|
||||||
# --- Print White Attacks ---
|
|
||||||
print(" [ // Color 0: White")
|
|
||||||
for i, attacks_bb in enumerate(attacks_by_color[0]):
|
|
||||||
raw_binary_string = f"{attacks_bb:064b}"
|
|
||||||
chunks = [raw_binary_string[i:i+8] for i in range(0, 64, 8)]
|
|
||||||
binary_string = f"0b{'_'.join(chunks)}"
|
|
||||||
print(f" {binary_string}, // Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})")
|
|
||||||
print(" ],")
|
|
||||||
|
|
||||||
# --- Print Black Attacks ---
|
|
||||||
print(" [ // Color 1: Black")
|
|
||||||
for i, attacks_bb in enumerate(attacks_by_color[1]):
|
|
||||||
raw_binary_string = f"{attacks_bb:064b}"
|
|
||||||
chunks = [raw_binary_string[i:i+8] for i in range(0, 64, 8)]
|
|
||||||
binary_string = f"0b{'_'.join(chunks)}"
|
|
||||||
print(f" {binary_string}, // Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})")
|
|
||||||
print(" ]")
|
|
||||||
|
|
||||||
print("];")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
attacks = generate_pawn_attacks()
|
|
||||||
print_rust_array(attacks, "PAWN_ATTACKS")
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
def generate_premasks():
|
|
||||||
"""
|
|
||||||
Generiert relevante Belegungsmasken (relevant occupancy masks) für
|
|
||||||
Türme (Rooks) und Läufer (Bishops) auf allen 64 Feldern.
|
|
||||||
|
|
||||||
Diese Masken enthalten alle Felder zwischen der Figur und dem Rand,
|
|
||||||
ABER AUSSCHLIESSLICH der Randfelder selbst.
|
|
||||||
"""
|
|
||||||
all_rook_masks = []
|
|
||||||
all_bishop_masks = []
|
|
||||||
|
|
||||||
# Richtungen für beide Figurentypen
|
|
||||||
rook_directions = [
|
|
||||||
(1, 0), # Hoch
|
|
||||||
(-1, 0), # Runter
|
|
||||||
(0, 1), # Rechts
|
|
||||||
(0, -1) # Links
|
|
||||||
]
|
|
||||||
bishop_directions = [
|
|
||||||
(1, 1), # Hoch-Rechts
|
|
||||||
(1, -1), # Hoch-Links
|
|
||||||
(-1, 1), # Runter-Rechts
|
|
||||||
(-1, -1) # Runter-Links
|
|
||||||
]
|
|
||||||
|
|
||||||
for sq in range(64):
|
|
||||||
rook_mask_bb = 0
|
|
||||||
bishop_mask_bb = 0
|
|
||||||
|
|
||||||
rank = sq // 8
|
|
||||||
file = sq % 8
|
|
||||||
|
|
||||||
# --- 1. Turm (Rook) Masken-Generierung ---
|
|
||||||
# (Dies ist die korrigierte Logik)
|
|
||||||
for dr, df in rook_directions:
|
|
||||||
target_rank = rank + dr
|
|
||||||
target_file = file + df
|
|
||||||
|
|
||||||
# Schleife, solange wir auf dem Brett sind (0-7)
|
|
||||||
while 0 <= target_rank <= 7 and 0 <= target_file <= 7:
|
|
||||||
is_relevant = False
|
|
||||||
|
|
||||||
# Prüfen, ob das Feld *vor* dem Rand liegt.
|
|
||||||
if df != 0: # Horizontale Bewegung
|
|
||||||
if 1 <= target_file <= 6: # Files 'b' bis 'g'
|
|
||||||
is_relevant = True
|
|
||||||
elif dr != 0: # Vertikale Bewegung
|
|
||||||
if 1 <= target_rank <= 6: # Ranks 2 bis 7
|
|
||||||
is_relevant = True
|
|
||||||
|
|
||||||
if is_relevant:
|
|
||||||
target_sq = target_rank * 8 + target_file
|
|
||||||
rook_mask_bb |= (1 << target_sq)
|
|
||||||
|
|
||||||
# Zum nächsten Feld in dieser Richtung
|
|
||||||
target_rank += dr
|
|
||||||
target_file += df
|
|
||||||
|
|
||||||
all_rook_masks.append(rook_mask_bb)
|
|
||||||
|
|
||||||
# --- 2. Läufer (Bishop) Masken-Generierung ---
|
|
||||||
# (Diese Logik war in deinem "Rook"-Skript und ist hier korrekt)
|
|
||||||
for dr, df in bishop_directions:
|
|
||||||
target_rank = rank + dr
|
|
||||||
target_file = file + df
|
|
||||||
|
|
||||||
# Schleife, solange wir *von allen* Rändern entfernt sind (1-6)
|
|
||||||
while 1 <= target_rank <= 6 and 1 <= target_file <= 6:
|
|
||||||
target_sq = target_rank * 8 + target_file
|
|
||||||
bishop_mask_bb |= (1 << target_sq)
|
|
||||||
|
|
||||||
# Zum nächsten Feld in dieser Richtung
|
|
||||||
target_rank += dr
|
|
||||||
target_file += df
|
|
||||||
|
|
||||||
all_bishop_masks.append(bishop_mask_bb)
|
|
||||||
|
|
||||||
# Gibt beide Listen als Tupel zurück
|
|
||||||
return all_rook_masks, all_bishop_masks
|
|
||||||
|
|
||||||
def print_rust_array(attacks, const_name):
|
|
||||||
"""
|
|
||||||
Gibt die Liste der Bitboards als Rust-Array aus.
|
|
||||||
"""
|
|
||||||
print(f"pub const {const_name}: [u64; 64] = [")
|
|
||||||
|
|
||||||
for i, attacks_bb in enumerate(attacks):
|
|
||||||
# Formatieren als 64-Bit binärer String mit Nullen
|
|
||||||
raw_binary_string = f"{attacks_bb:064b}"
|
|
||||||
|
|
||||||
# Unterstriche alle 8 Bits zur Lesbarkeit einfügen
|
|
||||||
chunks = [raw_binary_string[j:j+8] for j in range(0, 64, 8)]
|
|
||||||
binary_string = f"0b{'_'.join(chunks)}"
|
|
||||||
|
|
||||||
# Index 'ABCDEFGH' korrekt zuordnen
|
|
||||||
print(f" {binary_string}, // Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})")
|
|
||||||
|
|
||||||
print("];")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Entpackt das Tupel mit beiden Masken-Listen
|
|
||||||
rook_masks, bishop_masks = generate_premasks()
|
|
||||||
|
|
||||||
print("--- ROOK MASKS ---")
|
|
||||||
print_rust_array(rook_masks, "ROOK_RELEVANT_OCCUPANCY")
|
|
||||||
|
|
||||||
print("\n--- BISHOP MASKS ---")
|
|
||||||
print_rust_array(bishop_masks, "BISHOP_RELEVANT_OCCUPANCY")
|
|
||||||
|
|
@ -1,197 +0,0 @@
|
||||||
import tkinter as tk
|
|
||||||
|
|
||||||
class ChessBitboardApp:
|
|
||||||
def __init__(self, root):
|
|
||||||
self.root = root
|
|
||||||
self.root.title("Chess Bitboard Generator")
|
|
||||||
|
|
||||||
# The bitboard, stored as a 64-bit integer
|
|
||||||
self.bitboard = 0
|
|
||||||
|
|
||||||
# A dictionary to keep track of squares and their marked state
|
|
||||||
# Key: (row, col), Value: {
|
|
||||||
# 'widget': tk.Frame, 'label_alg': tk.Label, 'label_idx': tk.Label,
|
|
||||||
# 'marked': bool, 'original_color': str
|
|
||||||
# }
|
|
||||||
self.squares = {}
|
|
||||||
|
|
||||||
# --- Create the GUI ---
|
|
||||||
|
|
||||||
# Frame for the chessboard
|
|
||||||
board_frame = tk.Frame(root)
|
|
||||||
board_frame.pack()
|
|
||||||
|
|
||||||
# Create the 8x8 grid of squares
|
|
||||||
# We loop from row 7 (rank 8) down to 0 (rank 1) for visual layout
|
|
||||||
for r in range(7, -1, -1): # 7, 6, 5, ... 0
|
|
||||||
for c in range(8): # 0, 1, 2, ... 7
|
|
||||||
|
|
||||||
# Determine the square's original color
|
|
||||||
is_light_square = (r + c) % 2 == 1
|
|
||||||
original_color = "#F0D9B5" if is_light_square else "#B58863"
|
|
||||||
|
|
||||||
# Create the square as a Frame
|
|
||||||
square = tk.Frame(
|
|
||||||
board_frame,
|
|
||||||
width=50,
|
|
||||||
height=50,
|
|
||||||
bg=original_color,
|
|
||||||
relief="sunken",
|
|
||||||
borderwidth=1
|
|
||||||
)
|
|
||||||
# Make frame *not* resize to labels
|
|
||||||
square.pack_propagate(False) # Use pack_propagate since we use place/pack inside
|
|
||||||
square.grid(row=7 - r, column=c)
|
|
||||||
|
|
||||||
# --- Add labels to the square (Feature 2) ---
|
|
||||||
algebraic_not = f"{'abcdefgh'[c]}{r + 1}"
|
|
||||||
bit_index = r * 8 + c
|
|
||||||
|
|
||||||
label_alg = tk.Label(square, text=algebraic_not, bg=original_color, font=("Arial", 8, "bold"))
|
|
||||||
label_alg.place(x=2, y=1) # Use place to position label
|
|
||||||
|
|
||||||
label_idx = tk.Label(square, text=f"{bit_index}", bg=original_color, font=("Arial", 8))
|
|
||||||
label_idx.place(relx=1.0, rely=1.0, anchor='se', x=-2, y=-1) # Use place for bottom-right
|
|
||||||
|
|
||||||
# Bind the click event to all parts of the square
|
|
||||||
click_lambda = lambda event, row=r, col=c: self.on_square_click(event, row, col)
|
|
||||||
square.bind("<Button-1>", click_lambda)
|
|
||||||
label_alg.bind("<Button-1>", click_lambda)
|
|
||||||
label_idx.bind("<Button-1>", click_lambda)
|
|
||||||
|
|
||||||
# Store the square's info
|
|
||||||
self.squares[(r, c)] = {
|
|
||||||
'widget': square,
|
|
||||||
'label_alg': label_alg,
|
|
||||||
'label_idx': label_idx,
|
|
||||||
'marked': False,
|
|
||||||
'original_color': original_color
|
|
||||||
}
|
|
||||||
|
|
||||||
# Frame for the bitboard display
|
|
||||||
info_frame = tk.Frame(root, pady=10)
|
|
||||||
info_frame.pack()
|
|
||||||
|
|
||||||
# --- Make display labels copyable (Feature 1) ---
|
|
||||||
self.binary_var = tk.StringVar()
|
|
||||||
self.int_var = tk.StringVar()
|
|
||||||
|
|
||||||
tk.Label(info_frame, text="Binary:").pack()
|
|
||||||
self.binary_label = tk.Entry(
|
|
||||||
info_frame,
|
|
||||||
textvariable=self.binary_var,
|
|
||||||
state="readonly",
|
|
||||||
font=("Courier", 10),
|
|
||||||
width=77 # 64 chars + 15 underscores + 'b'
|
|
||||||
)
|
|
||||||
self.binary_label.pack()
|
|
||||||
|
|
||||||
tk.Label(info_frame, text="Integer:").pack()
|
|
||||||
self.int_label = tk.Entry(
|
|
||||||
info_frame,
|
|
||||||
textvariable=self.int_var,
|
|
||||||
state="readonly",
|
|
||||||
font=("Courier", 12, "bold"),
|
|
||||||
width=22
|
|
||||||
)
|
|
||||||
self.int_label.pack()
|
|
||||||
|
|
||||||
# --- Add Entry for pasting bitboard (Feature 3) ---
|
|
||||||
input_frame = tk.Frame(root, pady=5)
|
|
||||||
input_frame.pack()
|
|
||||||
|
|
||||||
tk.Label(input_frame, text="Paste Bitboard (int) and Press Enter:").pack(side=tk.LEFT)
|
|
||||||
self.paste_entry = tk.Entry(input_frame, font=("Courier", 12), width=22)
|
|
||||||
self.paste_entry.pack(side=tk.LEFT, padx=5)
|
|
||||||
self.paste_entry.bind("<Return>", self.on_paste_bitboard)
|
|
||||||
|
|
||||||
# Initialize display
|
|
||||||
self.update_display()
|
|
||||||
|
|
||||||
def on_square_click(self, event, row, col):
|
|
||||||
"""Handles the click event for a square."""
|
|
||||||
square_info = self.squares[(row, col)]
|
|
||||||
|
|
||||||
# Toggle the marked state
|
|
||||||
square_info['marked'] = not square_info['marked']
|
|
||||||
|
|
||||||
self.update_square_visuals(row, col)
|
|
||||||
|
|
||||||
# Recalculate the bitboard and update the display
|
|
||||||
self.recalculate_bitboard()
|
|
||||||
self.update_display()
|
|
||||||
|
|
||||||
def update_square_visuals(self, row, col):
|
|
||||||
"""Updates a single square's color based on its 'marked' state."""
|
|
||||||
square_info = self.squares[(row, col)]
|
|
||||||
|
|
||||||
is_marked = square_info['marked']
|
|
||||||
new_color = "#50C878" if is_marked else square_info['original_color']
|
|
||||||
label_fg_color = "white" if is_marked else "black" # Make text white on green
|
|
||||||
|
|
||||||
square_info['widget'].config(bg=new_color)
|
|
||||||
square_info['label_alg'].config(bg=new_color, fg=label_fg_color)
|
|
||||||
square_info['label_idx'].config(bg=new_color, fg=label_fg_color)
|
|
||||||
|
|
||||||
def recalculate_bitboard(self):
|
|
||||||
"""Recalculates the 64-bit integer from the marked squares."""
|
|
||||||
self.bitboard = 0
|
|
||||||
|
|
||||||
for r in range(8):
|
|
||||||
for c in range(8):
|
|
||||||
if self.squares[(r, c)]['marked']:
|
|
||||||
bit_index = r * 8 + c
|
|
||||||
self.bitboard |= (1 << bit_index)
|
|
||||||
|
|
||||||
def update_display(self):
|
|
||||||
"""Updates the binary and integer labels."""
|
|
||||||
|
|
||||||
# Update the integer label
|
|
||||||
self.int_var.set(f"{self.bitboard}")
|
|
||||||
|
|
||||||
# Update the binary label
|
|
||||||
binary_string = f"{self.bitboard:064b}"
|
|
||||||
formatted_binary = "b" + "_".join(binary_string[i:i+8] for i in range(0, 64, 4))
|
|
||||||
self.binary_var.set(f"{formatted_binary}")
|
|
||||||
|
|
||||||
def on_paste_bitboard(self, event):
|
|
||||||
"""Handles the 'Enter' key press in the paste entry box."""
|
|
||||||
try:
|
|
||||||
# Get text from entry and convert to integer
|
|
||||||
new_bitboard = int(self.paste_entry.get())
|
|
||||||
if 0 <= new_bitboard <= (1 << 64) - 1:
|
|
||||||
self.bitboard = new_bitboard
|
|
||||||
# Update the board visuals from the new bitboard
|
|
||||||
self.update_board_from_bitboard()
|
|
||||||
# Update the display labels
|
|
||||||
self.update_display()
|
|
||||||
else:
|
|
||||||
# Handle out-of-range numbers
|
|
||||||
self.paste_entry.delete(0, tk.END)
|
|
||||||
self.paste_entry.insert(0, "Out of 64-bit range")
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
# Handle non-integer input
|
|
||||||
self.paste_entry.delete(0, tk.END)
|
|
||||||
self.paste_entry.insert(0, "Invalid Integer")
|
|
||||||
|
|
||||||
def update_board_from_bitboard(self):
|
|
||||||
"""Updates the visual state of all squares based on self.bitboard."""
|
|
||||||
for r in range(8):
|
|
||||||
for c in range(8):
|
|
||||||
bit_index = r * 8 + c
|
|
||||||
square_info = self.squares[(r, c)]
|
|
||||||
|
|
||||||
# Check if the bit at bit_index is set
|
|
||||||
if (self.bitboard >> bit_index) & 1:
|
|
||||||
square_info['marked'] = True
|
|
||||||
else:
|
|
||||||
square_info['marked'] = False
|
|
||||||
|
|
||||||
# Update the square's color
|
|
||||||
self.update_square_visuals(r, c)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
root = tk.Tk()
|
|
||||||
app = ChessBitboardApp(root)
|
|
||||||
root.mainloop()
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
a = """
|
|
||||||
[
|
|
||||||
0x8a80104000800020,
|
|
||||||
0x140002000100040,
|
|
||||||
0x2801880a0017001,
|
|
||||||
0x100081001000420,
|
|
||||||
0x200020010080420,
|
|
||||||
0x3001c0002010008,
|
|
||||||
0x8480008002000100,
|
|
||||||
0x2080088004402900,
|
|
||||||
0x800098204000,
|
|
||||||
0x2024401000200040,
|
|
||||||
0x100802000801000,
|
|
||||||
0x120800800801000,
|
|
||||||
0x208808088000400,
|
|
||||||
0x2802200800400,
|
|
||||||
0x2200800100020080,
|
|
||||||
0x801000060821100,
|
|
||||||
0x80044006422000,
|
|
||||||
0x100808020004000,
|
|
||||||
0x12108a0010204200,
|
|
||||||
0x140848010000802,
|
|
||||||
0x481828014002800,
|
|
||||||
0x8094004002004100,
|
|
||||||
0x4010040010010802,
|
|
||||||
0x20008806104,
|
|
||||||
0x100400080208000,
|
|
||||||
0x2040002120081000,
|
|
||||||
0x21200680100081,
|
|
||||||
0x20100080080080,
|
|
||||||
0x2000a00200410,
|
|
||||||
0x20080800400,
|
|
||||||
0x80088400100102,
|
|
||||||
0x80004600042881,
|
|
||||||
0x4040008040800020,
|
|
||||||
0x440003000200801,
|
|
||||||
0x4200011004500,
|
|
||||||
0x188020010100100,
|
|
||||||
0x14800401802800,
|
|
||||||
0x2080040080800200,
|
|
||||||
0x124080204001001,
|
|
||||||
0x200046502000484,
|
|
||||||
0x480400080088020,
|
|
||||||
0x1000422010034000,
|
|
||||||
0x30200100110040,
|
|
||||||
0x100021010009,
|
|
||||||
0x2002080100110004,
|
|
||||||
0x202008004008002,
|
|
||||||
0x20020004010100,
|
|
||||||
0x2048440040820001,
|
|
||||||
0x101002200408200,
|
|
||||||
0x40802000401080,
|
|
||||||
0x4008142004410100,
|
|
||||||
0x2060820c0120200,
|
|
||||||
0x1001004080100,
|
|
||||||
0x20c020080040080,
|
|
||||||
0x2935610830022400,
|
|
||||||
0x44440041009200,
|
|
||||||
0x280001040802101,
|
|
||||||
0x2100190040002085,
|
|
||||||
0x80c0084100102001,
|
|
||||||
0x4024081001000421,
|
|
||||||
0x20030a0244872,
|
|
||||||
0x12001008414402,
|
|
||||||
0x2006104900a0804,
|
|
||||||
0x1004081002402,
|
|
||||||
]
|
|
||||||
""".replace("[", "").replace("]", "").replace(",", "").strip().split("\n")
|
|
||||||
a = [int(x, 16) for x in a]
|
|
||||||
|
|
||||||
b = """
|
|
||||||
[
|
|
||||||
0x8a80104000800020,
|
|
||||||
0x140002000100040,
|
|
||||||
0x2801880a0017001,
|
|
||||||
0x100081001000420,
|
|
||||||
0x200020010080420,
|
|
||||||
0x3001c0002010008,
|
|
||||||
0x8480008002000100,
|
|
||||||
0x2080088004402900,
|
|
||||||
0x800098204000,
|
|
||||||
0x2024401000200040,
|
|
||||||
0x100802000801000,
|
|
||||||
0x120800800801000,
|
|
||||||
0x208808088000400,
|
|
||||||
0x2802200800400,
|
|
||||||
0x2200800100020080,
|
|
||||||
0x801000060821100,
|
|
||||||
0x80044006422000,
|
|
||||||
0x100808020004000,
|
|
||||||
0x12108a0010204200,
|
|
||||||
0x140848010000802,
|
|
||||||
0x481828014002800,
|
|
||||||
0x8094004002004100,
|
|
||||||
0x4010040010010802,
|
|
||||||
0x20008806104,
|
|
||||||
0x100400080208000,
|
|
||||||
0x2040002120081000,
|
|
||||||
0x21200680100081,
|
|
||||||
0x20100080080080,
|
|
||||||
0x2000a00200410,
|
|
||||||
0x20080800400,
|
|
||||||
0x80088400100102,
|
|
||||||
0x80004600042881,
|
|
||||||
0x4040008040800020,
|
|
||||||
0x440003000200801,
|
|
||||||
0x4200011004500,
|
|
||||||
0x188020010100100,
|
|
||||||
0x14800401802800,
|
|
||||||
0x2080040080800200,
|
|
||||||
0x124080204001001,
|
|
||||||
0x200046502000484,
|
|
||||||
0x480400080088020,
|
|
||||||
0x1000422010034000,
|
|
||||||
0x30200100110040,
|
|
||||||
0x100021010009,
|
|
||||||
0x2002080100110004,
|
|
||||||
0x202008004008002,
|
|
||||||
0x20020004010100,
|
|
||||||
0x2048440040820001,
|
|
||||||
0x101002200408200,
|
|
||||||
0x40802000401080,
|
|
||||||
0x4008142004410100,
|
|
||||||
0x2060820c0120200,
|
|
||||||
0x1001004080100,
|
|
||||||
0x20c020080040080,
|
|
||||||
0x2935610830022400,
|
|
||||||
0x44440041009200,
|
|
||||||
0x280001040802101,
|
|
||||||
0x2100190040002085,
|
|
||||||
0x80c0084100102001,
|
|
||||||
0x4024081001000421,
|
|
||||||
0x20030a0244872,
|
|
||||||
0x12001008414402,
|
|
||||||
0x2006104900a0804,
|
|
||||||
0x1004081002402,
|
|
||||||
]
|
|
||||||
""".replace("[", "").replace("]", "").replace(",", "").strip().split("\n")
|
|
||||||
b = [int(x, 16) for x in b]
|
|
||||||
|
|
||||||
def format_rust_array(data_list, array_name="GeneratedArray"):
|
|
||||||
"""
|
|
||||||
Converts a list of integers/hex into a formatted Rust array
|
|
||||||
with binary representation and chess square comments.
|
|
||||||
"""
|
|
||||||
print(f"pub const {array_name}: [u64; {len(data_list)}] = [")
|
|
||||||
|
|
||||||
files = "ABCDEFGH"
|
|
||||||
|
|
||||||
for i, val in enumerate(data_list):
|
|
||||||
# 1. Convert to 64-bit binary string (MSB on left)
|
|
||||||
bin_str = f"{val:064b}"
|
|
||||||
|
|
||||||
# 2. Insert underscores every 8 bits for readability
|
|
||||||
# Range 0 to 64 with step 8
|
|
||||||
chunks = [bin_str[j:j+8] for j in range(0, 64, 8)]
|
|
||||||
formatted_bin = "_".join(chunks)
|
|
||||||
|
|
||||||
# 3. Calculate Square and Algebraic Notation for the comment
|
|
||||||
# Assuming standard Little-Endian Rank-File mapping (A1=0, B1=1 ... H8=63)
|
|
||||||
file_idx = i % 8
|
|
||||||
rank_idx = i // 8
|
|
||||||
|
|
||||||
if rank_idx < 8:
|
|
||||||
algebraic = f"{files[file_idx]}{rank_idx + 1}"
|
|
||||||
else:
|
|
||||||
algebraic = "N/A" # Handle lists larger than 64 items gracefully
|
|
||||||
|
|
||||||
# 4. Print the formatted line
|
|
||||||
print(f" 0b{formatted_bin}, // Square {i} ({algebraic})")
|
|
||||||
|
|
||||||
print("];")
|
|
||||||
|
|
||||||
# --- OPTION 1: Convert your specific hex list ---
|
|
||||||
my_hex_list = [
|
|
||||||
0x8a80104000800020,
|
|
||||||
0x140002000100040
|
|
||||||
]
|
|
||||||
|
|
||||||
# --- OPTION 2: Generate the actual King Attacks (to match your example) ---
|
|
||||||
def generate_king_attacks():
|
|
||||||
king_moves = []
|
|
||||||
for square in range(64):
|
|
||||||
attacks = 0
|
|
||||||
file = square % 8
|
|
||||||
rank = square // 8
|
|
||||||
|
|
||||||
# Iterate over all 8 neighbors
|
|
||||||
for d_file in [-1, 0, 1]:
|
|
||||||
for d_rank in [-1, 0, 1]:
|
|
||||||
if d_file == 0 and d_rank == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
target_file = file + d_file
|
|
||||||
target_rank = rank + d_rank
|
|
||||||
|
|
||||||
if 0 <= target_file < 8 and 0 <= target_rank < 8:
|
|
||||||
target_square = target_rank * 8 + target_file
|
|
||||||
attacks |= (1 << target_square)
|
|
||||||
king_moves.append(attacks)
|
|
||||||
return king_moves
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
format_rust_array(a, "MAGICS_ROOK")
|
|
||||||
format_rust_array(b, "MAGICS_BISHOP")
|
|
||||||
|
|
@ -1,487 +0,0 @@
|
||||||
<<<<<<< HEAD
|
|
||||||
use crate::square::Square;
|
|
||||||
use std::mem;
|
|
||||||
use crate::r#move::*;
|
|
||||||
use std::ops::Not;
|
|
||||||
|
|
||||||
pub const CASTLING_WK: u8 = 1;
|
|
||||||
pub const CASTLING_WK_MASK: u64 = 96; // F1 G1
|
|
||||||
|
|
||||||
pub const CASTLING_WQ: u8 = 2;
|
|
||||||
pub const CASTLING_WQ_MASK: u64 = 14; // B1 C1 D1
|
|
||||||
|
|
||||||
pub const CASTLING_BK: u8 = 4;
|
|
||||||
pub const CASTLING_BK_MASK: u64 = 6917529027641081856; // F8 G8
|
|
||||||
|
|
||||||
pub const CASTLING_BQ: u8 = 8;
|
|
||||||
pub const CASTLING_BQ_MASK: u64 = 1008806316530991104; // B8 C8 D8
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum Color {
|
|
||||||
White = 0,
|
|
||||||
Black = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Not for Color {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn not(self) -> Self::Output {
|
|
||||||
match self {
|
|
||||||
Color::White => Color::Black,
|
|
||||||
Color::Black => Color::White,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum PieceType {
|
|
||||||
Pawn = 0,
|
|
||||||
Knight = 1,
|
|
||||||
Bishop = 2,
|
|
||||||
Rook = 3,
|
|
||||||
Queen = 4,
|
|
||||||
King = 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Board {
|
|
||||||
pub side_to_move: Color,
|
|
||||||
|
|
||||||
pub pieces: [[u64; 2]; 6],
|
|
||||||
|
|
||||||
=======
|
|
||||||
use crate::color::Color;
|
|
||||||
use crate::square::Square;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
pub const CASTLING_W_KING: u8 = 1;
|
|
||||||
pub const CASTLING_W_KING_MASK: u64 = 96; // F1 G1
|
|
||||||
|
|
||||||
pub const CASTLING_W_QUEEN: u8 = 2;
|
|
||||||
pub const CASTLING_W_QUEEN_MASK: u64 = 14; // B1 C1 D1
|
|
||||||
|
|
||||||
pub const CASTLING_B_KING: u8 = 4;
|
|
||||||
pub const CASTLING_B_KING_MASK: u64 = 6917529027641081856; // F8 G8
|
|
||||||
|
|
||||||
pub const CASTLING_B_QUEEN: u8 = 8;
|
|
||||||
pub const CASTLING_B_QUEEN_MASK: u64 = 1008806316530991104; // B8 C8 D8
|
|
||||||
|
|
||||||
pub struct Board {
|
|
||||||
pub color: Color,
|
|
||||||
|
|
||||||
pub pawns: [u64; 2],
|
|
||||||
pub knights: [u64; 2],
|
|
||||||
pub bishops: [u64; 2],
|
|
||||||
pub rooks: [u64; 2],
|
|
||||||
pub queens: [u64; 2],
|
|
||||||
pub kings: [u64; 2],
|
|
||||||
|
|
||||||
// Replaced 'withes' and 'blacks' with 'occupied' array
|
|
||||||
>>>>>>> origin/master
|
|
||||||
pub occupied: [u64; 2],
|
|
||||||
pub all_occupied: u64,
|
|
||||||
pub empty_squares: u64,
|
|
||||||
|
|
||||||
pub castling_rights: u8,
|
|
||||||
pub en_passant_target: Option<Square>,
|
|
||||||
|
|
||||||
pub halfmove_clock: u8,
|
|
||||||
pub fullmove_number: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Board {
|
|
||||||
/// Creates a new Board instance from a FEN string.
|
|
||||||
/// Assumes the FEN string is valid.
|
|
||||||
pub fn from_fen(fen: &str) -> Self {
|
|
||||||
let mut parts = fen.split_whitespace();
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
// Initialisiere das 2D-Array
|
|
||||||
let mut pieces = [[0u64; 2]; 6];
|
|
||||||
=======
|
|
||||||
let mut pawns = [0u64; 2];
|
|
||||||
let mut knights = [0u64; 2];
|
|
||||||
let mut bishops = [0u64; 2];
|
|
||||||
let mut rooks = [0u64; 2];
|
|
||||||
let mut queens = [0u64; 2];
|
|
||||||
let mut kings = [0u64; 2];
|
|
||||||
|
|
||||||
// Changed from 'withes' and 'blacks'
|
|
||||||
>>>>>>> origin/master
|
|
||||||
let mut occupied = [0u64; 2];
|
|
||||||
|
|
||||||
// Part 1: Piece placement
|
|
||||||
let placement = parts.next().unwrap_or("");
|
|
||||||
let mut rank = 7;
|
|
||||||
let mut file = 0;
|
|
||||||
|
|
||||||
for c in placement.chars() {
|
|
||||||
if c.is_digit(10) {
|
|
||||||
file += c.to_digit(10).unwrap_or(0) as usize;
|
|
||||||
} else if c == '/' {
|
|
||||||
rank -= 1;
|
|
||||||
file = 0;
|
|
||||||
} else if c.is_alphabetic() {
|
|
||||||
let sq = (rank * 8 + file) as u8;
|
|
||||||
let mask = 1u64 << sq;
|
|
||||||
|
|
||||||
if c.is_uppercase() {
|
|
||||||
let color_idx = Color::White as usize;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
occupied[color_idx] |= mask;
|
|
||||||
match c {
|
|
||||||
'P' => pieces[PieceType::Pawn as usize][color_idx] |= mask,
|
|
||||||
'N' => pieces[PieceType::Knight as usize][color_idx] |= mask,
|
|
||||||
'B' => pieces[PieceType::Bishop as usize][color_idx] |= mask,
|
|
||||||
'R' => pieces[PieceType::Rook as usize][color_idx] |= mask,
|
|
||||||
'Q' => pieces[PieceType::Queen as usize][color_idx] |= mask,
|
|
||||||
'K' => pieces[PieceType::King as usize][color_idx] |= mask,
|
|
||||||
=======
|
|
||||||
occupied[color_idx] |= mask; // Changed
|
|
||||||
match c {
|
|
||||||
'P' => pawns[color_idx] |= mask,
|
|
||||||
'N' => knights[color_idx] |= mask,
|
|
||||||
'B' => bishops[color_idx] |= mask,
|
|
||||||
'R' => rooks[color_idx] |= mask,
|
|
||||||
'Q' => queens[color_idx] |= mask,
|
|
||||||
'K' => kings[color_idx] |= mask,
|
|
||||||
>>>>>>> origin/master
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let color_idx = Color::Black as usize;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
occupied[color_idx] |= mask;
|
|
||||||
match c {
|
|
||||||
'p' => pieces[PieceType::Pawn as usize][color_idx] |= mask,
|
|
||||||
'n' => pieces[PieceType::Knight as usize][color_idx] |= mask,
|
|
||||||
'b' => pieces[PieceType::Bishop as usize][color_idx] |= mask,
|
|
||||||
'r' => pieces[PieceType::Rook as usize][color_idx] |= mask,
|
|
||||||
'q' => pieces[PieceType::Queen as usize][color_idx] |= mask,
|
|
||||||
'k' => pieces[PieceType::King as usize][color_idx] |= mask,
|
|
||||||
=======
|
|
||||||
occupied[color_idx] |= mask; // Changed
|
|
||||||
match c {
|
|
||||||
'p' => pawns[color_idx] |= mask,
|
|
||||||
'n' => knights[color_idx] |= mask,
|
|
||||||
'b' => bishops[color_idx] |= mask,
|
|
||||||
'r' => rooks[color_idx] |= mask,
|
|
||||||
'q' => queens[color_idx] |= mask,
|
|
||||||
'k' => kings[color_idx] |= mask,
|
|
||||||
>>>>>>> origin/master
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part 2: Active color
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let side_to_move = match parts.next().unwrap_or("w") {
|
|
||||||
=======
|
|
||||||
let color = match parts.next().unwrap_or("w") {
|
|
||||||
>>>>>>> origin/master
|
|
||||||
"b" => Color::Black,
|
|
||||||
_ => Color::White,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Part 3: Castling rights
|
|
||||||
let mut castling_rights = 0u8;
|
|
||||||
if let Some(castle_str) = parts.next() {
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if castle_str.contains('K') { castling_rights |= CASTLING_WK; }
|
|
||||||
if castle_str.contains('Q') { castling_rights |= CASTLING_WQ; }
|
|
||||||
if castle_str.contains('k') { castling_rights |= CASTLING_BK; }
|
|
||||||
if castle_str.contains('q') { castling_rights |= CASTLING_BQ; }
|
|
||||||
=======
|
|
||||||
if castle_str.contains('K') { castling_rights |= 1; }
|
|
||||||
if castle_str.contains('Q') { castling_rights |= 2; }
|
|
||||||
if castle_str.contains('k') { castling_rights |= 4; }
|
|
||||||
if castle_str.contains('q') { castling_rights |= 8; }
|
|
||||||
>>>>>>> origin/master
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part 4: En passant target
|
|
||||||
let en_passant_target = match parts.next().unwrap_or("-") {
|
|
||||||
"-" => None,
|
|
||||||
sq_str => {
|
|
||||||
let chars: Vec<char> = sq_str.chars().collect();
|
|
||||||
let file = (chars[0] as u8 - b'a') as u8;
|
|
||||||
let rank = (chars[1] as u8 - b'1') as u8;
|
|
||||||
let sq_index = rank * 8 + file;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
// Convert the u8 index back to the Square enum
|
|
||||||
>>>>>>> origin/master
|
|
||||||
// This is unsafe, but assumes the FEN is valid
|
|
||||||
Some(unsafe { mem::transmute::<u8, Square>(sq_index) })
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Part 5: Halfmove clock
|
|
||||||
let halfmove_clock = parts.next().unwrap_or("0").parse::<u8>().unwrap_or(0);
|
|
||||||
|
|
||||||
// Part 6: Fullmove number
|
|
||||||
let fullmove_number = parts.next().unwrap_or("1").parse::<u16>().unwrap_or(1);
|
|
||||||
|
|
||||||
let all_occupied = occupied[Color::White as usize] | occupied[Color::Black as usize];
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let empty_squares = !all_occupied;
|
|
||||||
|
|
||||||
Board {
|
|
||||||
side_to_move,
|
|
||||||
pieces, // Geändertes Feld
|
|
||||||
=======
|
|
||||||
|
|
||||||
let empty_squares = !all_occupied;
|
|
||||||
|
|
||||||
Board {
|
|
||||||
color,
|
|
||||||
pawns,
|
|
||||||
knights,
|
|
||||||
bishops,
|
|
||||||
rooks,
|
|
||||||
queens,
|
|
||||||
kings,
|
|
||||||
>>>>>>> origin/master
|
|
||||||
occupied,
|
|
||||||
all_occupied,
|
|
||||||
empty_squares,
|
|
||||||
castling_rights,
|
|
||||||
en_passant_target,
|
|
||||||
halfmove_clock,
|
|
||||||
fullmove_number,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the current board state into a FEN string.
|
|
||||||
pub fn to_fen(&self) -> String {
|
|
||||||
let mut fen = String::with_capacity(90);
|
|
||||||
|
|
||||||
// Part 1: Piece placement
|
|
||||||
let mut empty_count = 0;
|
|
||||||
for rank in (0..=7).rev() {
|
|
||||||
for file in 0..=7 {
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let sq = (rank * 8 + file) as u8;
|
|
||||||
let mask = 1u64 << sq;
|
|
||||||
=======
|
|
||||||
// sq is the u8 index (0-63)
|
|
||||||
let sq = (rank * 8 + file) as u8;
|
|
||||||
let mask = 1u64 << sq; // This works (u64 << u8)
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
if let Some(piece) = self.get_piece_at(mask) {
|
|
||||||
if empty_count > 0 {
|
|
||||||
fen.push((b'0' + empty_count) as char);
|
|
||||||
empty_count = 0;
|
|
||||||
}
|
|
||||||
fen.push(piece);
|
|
||||||
} else {
|
|
||||||
empty_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if empty_count > 0 {
|
|
||||||
fen.push((b'0' + empty_count) as char);
|
|
||||||
empty_count = 0;
|
|
||||||
}
|
|
||||||
if rank > 0 {
|
|
||||||
fen.push('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part 2: Active color
|
|
||||||
fen.push(' ');
|
|
||||||
<<<<<<< HEAD
|
|
||||||
fen.push(if self.side_to_move == Color::White { 'w' } else { 'b' });
|
|
||||||
=======
|
|
||||||
fen.push(if self.color == Color::White { 'w' } else { 'b' });
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
// Part 3: Castling rights
|
|
||||||
fen.push(' ');
|
|
||||||
let mut castle_str = String::new();
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if (self.castling_rights & CASTLING_WK) != 0 { castle_str.push('K'); }
|
|
||||||
if (self.castling_rights & CASTLING_WQ) != 0 { castle_str.push('Q'); }
|
|
||||||
if (self.castling_rights & CASTLING_BK) != 0 { castle_str.push('k'); }
|
|
||||||
if (self.castling_rights & CASTLING_BQ) != 0 { castle_str.push('q'); }
|
|
||||||
=======
|
|
||||||
if (self.castling_rights & 1) != 0 { castle_str.push('K'); }
|
|
||||||
if (self.castling_rights & 2) != 0 { castle_str.push('Q'); }
|
|
||||||
if (self.castling_rights & 4) != 0 { castle_str.push('k'); }
|
|
||||||
if (self.castling_rights & 8) != 0 { castle_str.push('q'); }
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
if castle_str.is_empty() {
|
|
||||||
fen.push('-');
|
|
||||||
} else {
|
|
||||||
fen.push_str(&castle_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part 4: En passant target
|
|
||||||
fen.push(' ');
|
|
||||||
if let Some(sq) = self.en_passant_target {
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
// Cast the Square enum to its u8 representation
|
|
||||||
>>>>>>> origin/master
|
|
||||||
let sq_index = sq as u8;
|
|
||||||
let file = (sq_index % 8) as u8;
|
|
||||||
let rank = (sq_index / 8) as u8;
|
|
||||||
fen.push((b'a' + file) as char);
|
|
||||||
fen.push((b'1' + rank) as char);
|
|
||||||
} else {
|
|
||||||
fen.push('-');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part 5: Halfmove clock
|
|
||||||
fen.push(' ');
|
|
||||||
fen.push_str(&self.halfmove_clock.to_string());
|
|
||||||
|
|
||||||
// Part 6: Fullmove number
|
|
||||||
fen.push(' ');
|
|
||||||
fen.push_str(&self.fullmove_number.to_string());
|
|
||||||
|
|
||||||
fen
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper function to find which piece (as a char) is on a given square mask.
|
|
||||||
fn get_piece_at(&self, sq_mask: u64) -> Option<char> {
|
|
||||||
let white = Color::White as usize;
|
|
||||||
let black = Color::Black as usize;
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if (self.pieces[PieceType::Pawn as usize][white] & sq_mask) != 0 { return Some('P'); }
|
|
||||||
if (self.pieces[PieceType::Pawn as usize][black] & sq_mask) != 0 { return Some('p'); }
|
|
||||||
if (self.pieces[PieceType::Knight as usize][white] & sq_mask) != 0 { return Some('N'); }
|
|
||||||
if (self.pieces[PieceType::Knight as usize][black] & sq_mask) != 0 { return Some('n'); }
|
|
||||||
if (self.pieces[PieceType::Bishop as usize][white] & sq_mask) != 0 { return Some('B'); }
|
|
||||||
if (self.pieces[PieceType::Bishop as usize][black] & sq_mask) != 0 { return Some('b'); }
|
|
||||||
if (self.pieces[PieceType::Rook as usize][white] & sq_mask) != 0 { return Some('R'); }
|
|
||||||
if (self.pieces[PieceType::Rook as usize][black] & sq_mask) != 0 { return Some('r'); }
|
|
||||||
if (self.pieces[PieceType::Queen as usize][white] & sq_mask) != 0 { return Some('Q'); }
|
|
||||||
if (self.pieces[PieceType::Queen as usize][black] & sq_mask) != 0 { return Some('q'); }
|
|
||||||
if (self.pieces[PieceType::King as usize][white] & sq_mask) != 0 { return Some('K'); }
|
|
||||||
if (self.pieces[PieceType::King as usize][black] & sq_mask) != 0 { return Some('k'); }
|
|
||||||
=======
|
|
||||||
if (self.pawns[white] & sq_mask) != 0 { return Some('P'); }
|
|
||||||
if (self.pawns[black] & sq_mask) != 0 { return Some('p'); }
|
|
||||||
if (self.knights[white] & sq_mask) != 0 { return Some('N'); }
|
|
||||||
if (self.knights[black] & sq_mask) != 0 { return Some('n'); }
|
|
||||||
if (self.bishops[white] & sq_mask) != 0 { return Some('B'); }
|
|
||||||
if (self.bishops[black] & sq_mask) != 0 { return Some('b'); }
|
|
||||||
if (self.rooks[white] & sq_mask) != 0 { return Some('R'); }
|
|
||||||
if (self.rooks[black] & sq_mask) != 0 { return Some('r'); }
|
|
||||||
if (self.queens[white] & sq_mask) != 0 { return Some('Q'); }
|
|
||||||
if (self.queens[black] & sq_mask) != 0 { return Some('q'); }
|
|
||||||
if (self.kings[white] & sq_mask) != 0 { return Some('K'); }
|
|
||||||
if (self.kings[black] & sq_mask) != 0 { return Some('k'); }
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints a single bitboard (u64) as an 8x8 grid for debugging.
|
|
||||||
fn print_bitboard(&self, name: &str, bitboard: u64) {
|
|
||||||
println!("--- {} ---", name);
|
|
||||||
println!(" a b c d e f g h");
|
|
||||||
for rank in (0..=7).rev() {
|
|
||||||
print!("{} ", rank + 1);
|
|
||||||
for file in 0..=7 {
|
|
||||||
let sq_index = rank * 8 + file;
|
|
||||||
let mask = 1u64 << sq_index;
|
|
||||||
|
|
||||||
if (bitboard & mask) != 0 {
|
|
||||||
print!("1 ");
|
|
||||||
} else {
|
|
||||||
print!(". ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
println!("RAW VALUE: {}", bitboard);
|
|
||||||
<<<<<<< HEAD
|
|
||||||
println!();
|
|
||||||
=======
|
|
||||||
println!(); // Add a newline for spacing
|
|
||||||
>>>>>>> origin/master
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints all internal bitboards for debugging purposes.
|
|
||||||
pub fn pretty_print_internals(&self) {
|
|
||||||
println!("\n========= BOARD INTERNAL BITBOARDS =========");
|
|
||||||
|
|
||||||
let white = Color::White as usize;
|
|
||||||
let black = Color::Black as usize;
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
self.print_bitboard("White Pawns", self.pieces[PieceType::Pawn as usize][white]);
|
|
||||||
self.print_bitboard("Black Pawns", self.pieces[PieceType::Pawn as usize][black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Knights", self.pieces[PieceType::Knight as usize][white]);
|
|
||||||
self.print_bitboard("Black Knights", self.pieces[PieceType::Knight as usize][black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Bishops", self.pieces[PieceType::Bishop as usize][white]);
|
|
||||||
self.print_bitboard("Black Bishops", self.pieces[PieceType::Bishop as usize][black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Rooks", self.pieces[PieceType::Rook as usize][white]);
|
|
||||||
self.print_bitboard("Black Rooks", self.pieces[PieceType::Rook as usize][black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Queens", self.pieces[PieceType::Queen as usize][white]);
|
|
||||||
self.print_bitboard("Black Queens", self.pieces[PieceType::Queen as usize][black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White King", self.pieces[PieceType::King as usize][white]);
|
|
||||||
self.print_bitboard("Black King", self.pieces[PieceType::King as usize][black]);
|
|
||||||
|
|
||||||
println!("--- Aggregate Bitboards ---");
|
|
||||||
=======
|
|
||||||
self.print_bitboard("White Pawns", self.pawns[white]);
|
|
||||||
self.print_bitboard("Black Pawns", self.pawns[black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Knights", self.knights[white]);
|
|
||||||
self.print_bitboard("Black Knights", self.knights[black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Bishops", self.bishops[white]);
|
|
||||||
self.print_bitboard("Black Bishops", self.bishops[black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Rooks", self.rooks[white]);
|
|
||||||
self.print_bitboard("Black Rooks", self.rooks[black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White Queens", self.queens[white]);
|
|
||||||
self.print_bitboard("Black Queens", self.queens[black]);
|
|
||||||
|
|
||||||
self.print_bitboard("White King", self.kings[white]);
|
|
||||||
self.print_bitboard("Black King", self.kings[black]);
|
|
||||||
|
|
||||||
println!("--- Aggregate Bitboards ---");
|
|
||||||
// Updated to use the 'occupied' array
|
|
||||||
>>>>>>> origin/master
|
|
||||||
self.print_bitboard("All White Pieces", self.occupied[white]);
|
|
||||||
self.print_bitboard("All Black Pieces", self.occupied[black]);
|
|
||||||
self.print_bitboard("All Occupied", self.all_occupied);
|
|
||||||
self.print_bitboard("Empty Squares", self.empty_squares);
|
|
||||||
|
|
||||||
println!("============================================\n");
|
|
||||||
}
|
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
pub fn make_move(&mut self, mv: Move) {
|
|
||||||
let from = mv.value()& MOVE_FROM_MASK;
|
|
||||||
let to = mv.value() & MOVE_TO_MASK;
|
|
||||||
let flag = mv.value() & MOVE_FLAG_MASK;
|
|
||||||
|
|
||||||
// promo must come first because of double usage of the flag bits
|
|
||||||
if flag == MOVE_FLAG_NO_PROMO {
|
|
||||||
|
|
||||||
} else { //
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
=======
|
|
||||||
}
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
pub mod board;
|
|
||||||
pub mod r#move;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
pub mod color;
|
|
||||||
>>>>>>> origin/master
|
|
||||||
pub mod square;
|
|
||||||
pub mod movegen;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::generate_pseudo_legal_moves;
|
|
||||||
use chess_engine::r#move::*;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 1 2");
|
|
||||||
let mut move_list = MoveList::new();
|
|
||||||
|
|
||||||
generate_pseudo_legal_moves(&board, &mut move_list);
|
|
||||||
|
|
||||||
println!("Counted {} pseudo legal moves.", move_list.len());
|
|
||||||
=======
|
|
||||||
use chess_engine::movegen::tables::{get_rook_attacks, get_bishop_attacks};
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Calculate the move tables
|
|
||||||
get_rook_attacks();
|
|
||||||
get_bishop_attacks();
|
|
||||||
>>>>>>> origin/master
|
|
||||||
}
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
||||||
use std::slice;
|
|
||||||
use std::fmt;
|
|
||||||
use crate::square::Square;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
use crate::board::PieceType;
|
|
||||||
=======
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
// BIT 0 - 5: FROM SQUARE (0-63)
|
|
||||||
pub const MOVE_FROM_MASK: u16 = 0b0000_0000_0011_1111;
|
|
||||||
|
|
||||||
// BIT 6 - 11: TO SQUARE (0-63)
|
|
||||||
pub const MOVE_TO_MASK: u16 = 0b0000_1111_1100_0000;
|
|
||||||
|
|
||||||
// BIT 12 - 15: FLAGS (4 bits)
|
|
||||||
<<<<<<< HEAD
|
|
||||||
// 1. 0 no capture, 1 capture
|
|
||||||
pub const MOVE_FLAG_MASK: u16 = 0b1111_0000_0000_0000;
|
|
||||||
|
|
||||||
pub const MOVE_FLAG_QUIET: u16 = 0b0000_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_CAPTURE: u16 = 0b0001_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_EN_PASSANT: u16 = 0b0010_0000_0000_0000;
|
|
||||||
|
|
||||||
pub const MOVE_FLAG_WK_CASTLE: u16 = 0b0011_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_WQ_CASTLE: u16 = 0b0100_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_BK_CASTLE: u16 = 0b0101_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_BQ_CASTLE: u16 = 0b0110_0000_0000_0000;
|
|
||||||
// 0111 is free
|
|
||||||
|
|
||||||
// Promotion flags (use the 1xxx bits)
|
|
||||||
// We combine capture flag with promotion type
|
|
||||||
pub const MOVE_FLAG_PROMO: u16 = 0b1000_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_NO_PROMO: u16 = 0b0000_0000_0000_0000;
|
|
||||||
|
|
||||||
=======
|
|
||||||
pub const MOVE_FLAG_MASK: u16 = 0b1111_0000_0000_0000;
|
|
||||||
|
|
||||||
pub const MOVE_FLAG_QUIET: u16 = 0b0000_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_DOUBLE_PAWN: u16 = 0b0001_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_KING_CASTLE: u16 = 0b0010_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_QUEEN_CASTLE: u16 = 0b0011_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_CAPTURE: u16 = 0b0100_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_EN_PASSANT: u16 = 0b0101_0000_0000_0000;
|
|
||||||
// 0110, 0111 are free
|
|
||||||
|
|
||||||
// Promotion flags (use the 1xxx bits)
|
|
||||||
// We combine capture flag with promotion type
|
|
||||||
>>>>>>> origin/master
|
|
||||||
pub const MOVE_FLAG_PROMO_N: u16 = 0b1000_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_B: u16 = 0b1001_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_R: u16 = 0b1010_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_Q: u16 = 0b1011_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_CAP_N: u16 = 0b1100_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_CAP_B: u16 = 0b1101_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_CAP_R: u16 = 0b1110_0000_0000_0000;
|
|
||||||
pub const MOVE_FLAG_PROMO_CAP_Q: u16 = 0b1111_0000_0000_0000;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub struct Move(u16);
|
|
||||||
|
|
||||||
impl Move {
|
|
||||||
pub fn new(from: Square, to: Square, flags: u16) -> Move {
|
|
||||||
Move(flags |
|
|
||||||
((to as u16) << 6 ) |
|
|
||||||
from as u16)
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
pub fn value(&self) -> u16 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> origin/master
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get_flags(&self) -> u16 {
|
|
||||||
self.0 & MOVE_FLAG_MASK
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
// Helper for search
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_capture(&self) -> bool {
|
|
||||||
// Check if the 3rd bit of the flag (0100) is set.
|
|
||||||
// This covers simple captures (0100), EP (0101), and promo-captures (11xx).
|
|
||||||
(self.0 & 0b0100_0000_0000_0000) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper for search
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_promotion(&self) -> bool {
|
|
||||||
// Check if the 4th bit of the flag (1xxx) is set.
|
|
||||||
(self.0 & 0b1000_0000_0000_0000) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
/// Converts a square index (0-63) to algebraic notation (e.g., 0 -> "a1", 63 -> "h8").
|
|
||||||
fn square_val_to_alg(val: u16) -> String {
|
|
||||||
let file = (b'a' + (val % 8) as u8) as char;
|
|
||||||
let rank = (b'1' + (val / 8) as u8) as char;
|
|
||||||
format!("{}{}", file, rank)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the move to coordinate notation (e.g., "e2e4", "e7e8q", "e1g1").
|
|
||||||
pub fn to_algebraic(&self) -> String {
|
|
||||||
let flags = self.get_flags();
|
|
||||||
|
|
||||||
// Handle castling first. In this new format, the "to" square is
|
|
||||||
// the *king's* destination square (g1/c1 or g8/c8).
|
|
||||||
// Your old implementation reading the file is still fine.
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if (flags == MOVE_FLAG_WK_CASTLE) || (flags == MOVE_FLAG_BK_CASTLE) {
|
|
||||||
return "O-O".to_string();
|
|
||||||
}
|
|
||||||
if (flags == MOVE_FLAG_WQ_CASTLE) || (flags == MOVE_FLAG_BQ_CASTLE) {
|
|
||||||
=======
|
|
||||||
if flags == MOVE_FLAG_KING_CASTLE {
|
|
||||||
return "O-O".to_string();
|
|
||||||
}
|
|
||||||
if flags == MOVE_FLAG_QUEEN_CASTLE {
|
|
||||||
>>>>>>> origin/master
|
|
||||||
return "O-O-O".to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let from_val = self.0 & MOVE_FROM_MASK;
|
|
||||||
let to_val = (self.0 & MOVE_TO_MASK) >> 6;
|
|
||||||
|
|
||||||
let from_str = Self::square_val_to_alg(from_val);
|
|
||||||
let to_str = Self::square_val_to_alg(to_val);
|
|
||||||
|
|
||||||
// Check if it's any promotion type (1xxx)
|
|
||||||
if (flags & 0b1000_0000_0000_0000) != 0 {
|
|
||||||
let promo_char = match flags {
|
|
||||||
MOVE_FLAG_PROMO_N | MOVE_FLAG_PROMO_CAP_N => 'n',
|
|
||||||
MOVE_FLAG_PROMO_B | MOVE_FLAG_PROMO_CAP_B => 'b',
|
|
||||||
MOVE_FLAG_PROMO_R | MOVE_FLAG_PROMO_CAP_R => 'r',
|
|
||||||
MOVE_FLAG_PROMO_Q | MOVE_FLAG_PROMO_CAP_Q => 'q',
|
|
||||||
_ => '?', // Should not happen
|
|
||||||
};
|
|
||||||
format!("{}{}{}", from_str, to_str, promo_char)
|
|
||||||
} else {
|
|
||||||
// This covers Quiet, DoublePawn, Capture, EnPassant
|
|
||||||
format!("{}{}", from_str, to_str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... Rest des MoveList-Codes bleibt exakt gleich ...
|
|
||||||
// (MoveList, new, push, len, is_empty, iter, impl fmt::Display)
|
|
||||||
pub struct MoveList {
|
|
||||||
moves: [Move; 256],
|
|
||||||
count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MoveList {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
MoveList {
|
|
||||||
moves: [unsafe { std::mem::zeroed() }; 256],
|
|
||||||
count: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn push(&mut self, mv: Move) {
|
|
||||||
debug_assert!(self.count < 256, "Move list overflow!");
|
|
||||||
|
|
||||||
self.moves[self.count] = mv;
|
|
||||||
self.count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.count
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.count == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn iter(&self) -> slice::Iter<'_, Move> {
|
|
||||||
self.moves[..self.count].iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for MoveList {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", &self.iter().map(|mv| mv.to_algebraic()).collect::<Vec<String>>().join(" "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
|
|
||||||
pub struct UndoMove {
|
|
||||||
mv: Move,
|
|
||||||
captured_piece: Option<PieceType>,
|
|
||||||
old_en_passant_square: Option<Square>,
|
|
||||||
old_castling_rights: u8,
|
|
||||||
old_halfmove_clock: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UndoMove {
|
|
||||||
pub fn new(mv: Move,
|
|
||||||
captured_piece: Option<PieceType>,
|
|
||||||
old_en_passant_square: Option<Square>,
|
|
||||||
old_castling_rights: u8,
|
|
||||||
old_halfmove_clock: u8) -> Self {
|
|
||||||
Self {
|
|
||||||
mv,
|
|
||||||
captured_piece,
|
|
||||||
old_en_passant_square,
|
|
||||||
old_castling_rights,
|
|
||||||
old_halfmove_clock
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
=======
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
pub mod non_sliders;
|
|
||||||
pub mod sliders;
|
|
||||||
pub mod pawns;
|
|
||||||
pub mod tables;
|
|
||||||
|
|
||||||
use crate::board::Board;
|
|
||||||
use crate::r#move::*;
|
|
||||||
use non_sliders::*;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
use sliders::*;
|
|
||||||
use pawns::*;
|
|
||||||
|
|
||||||
pub fn generate_pseudo_legal_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
generate_pawn_moves(board, list);
|
|
||||||
generate_knight_moves(board, list);
|
|
||||||
generate_bishop_moves(board, list);
|
|
||||||
generate_rook_moves(board, list);
|
|
||||||
generate_queen_moves(board, list);
|
|
||||||
generate_king_moves(board, list);
|
|
||||||
=======
|
|
||||||
|
|
||||||
pub fn generate_pseudo_legal_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
generate_knight_moves(board, list);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
}
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
use crate::board::*;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
use crate::r#move::*;
|
|
||||||
use crate::square::*;
|
|
||||||
use super::tables::{KING_ATTACKS, KNIGHT_ATTACKS};
|
|
||||||
|
|
||||||
pub fn generate_knight_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
let enemy_occupied = board.occupied[!board.side_to_move as usize];
|
|
||||||
let mut friendly_knights = board.pieces[PieceType::Knight as usize][board.side_to_move as usize];
|
|
||||||
|
|
||||||
while friendly_knights != 0 {
|
|
||||||
let square = SQUARES[friendly_knights.trailing_zeros() as usize];
|
|
||||||
let mut attacks = KNIGHT_ATTACKS[square as usize] & !board.occupied[board.side_to_move as usize];
|
|
||||||
=======
|
|
||||||
use crate::color::Color;
|
|
||||||
use crate::r#move::{
|
|
||||||
Move, MoveList, MOVE_FLAG_CAPTURE, MOVE_FLAG_KING_CASTLE, MOVE_FLAG_QUEEN_CASTLE,
|
|
||||||
MOVE_FLAG_QUIET,
|
|
||||||
};
|
|
||||||
use crate::square::{Square, SQUARES};
|
|
||||||
use super::tables::{KING_ATTACKS, KNIGHT_ATTACKS};
|
|
||||||
|
|
||||||
pub fn generate_knight_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
let enemy_occupied = board.occupied[!board.color as usize];
|
|
||||||
let mut friendly_knights = board.knights[board.color as usize];
|
|
||||||
|
|
||||||
while friendly_knights != 0 {
|
|
||||||
let square = SQUARES[friendly_knights.trailing_zeros() as usize];
|
|
||||||
let mut attacks = KNIGHT_ATTACKS[square as usize] & !board.occupied[board.color as usize];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
while attacks != 0 {
|
|
||||||
let attack = SQUARES[attacks.trailing_zeros() as usize];
|
|
||||||
let attack_bb = 1u64 << attack as u64;
|
|
||||||
|
|
||||||
let flags = if (enemy_occupied & attack_bb) != 0 {
|
|
||||||
MOVE_FLAG_CAPTURE
|
|
||||||
} else {
|
|
||||||
MOVE_FLAG_QUIET
|
|
||||||
};
|
|
||||||
|
|
||||||
let mv = Move::new(square, attack, flags);
|
|
||||||
list.push(mv);
|
|
||||||
attacks &= attacks - 1;
|
|
||||||
}
|
|
||||||
friendly_knights &= friendly_knights - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_king_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let enemy_occupied = board.occupied[!board.side_to_move as usize];
|
|
||||||
let friendly_king = board.pieces[PieceType::King as usize][board.side_to_move as usize];
|
|
||||||
=======
|
|
||||||
let enemy_occupied = board.occupied[!board.color as usize];
|
|
||||||
let friendly_king = board.kings[board.color as usize];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
if friendly_king == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let square = SQUARES[friendly_king.trailing_zeros() as usize];
|
|
||||||
|
|
||||||
// 1. Generate standard king moves
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let mut attacks = KING_ATTACKS[square as usize] & !board.occupied[board.side_to_move as usize];
|
|
||||||
=======
|
|
||||||
let mut attacks = KING_ATTACKS[square as usize] & !board.occupied[board.color as usize];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
while attacks != 0 {
|
|
||||||
let attack = SQUARES[attacks.trailing_zeros() as usize];
|
|
||||||
let attack_bb = 1u64 << attack as u64;
|
|
||||||
|
|
||||||
let flags = if (enemy_occupied & attack_bb) != 0 {
|
|
||||||
MOVE_FLAG_CAPTURE
|
|
||||||
} else {
|
|
||||||
MOVE_FLAG_QUIET
|
|
||||||
};
|
|
||||||
|
|
||||||
let mv = Move::new(square, attack, flags);
|
|
||||||
list.push(mv);
|
|
||||||
attacks &= attacks - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Generate castling king moves
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if board.side_to_move == Color::White {
|
|
||||||
// Kingside (OO)
|
|
||||||
if (board.castling_rights & CASTLING_WK) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_WK_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E1, Square::G1, MOVE_FLAG_WK_CASTLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Queenside (OOO)
|
|
||||||
if (board.castling_rights & CASTLING_WQ) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_WQ_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E1, Square::C1, MOVE_FLAG_WQ_CASTLE));
|
|
||||||
=======
|
|
||||||
if board.color == Color::White {
|
|
||||||
// Kingside (OO)
|
|
||||||
if (board.castling_rights & CASTLING_W_KING) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_W_KING_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E1, Square::G1, MOVE_FLAG_KING_CASTLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Queenside (OOO)
|
|
||||||
if (board.castling_rights & CASTLING_W_QUEEN) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_W_QUEEN_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E1, Square::C1, MOVE_FLAG_QUEEN_CASTLE));
|
|
||||||
>>>>>>> origin/master
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // Black
|
|
||||||
// Kingside (OO)
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if (board.castling_rights & CASTLING_BK) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_BK_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E8, Square::G8, MOVE_FLAG_BK_CASTLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Queenside (OOO)
|
|
||||||
if (board.castling_rights & CASTLING_BQ) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_BQ_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E8, Square::C8, MOVE_FLAG_BQ_CASTLE));
|
|
||||||
=======
|
|
||||||
if (board.castling_rights & CASTLING_B_KING) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_B_KING_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E8, Square::G8, MOVE_FLAG_KING_CASTLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Queenside (OOO)
|
|
||||||
if (board.castling_rights & CASTLING_B_QUEEN) != 0 {
|
|
||||||
if (board.all_occupied & CASTLING_B_QUEEN_MASK) == 0 {
|
|
||||||
list.push(Move::new(Square::E8, Square::C8, MOVE_FLAG_QUEEN_CASTLE));
|
|
||||||
>>>>>>> origin/master
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
||||||
<<<<<<< HEAD
|
|
||||||
use crate::board::*;
|
|
||||||
use crate::r#move::*;
|
|
||||||
use crate::square::*;
|
|
||||||
=======
|
|
||||||
use crate::board::Board;
|
|
||||||
use crate::r#move::*;
|
|
||||||
use crate::square::*;
|
|
||||||
use crate::color::Color;
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
pub const RANK1_MASK: u64 = 255; // A1 - H1
|
|
||||||
pub const RANK2_MASK: u64 = 65280; // A2 - H2
|
|
||||||
pub const RANK3_MASK: u64 = 16711680; // A3 - H3
|
|
||||||
pub const RANK4_MASK: u64 = 4278190080; // A4 - H4
|
|
||||||
pub const RANK5_MASK: u64 = 1095216660480; // A5 - H5
|
|
||||||
pub const RANK6_MASK: u64 = 280375465082880; // A6 - H6
|
|
||||||
pub const RANK7_MASK: u64 = 71776119061217280; // A7 - H7
|
|
||||||
pub const RANK8_MASK: u64 = 18374686479671623680; // A8 - H8
|
|
||||||
|
|
||||||
|
|
||||||
pub const PAWN_A_SIDE_CAPTURE_MASK_WITHE: u64 = 280371153272574; // B1 - H6 (omitted promotions)
|
|
||||||
pub const PAWN_H_SIDE_CAPTURE_MASK_WITHE: u64 = 140185576636287; // A1- G6 (omitted promotions)
|
|
||||||
|
|
||||||
pub const PAWN_A_SIDE_CAPTURE_MASK_BLACK: u64 = 18374403900871409664; // B3 - H8 (omitted promotions)
|
|
||||||
pub const PAWN_H_SIDE_CAPTURE_MASK_BLACK: u64 = 9187201950435704832; // A3- G8 (omitted promotions)
|
|
||||||
|
|
||||||
|
|
||||||
pub const PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_WITHE: u64 = 71494644084506624; // B7 - H7
|
|
||||||
pub const PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE: u64 = 35747322042253312; // A7- G7
|
|
||||||
|
|
||||||
pub const PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_BLACK: u64 = 65024; // B2 - H2
|
|
||||||
pub const PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_BLACK: u64 = 32512; // A2 - G2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
|
|
||||||
// 1. Withe
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if board.side_to_move == Color::White {
|
|
||||||
let friendly_pawns = board.pieces[PieceType::Pawn as usize][0];
|
|
||||||
=======
|
|
||||||
if board.color == Color::White {
|
|
||||||
let friendly_pawns = board.pawns[0];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
let opponent_occupied = board.occupied[1];
|
|
||||||
|
|
||||||
// 1.1 Single Push
|
|
||||||
let mut single_push_targets = ((friendly_pawns & !(RANK8_MASK | RANK7_MASK)) << 8) & board.empty_squares;
|
|
||||||
|
|
||||||
while single_push_targets > 0 {
|
|
||||||
let to = SQUARES[single_push_targets.trailing_zeros() as usize];
|
|
||||||
let from = to - 8;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
single_push_targets &= single_push_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.2 Double Push
|
|
||||||
let base_rank_pawns = friendly_pawns & RANK2_MASK;
|
|
||||||
let rank3_unblocked = (base_rank_pawns << 8) & board.empty_squares;
|
|
||||||
let mut double_push_targets = (rank3_unblocked << 8) & board.empty_squares;
|
|
||||||
|
|
||||||
while double_push_targets > 0 {
|
|
||||||
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
|
||||||
let from = to - 16;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
=======
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_DOUBLE_PAWN));
|
|
||||||
>>>>>>> origin/master
|
|
||||||
double_push_targets &= double_push_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.3 Captures
|
|
||||||
// 1.3.1 A-Side Capture (omitted promotion captures)
|
|
||||||
let mut a_side_capture_targets = (friendly_pawns & PAWN_H_SIDE_CAPTURE_MASK_WITHE) << 7 & opponent_occupied;
|
|
||||||
|
|
||||||
while a_side_capture_targets > 0 {
|
|
||||||
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize];
|
|
||||||
let from = to - 7;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
a_side_capture_targets &= a_side_capture_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.3.2 H-Side Capture (omitted promotion captures)
|
|
||||||
let mut h_side_capture_targets = (friendly_pawns & PAWN_A_SIDE_CAPTURE_MASK_WITHE) << 9 & opponent_occupied;
|
|
||||||
|
|
||||||
while h_side_capture_targets > 0 {
|
|
||||||
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize];
|
|
||||||
let from = to - 9;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
h_side_capture_targets &= h_side_capture_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.4 Promotion
|
|
||||||
// 1.4.1 Pushing promotion
|
|
||||||
let mut promotion_targets = ((friendly_pawns & RANK7_MASK) << 8) & board.empty_squares;
|
|
||||||
|
|
||||||
while promotion_targets > 0 {
|
|
||||||
let to = SQUARES[promotion_targets.trailing_zeros() as usize];
|
|
||||||
let from = to - 8;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_Q));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N));
|
|
||||||
promotion_targets &= promotion_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.4.2 Capturing Promotion
|
|
||||||
// 1.4.2.1 A-side capturing promotion
|
|
||||||
// CORRECTED: Use PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_WITHE (excludes A-file)
|
|
||||||
let mut promotion_targets_a_side_capture = ((friendly_pawns & PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_WITHE) << 7) & board.occupied[1];
|
|
||||||
while promotion_targets_a_side_capture > 0 {
|
|
||||||
let to = SQUARES[promotion_targets_a_side_capture.trailing_zeros() as usize];
|
|
||||||
let from = to - 7;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
|
||||||
promotion_targets_a_side_capture &= promotion_targets_a_side_capture - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.4.2.2 H-side capturing promotion
|
|
||||||
// CORRECTED: Use PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE (excludes H-file)
|
|
||||||
let mut promotion_targets_h_side_capture = ((friendly_pawns & PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE) << 9) & board.occupied[1];
|
|
||||||
while promotion_targets_h_side_capture > 0 {
|
|
||||||
let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize];
|
|
||||||
let from = to - 9;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
|
||||||
promotion_targets_h_side_capture &= promotion_targets_h_side_capture - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1.5 En Passant
|
|
||||||
if let Some(en_passant_target_square) = board.en_passant_target {
|
|
||||||
// Check if the target square is on the 6th rank (A6=40 to H6=47)
|
|
||||||
if (en_passant_target_square >= Square::A6) && (en_passant_target_square <= Square::H6) {
|
|
||||||
let en_passant_target_bb: u64 = 1_u64 << (en_passant_target_square as u64);
|
|
||||||
|
|
||||||
// 1. Check A-Side capture (<< 7, e.g., D5 -> C6)
|
|
||||||
let attacker_mask_a_side = (en_passant_target_bb >> 7) & PAWN_H_SIDE_CAPTURE_MASK_WITHE;
|
|
||||||
if (attacker_mask_a_side & friendly_pawns) > 0 {
|
|
||||||
let from = en_passant_target_square - 7;
|
|
||||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Check H-Side capture (<< 9, e.g., B5 -> C6)
|
|
||||||
let attacker_mask_h_side = (en_passant_target_bb >> 9) & PAWN_A_SIDE_CAPTURE_MASK_WITHE;
|
|
||||||
if (attacker_mask_h_side & friendly_pawns) > 0 {
|
|
||||||
let from = en_passant_target_square - 9;
|
|
||||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 2. Black
|
|
||||||
} else {
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let friendly_pawns = board.pieces[PieceType::Pawn as usize][1];
|
|
||||||
=======
|
|
||||||
let friendly_pawns = board.pawns[1];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
let opponent_occupied = board.occupied[0];
|
|
||||||
|
|
||||||
// 2.1 Single Push
|
|
||||||
let mut single_push_targets = ((friendly_pawns & !(RANK1_MASK | RANK2_MASK)) >> 8) & board.empty_squares;
|
|
||||||
|
|
||||||
while single_push_targets > 0 {
|
|
||||||
let to = SQUARES[single_push_targets.trailing_zeros() as usize];
|
|
||||||
let from = to + 8;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
single_push_targets &= single_push_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.2 Double Push
|
|
||||||
let base_rank_pawns = friendly_pawns & RANK7_MASK;
|
|
||||||
let rank6_unblocked = (base_rank_pawns >> 8) & board.empty_squares;
|
|
||||||
let mut double_push_targets = (rank6_unblocked >> 8) & board.empty_squares;
|
|
||||||
|
|
||||||
while double_push_targets > 0 {
|
|
||||||
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
|
||||||
let from = to + 16;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
=======
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_DOUBLE_PAWN));
|
|
||||||
>>>>>>> origin/master
|
|
||||||
double_push_targets &= double_push_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.3 Captures
|
|
||||||
// 2.3.1 A-Side Capture (>> 9)
|
|
||||||
let mut a_side_capture_targets = (friendly_pawns & PAWN_A_SIDE_CAPTURE_MASK_BLACK) >> 9 & opponent_occupied;
|
|
||||||
|
|
||||||
while a_side_capture_targets > 0 {
|
|
||||||
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize];
|
|
||||||
let from = to + 9;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
a_side_capture_targets &= a_side_capture_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.3.2 H-Side Capture (>> 7)
|
|
||||||
let mut h_side_capture_targets = (friendly_pawns & PAWN_H_SIDE_CAPTURE_MASK_BLACK) >> 7 & opponent_occupied;
|
|
||||||
|
|
||||||
while h_side_capture_targets > 0 {
|
|
||||||
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize];
|
|
||||||
let from = to + 7;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
h_side_capture_targets &= h_side_capture_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.4 Promotion
|
|
||||||
// 2.4.1 Pushing promotion
|
|
||||||
let mut promotion_targets = ((friendly_pawns & RANK2_MASK) >> 8) & board.empty_squares;
|
|
||||||
|
|
||||||
while promotion_targets > 0 {
|
|
||||||
let to = SQUARES[promotion_targets.trailing_zeros() as usize];
|
|
||||||
let from = to + 8;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_Q));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N));
|
|
||||||
promotion_targets &= promotion_targets - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.4.2 Capturing Promotion
|
|
||||||
// 2.4.2.1 A-side capturing promotion (>> 9)
|
|
||||||
let mut promotion_targets_a_side_capture = ((friendly_pawns & PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_BLACK) >> 9) & opponent_occupied;
|
|
||||||
while promotion_targets_a_side_capture > 0 {
|
|
||||||
let to = SQUARES[promotion_targets_a_side_capture.trailing_zeros() as usize];
|
|
||||||
let from = to + 9;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
|
||||||
promotion_targets_a_side_capture &= promotion_targets_a_side_capture - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.4.2.2 H-side capturing promotion (>> 7)
|
|
||||||
let mut promotion_targets_h_side_capture = ((friendly_pawns & PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_BLACK) >> 7) & opponent_occupied;
|
|
||||||
while promotion_targets_h_side_capture > 0 {
|
|
||||||
let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize];
|
|
||||||
let from = to + 7;
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
|
||||||
promotion_targets_h_side_capture &= promotion_targets_h_side_capture - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.5 En Passant
|
|
||||||
if let Some(en_passant_target_square) = board.en_passant_target {
|
|
||||||
// Check if the target square is on the 3rd rank (A3=16 to H3=23)
|
|
||||||
if (en_passant_target_square >= Square::A3) && (en_passant_target_square <= Square::H3) {
|
|
||||||
let en_passant_target_bb: u64 = 1_u64 << (en_passant_target_square as u64);
|
|
||||||
|
|
||||||
// 1. Check A-Side capture (>> 9, e.g., B4 -> A3)
|
|
||||||
let attacker_mask_a_side = (en_passant_target_bb << 9) & PAWN_A_SIDE_CAPTURE_MASK_BLACK;
|
|
||||||
if (attacker_mask_a_side & friendly_pawns) > 0 {
|
|
||||||
let from = en_passant_target_square + 9;
|
|
||||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Check H-Side capture (>> 7, e.g., G4 -> H3)
|
|
||||||
let attacker_mask_h_side = (en_passant_target_bb << 7) & PAWN_H_SIDE_CAPTURE_MASK_BLACK;
|
|
||||||
if (attacker_mask_h_side & friendly_pawns) > 0 {
|
|
||||||
let from = en_passant_target_square + 7;
|
|
||||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
use crate::board::*;
|
|
||||||
<<<<<<< HEAD
|
|
||||||
use crate::r#move::{Move, MoveList, MOVE_FLAG_CAPTURE, MOVE_FLAG_QUIET};
|
|
||||||
use crate::square::SQUARES;
|
|
||||||
use super::tables::*;
|
|
||||||
|
|
||||||
pub fn generate_rook_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
let mut friendly_rooks = board.pieces[PieceType::Rook as usize][board.side_to_move as usize];
|
|
||||||
=======
|
|
||||||
use crate::color::Color;
|
|
||||||
use crate::r#move::{Move, MoveList, MOVE_FLAG_CAPTURE, MOVE_FLAG_QUIET};
|
|
||||||
use crate::square::{Square, SQUARES};
|
|
||||||
use super::tables::{PREMASKS_ROOK, PREMASKS_BISHOP, MAGICS_ROOK, MAGICS_BISHOP, RELEVANT_BITS_ROOK, RELEVANT_BITS_BISHOP, get_rook_attacks, get_bishop_attacks};
|
|
||||||
|
|
||||||
pub fn generate_rook_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
let mut friendly_rooks = board.rooks[board.color as usize];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
while friendly_rooks > 0 {
|
|
||||||
let square_index = friendly_rooks.trailing_zeros() as usize;
|
|
||||||
|
|
||||||
let premask = PREMASKS_ROOK[square_index];
|
|
||||||
let magic = MAGICS_ROOK[square_index];
|
|
||||||
let relevant_bits = RELEVANT_BITS_ROOK[square_index];
|
|
||||||
let shift = 64 - relevant_bits;
|
|
||||||
let blockers = board.all_occupied & premask;
|
|
||||||
let attack_table = get_rook_attacks();
|
|
||||||
|
|
||||||
let magic_index = (blockers.wrapping_mul(magic)) >> shift;
|
|
||||||
|
|
||||||
let movable_squares = attack_table[square_index][magic_index as usize];
|
|
||||||
|
|
||||||
// 1. Normal moves
|
|
||||||
let mut quiet_moves = movable_squares & !board.all_occupied;
|
|
||||||
while quiet_moves > 0 {
|
|
||||||
let from = SQUARES[square_index];
|
|
||||||
let to = SQUARES[quiet_moves.trailing_zeros() as usize];
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
quiet_moves &= quiet_moves - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Captures
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let mut capture_moves = movable_squares & board.occupied[!board.side_to_move as usize];
|
|
||||||
=======
|
|
||||||
let mut capture_moves = movable_squares & board.occupied[!board.color as usize];
|
|
||||||
>>>>>>> origin/master
|
|
||||||
while capture_moves > 0 {
|
|
||||||
let from = SQUARES[square_index];
|
|
||||||
let to = SQUARES[capture_moves.trailing_zeros() as usize];
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
capture_moves &= capture_moves - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
friendly_rooks &= friendly_rooks - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
pub fn generate_bishop_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
let mut friendly_bishops = board.pieces[PieceType::Bishop as usize][board.side_to_move as usize];
|
|
||||||
while friendly_bishops > 0 {
|
|
||||||
let square_index = friendly_bishops.trailing_zeros() as usize;
|
|
||||||
|
|
||||||
let premask = PREMASKS_BISHOP[square_index];
|
|
||||||
let magic = MAGICS_BISHOP[square_index];
|
|
||||||
let relevant_bits = RELEVANT_BITS_BISHOP[square_index];
|
|
||||||
let shift = 64 - relevant_bits;
|
|
||||||
let blockers = board.all_occupied & premask;
|
|
||||||
let attack_table = get_bishop_attacks();
|
|
||||||
|
|
||||||
let magic_index = (blockers.wrapping_mul(magic)) >> shift;
|
|
||||||
|
|
||||||
let movable_squares = attack_table[square_index][magic_index as usize];
|
|
||||||
|
|
||||||
// 1. Normal moves
|
|
||||||
let mut quiet_moves = movable_squares & !board.all_occupied;
|
|
||||||
while quiet_moves > 0 {
|
|
||||||
let from = SQUARES[square_index];
|
|
||||||
let to = SQUARES[quiet_moves.trailing_zeros() as usize];
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
quiet_moves &= quiet_moves - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Captures
|
|
||||||
let mut capture_moves = movable_squares & board.occupied[!board.side_to_move as usize];
|
|
||||||
while capture_moves > 0 {
|
|
||||||
let from = SQUARES[square_index];
|
|
||||||
let to = SQUARES[capture_moves.trailing_zeros() as usize];
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
capture_moves &= capture_moves - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
friendly_bishops &= friendly_bishops - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_queen_moves(board: &Board, list: &mut MoveList) {
|
|
||||||
let mut friendly_queens = board.pieces[PieceType::Queen as usize][board.side_to_move as usize];
|
|
||||||
while friendly_queens > 0 {
|
|
||||||
let square_index = friendly_queens.trailing_zeros() as usize;
|
|
||||||
|
|
||||||
// --- 1. Get Rook Attacks ---
|
|
||||||
let rook_premask = PREMASKS_ROOK[square_index];
|
|
||||||
let rook_magic = MAGICS_ROOK[square_index];
|
|
||||||
let rook_relevant_bits = RELEVANT_BITS_ROOK[square_index];
|
|
||||||
let rook_shift = 64 - rook_relevant_bits;
|
|
||||||
let rook_blockers = board.all_occupied & rook_premask;
|
|
||||||
let rook_attack_table = get_rook_attacks();
|
|
||||||
let rook_magic_index = (rook_blockers.wrapping_mul(rook_magic)) >> rook_shift;
|
|
||||||
let rook_moves = rook_attack_table[square_index][rook_magic_index as usize];
|
|
||||||
|
|
||||||
// --- 2. Get Bishop Attacks ---
|
|
||||||
let bishop_premask = PREMASKS_BISHOP[square_index];
|
|
||||||
let bishop_magic = MAGICS_BISHOP[square_index];
|
|
||||||
let bishop_relevant_bits = RELEVANT_BITS_BISHOP[square_index];
|
|
||||||
let bishop_shift = 64 - bishop_relevant_bits;
|
|
||||||
let bishop_blockers = board.all_occupied & bishop_premask;
|
|
||||||
let bishop_attack_table = get_bishop_attacks();
|
|
||||||
let bishop_magic_index = (bishop_blockers.wrapping_mul(bishop_magic)) >> bishop_shift;
|
|
||||||
let bishop_moves = bishop_attack_table[square_index][bishop_magic_index as usize];
|
|
||||||
|
|
||||||
// --- 3. Combine Attacks ---
|
|
||||||
let movable_squares = rook_moves | bishop_moves;
|
|
||||||
|
|
||||||
// --- 4. Generate Moves (Identical to Rook/Bishop) ---
|
|
||||||
|
|
||||||
// 4a. Normal moves
|
|
||||||
let mut quiet_moves = movable_squares & !board.all_occupied;
|
|
||||||
while quiet_moves > 0 {
|
|
||||||
let from = SQUARES[square_index];
|
|
||||||
let to = SQUARES[quiet_moves.trailing_zeros() as usize];
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
|
||||||
quiet_moves &= quiet_moves - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4b. Captures
|
|
||||||
let mut capture_moves = movable_squares & board.occupied[!board.side_to_move as usize];
|
|
||||||
while capture_moves > 0 {
|
|
||||||
let from = SQUARES[square_index];
|
|
||||||
let to = SQUARES[capture_moves.trailing_zeros() as usize];
|
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
|
||||||
capture_moves &= capture_moves - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
friendly_queens &= friendly_queens - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
=======
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
@ -1,647 +0,0 @@
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
|
|
||||||
pub const KNIGHT_ATTACKS: [u64; 64] = [
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000010_00000100_00000000, // Square 0 (A1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000101_00001000_00000000, // Square 1 (B1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00001010_00010001_00000000, // Square 2 (C1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00010100_00100010_00000000, // Square 3 (D1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00101000_01000100_00000000, // Square 4 (E1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_01010000_10001000_00000000, // Square 5 (F1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_10100000_00010000_00000000, // Square 6 (G1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_01000000_00100000_00000000, // Square 7 (H1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000010_00000100_00000000_00000100, // Square 8 (A2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000101_00001000_00000000_00001000, // Square 9 (B2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00001010_00010001_00000000_00010001, // Square 10 (C2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00010100_00100010_00000000_00100010, // Square 11 (D2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00101000_01000100_00000000_01000100, // Square 12 (E2)
|
|
||||||
0b00000000_00000000_00000000_00000000_01010000_10001000_00000000_10001000, // Square 13 (F2)
|
|
||||||
0b00000000_00000000_00000000_00000000_10100000_00010000_00000000_00010000, // Square 14 (G2)
|
|
||||||
0b00000000_00000000_00000000_00000000_01000000_00100000_00000000_00100000, // Square 15 (H2)
|
|
||||||
0b00000000_00000000_00000000_00000010_00000100_00000000_00000100_00000010, // Square 16 (A3)
|
|
||||||
0b00000000_00000000_00000000_00000101_00001000_00000000_00001000_00000101, // Square 17 (B3)
|
|
||||||
0b00000000_00000000_00000000_00001010_00010001_00000000_00010001_00001010, // Square 18 (C3)
|
|
||||||
0b00000000_00000000_00000000_00010100_00100010_00000000_00100010_00010100, // Square 19 (D3)
|
|
||||||
0b00000000_00000000_00000000_00101000_01000100_00000000_01000100_00101000, // Square 20 (E3)
|
|
||||||
0b00000000_00000000_00000000_01010000_10001000_00000000_10001000_01010000, // Square 21 (F3)
|
|
||||||
0b00000000_00000000_00000000_10100000_00010000_00000000_00010000_10100000, // Square 22 (G3)
|
|
||||||
0b00000000_00000000_00000000_01000000_00100000_00000000_00100000_01000000, // Square 23 (H3)
|
|
||||||
0b00000000_00000000_00000010_00000100_00000000_00000100_00000010_00000000, // Square 24 (A4)
|
|
||||||
0b00000000_00000000_00000101_00001000_00000000_00001000_00000101_00000000, // Square 25 (B4)
|
|
||||||
0b00000000_00000000_00001010_00010001_00000000_00010001_00001010_00000000, // Square 26 (C4)
|
|
||||||
0b00000000_00000000_00010100_00100010_00000000_00100010_00010100_00000000, // Square 27 (D4)
|
|
||||||
0b00000000_00000000_00101000_01000100_00000000_01000100_00101000_00000000, // Square 28 (E4)
|
|
||||||
0b00000000_00000000_01010000_10001000_00000000_10001000_01010000_00000000, // Square 29 (F4)
|
|
||||||
0b00000000_00000000_10100000_00010000_00000000_00010000_10100000_00000000, // Square 30 (G4)
|
|
||||||
0b00000000_00000000_01000000_00100000_00000000_00100000_01000000_00000000, // Square 31 (H4)
|
|
||||||
0b00000000_00000010_00000100_00000000_00000100_00000010_00000000_00000000, // Square 32 (A5)
|
|
||||||
0b00000000_00000101_00001000_00000000_00001000_00000101_00000000_00000000, // Square 33 (B5)
|
|
||||||
0b00000000_00001010_00010001_00000000_00010001_00001010_00000000_00000000, // Square 34 (C5)
|
|
||||||
0b00000000_00010100_00100010_00000000_00100010_00010100_00000000_00000000, // Square 35 (D5)
|
|
||||||
0b00000000_00101000_01000100_00000000_01000100_00101000_00000000_00000000, // Square 36 (E5)
|
|
||||||
0b00000000_01010000_10001000_00000000_10001000_01010000_00000000_00000000, // Square 37 (F5)
|
|
||||||
0b00000000_10100000_00010000_00000000_00010000_10100000_00000000_00000000, // Square 38 (G5)
|
|
||||||
0b00000000_01000000_00100000_00000000_00100000_01000000_00000000_00000000, // Square 39 (H5)
|
|
||||||
0b00000010_00000100_00000000_00000100_00000010_00000000_00000000_00000000, // Square 40 (A6)
|
|
||||||
0b00000101_00001000_00000000_00001000_00000101_00000000_00000000_00000000, // Square 41 (B6)
|
|
||||||
0b00001010_00010001_00000000_00010001_00001010_00000000_00000000_00000000, // Square 42 (C6)
|
|
||||||
0b00010100_00100010_00000000_00100010_00010100_00000000_00000000_00000000, // Square 43 (D6)
|
|
||||||
0b00101000_01000100_00000000_01000100_00101000_00000000_00000000_00000000, // Square 44 (E6)
|
|
||||||
0b01010000_10001000_00000000_10001000_01010000_00000000_00000000_00000000, // Square 45 (F6)
|
|
||||||
0b10100000_00010000_00000000_00010000_10100000_00000000_00000000_00000000, // Square 46 (G6)
|
|
||||||
0b01000000_00100000_00000000_00100000_01000000_00000000_00000000_00000000, // Square 47 (H6)
|
|
||||||
0b00000100_00000000_00000100_00000010_00000000_00000000_00000000_00000000, // Square 48 (A7)
|
|
||||||
0b00001000_00000000_00001000_00000101_00000000_00000000_00000000_00000000, // Square 49 (B7)
|
|
||||||
0b00010001_00000000_00010001_00001010_00000000_00000000_00000000_00000000, // Square 50 (C7)
|
|
||||||
0b00100010_00000000_00100010_00010100_00000000_00000000_00000000_00000000, // Square 51 (D7)
|
|
||||||
0b01000100_00000000_01000100_00101000_00000000_00000000_00000000_00000000, // Square 52 (E7)
|
|
||||||
0b10001000_00000000_10001000_01010000_00000000_00000000_00000000_00000000, // Square 53 (F7)
|
|
||||||
0b00010000_00000000_00010000_10100000_00000000_00000000_00000000_00000000, // Square 54 (G7)
|
|
||||||
0b00100000_00000000_00100000_01000000_00000000_00000000_00000000_00000000, // Square 55 (H7)
|
|
||||||
0b00000000_00000100_00000010_00000000_00000000_00000000_00000000_00000000, // Square 56 (A8)
|
|
||||||
0b00000000_00001000_00000101_00000000_00000000_00000000_00000000_00000000, // Square 57 (B8)
|
|
||||||
0b00000000_00010001_00001010_00000000_00000000_00000000_00000000_00000000, // Square 58 (C8)
|
|
||||||
0b00000000_00100010_00010100_00000000_00000000_00000000_00000000_00000000, // Square 59 (D8)
|
|
||||||
0b00000000_01000100_00101000_00000000_00000000_00000000_00000000_00000000, // Square 60 (E8)
|
|
||||||
0b00000000_10001000_01010000_00000000_00000000_00000000_00000000_00000000, // Square 61 (F8)
|
|
||||||
0b00000000_00010000_10100000_00000000_00000000_00000000_00000000_00000000, // Square 62 (G8)
|
|
||||||
0b00000000_00100000_01000000_00000000_00000000_00000000_00000000_00000000, // Square 63 (H8)
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const PREMASKS_ROOK: [u64; 64] = [
|
|
||||||
0b00000000_00000001_00000001_00000001_00000001_00000001_00000001_01111110, // Square 0 (A1)
|
|
||||||
0b00000000_00000010_00000010_00000010_00000010_00000010_00000010_01111100, // Square 1 (B1)
|
|
||||||
0b00000000_00000100_00000100_00000100_00000100_00000100_00000100_01111010, // Square 2 (C1)
|
|
||||||
0b00000000_00001000_00001000_00001000_00001000_00001000_00001000_01110110, // Square 3 (D1)
|
|
||||||
0b00000000_00010000_00010000_00010000_00010000_00010000_00010000_01101110, // Square 4 (E1)
|
|
||||||
0b00000000_00100000_00100000_00100000_00100000_00100000_00100000_01011110, // Square 5 (F1)
|
|
||||||
0b00000000_01000000_01000000_01000000_01000000_01000000_01000000_00111110, // Square 6 (G1)
|
|
||||||
0b00000000_10000000_10000000_10000000_10000000_10000000_10000000_01111110, // Square 7 (H1)
|
|
||||||
0b00000000_00000001_00000001_00000001_00000001_00000001_01111110_00000000, // Square 8 (A2)
|
|
||||||
0b00000000_00000010_00000010_00000010_00000010_00000010_01111100_00000000, // Square 9 (B2)
|
|
||||||
0b00000000_00000100_00000100_00000100_00000100_00000100_01111010_00000000, // Square 10 (C2)
|
|
||||||
0b00000000_00001000_00001000_00001000_00001000_00001000_01110110_00000000, // Square 11 (D2)
|
|
||||||
0b00000000_00010000_00010000_00010000_00010000_00010000_01101110_00000000, // Square 12 (E2)
|
|
||||||
0b00000000_00100000_00100000_00100000_00100000_00100000_01011110_00000000, // Square 13 (F2)
|
|
||||||
0b00000000_01000000_01000000_01000000_01000000_01000000_00111110_00000000, // Square 14 (G2)
|
|
||||||
0b00000000_10000000_10000000_10000000_10000000_10000000_01111110_00000000, // Square 15 (H2)
|
|
||||||
0b00000000_00000001_00000001_00000001_00000001_01111110_00000001_00000000, // Square 16 (A3)
|
|
||||||
0b00000000_00000010_00000010_00000010_00000010_01111100_00000010_00000000, // Square 17 (B3)
|
|
||||||
0b00000000_00000100_00000100_00000100_00000100_01111010_00000100_00000000, // Square 18 (C3)
|
|
||||||
0b00000000_00001000_00001000_00001000_00001000_01110110_00001000_00000000, // Square 19 (D3)
|
|
||||||
0b00000000_00010000_00010000_00010000_00010000_01101110_00010000_00000000, // Square 20 (E3)
|
|
||||||
0b00000000_00100000_00100000_00100000_00100000_01011110_00100000_00000000, // Square 21 (F3)
|
|
||||||
0b00000000_01000000_01000000_01000000_01000000_00111110_01000000_00000000, // Square 22 (G3)
|
|
||||||
0b00000000_10000000_10000000_10000000_10000000_01111110_10000000_00000000, // Square 23 (H3)
|
|
||||||
0b00000000_00000001_00000001_00000001_01111110_00000001_00000001_00000000, // Square 24 (A4)
|
|
||||||
0b00000000_00000010_00000010_00000010_01111100_00000010_00000010_00000000, // Square 25 (B4)
|
|
||||||
0b00000000_00000100_00000100_00000100_01111010_00000100_00000100_00000000, // Square 26 (C4)
|
|
||||||
0b00000000_00001000_00001000_00001000_01110110_00001000_00001000_00000000, // Square 27 (D4)
|
|
||||||
0b00000000_00010000_00010000_00010000_01101110_00010000_00010000_00000000, // Square 28 (E4)
|
|
||||||
0b00000000_00100000_00100000_00100000_01011110_00100000_00100000_00000000, // Square 29 (F4)
|
|
||||||
0b00000000_01000000_01000000_01000000_00111110_01000000_01000000_00000000, // Square 30 (G4)
|
|
||||||
0b00000000_10000000_10000000_10000000_01111110_10000000_10000000_00000000, // Square 31 (H4)
|
|
||||||
0b00000000_00000001_00000001_01111110_00000001_00000001_00000001_00000000, // Square 32 (A5)
|
|
||||||
0b00000000_00000010_00000010_01111100_00000010_00000010_00000010_00000000, // Square 33 (B5)
|
|
||||||
0b00000000_00000100_00000100_01111010_00000100_00000100_00000100_00000000, // Square 34 (C5)
|
|
||||||
0b00000000_00001000_00001000_01110110_00001000_00001000_00001000_00000000, // Square 35 (D5)
|
|
||||||
0b00000000_00010000_00010000_01101110_00010000_00010000_00010000_00000000, // Square 36 (E5)
|
|
||||||
0b00000000_00100000_00100000_01011110_00100000_00100000_00100000_00000000, // Square 37 (F5)
|
|
||||||
0b00000000_01000000_01000000_00111110_01000000_01000000_01000000_00000000, // Square 38 (G5)
|
|
||||||
0b00000000_10000000_10000000_01111110_10000000_10000000_10000000_00000000, // Square 39 (H5)
|
|
||||||
0b00000000_00000001_01111110_00000001_00000001_00000001_00000001_00000000, // Square 40 (A6)
|
|
||||||
0b00000000_00000010_01111100_00000010_00000010_00000010_00000010_00000000, // Square 41 (B6)
|
|
||||||
0b00000000_00000100_01111010_00000100_00000100_00000100_00000100_00000000, // Square 42 (C6)
|
|
||||||
0b00000000_00001000_01110110_00001000_00001000_00001000_00001000_00000000, // Square 43 (D6)
|
|
||||||
0b00000000_00010000_01101110_00010000_00010000_00010000_00010000_00000000, // Square 44 (E6)
|
|
||||||
0b00000000_00100000_01011110_00100000_00100000_00100000_00100000_00000000, // Square 45 (F6)
|
|
||||||
0b00000000_01000000_00111110_01000000_01000000_01000000_01000000_00000000, // Square 46 (G6)
|
|
||||||
0b00000000_10000000_01111110_10000000_10000000_10000000_10000000_00000000, // Square 47 (H6)
|
|
||||||
0b00000000_01111110_00000001_00000001_00000001_00000001_00000001_00000000, // Square 48 (A7)
|
|
||||||
0b00000000_01111100_00000010_00000010_00000010_00000010_00000010_00000000, // Square 49 (B7)
|
|
||||||
0b00000000_01111010_00000100_00000100_00000100_00000100_00000100_00000000, // Square 50 (C7)
|
|
||||||
0b00000000_01110110_00001000_00001000_00001000_00001000_00001000_00000000, // Square 51 (D7)
|
|
||||||
0b00000000_01101110_00010000_00010000_00010000_00010000_00010000_00000000, // Square 52 (E7)
|
|
||||||
0b00000000_01011110_00100000_00100000_00100000_00100000_00100000_00000000, // Square 53 (F7)
|
|
||||||
0b00000000_00111110_01000000_01000000_01000000_01000000_01000000_00000000, // Square 54 (G7)
|
|
||||||
0b00000000_01111110_10000000_10000000_10000000_10000000_10000000_00000000, // Square 55 (H7)
|
|
||||||
0b01111110_00000001_00000001_00000001_00000001_00000001_00000001_00000000, // Square 56 (A8)
|
|
||||||
0b01111100_00000010_00000010_00000010_00000010_00000010_00000010_00000000, // Square 57 (B8)
|
|
||||||
0b01111010_00000100_00000100_00000100_00000100_00000100_00000100_00000000, // Square 58 (C8)
|
|
||||||
0b01110110_00001000_00001000_00001000_00001000_00001000_00001000_00000000, // Square 59 (D8)
|
|
||||||
0b01101110_00010000_00010000_00010000_00010000_00010000_00010000_00000000, // Square 60 (E8)
|
|
||||||
0b01011110_00100000_00100000_00100000_00100000_00100000_00100000_00000000, // Square 61 (F8)
|
|
||||||
0b00111110_01000000_01000000_01000000_01000000_01000000_01000000_00000000, // Square 62 (G8)
|
|
||||||
0b01111110_10000000_10000000_10000000_10000000_10000000_10000000_00000000, // Square 63 (H8)
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const PREMASKS_BISHOP: [u64; 64] = [
|
|
||||||
0b00000000_01000000_00100000_00010000_00001000_00000100_00000010_00000000, // Square 0 (A1)
|
|
||||||
0b00000000_00000000_01000000_00100000_00010000_00001000_00000100_00000000, // Square 1 (B1)
|
|
||||||
0b00000000_00000000_00000000_01000000_00100000_00010000_00001010_00000000, // Square 2 (C1)
|
|
||||||
0b00000000_00000000_00000000_00000000_01000000_00100010_00010100_00000000, // Square 3 (D1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000010_01000100_00101000_00000000, // Square 4 (E1)
|
|
||||||
0b00000000_00000000_00000000_00000010_00000100_00001000_01010000_00000000, // Square 5 (F1)
|
|
||||||
0b00000000_00000000_00000010_00000100_00001000_00010000_00100000_00000000, // Square 6 (G1)
|
|
||||||
0b00000000_00000010_00000100_00001000_00010000_00100000_01000000_00000000, // Square 7 (H1)
|
|
||||||
0b00000000_00100000_00010000_00001000_00000100_00000010_00000000_00000000, // Square 8 (A2)
|
|
||||||
0b00000000_01000000_00100000_00010000_00001000_00000100_00000000_00000000, // Square 9 (B2)
|
|
||||||
0b00000000_00000000_01000000_00100000_00010000_00001010_00000000_00000000, // Square 10 (C2)
|
|
||||||
0b00000000_00000000_00000000_01000000_00100010_00010100_00000000_00000000, // Square 11 (D2)
|
|
||||||
0b00000000_00000000_00000000_00000010_01000100_00101000_00000000_00000000, // Square 12 (E2)
|
|
||||||
0b00000000_00000000_00000010_00000100_00001000_01010000_00000000_00000000, // Square 13 (F2)
|
|
||||||
0b00000000_00000010_00000100_00001000_00010000_00100000_00000000_00000000, // Square 14 (G2)
|
|
||||||
0b00000000_00000100_00001000_00010000_00100000_01000000_00000000_00000000, // Square 15 (H2)
|
|
||||||
0b00000000_00010000_00001000_00000100_00000010_00000000_00000010_00000000, // Square 16 (A3)
|
|
||||||
0b00000000_00100000_00010000_00001000_00000100_00000000_00000100_00000000, // Square 17 (B3)
|
|
||||||
0b00000000_01000000_00100000_00010000_00001010_00000000_00001010_00000000, // Square 18 (C3)
|
|
||||||
0b00000000_00000000_01000000_00100010_00010100_00000000_00010100_00000000, // Square 19 (D3)
|
|
||||||
0b00000000_00000000_00000010_01000100_00101000_00000000_00101000_00000000, // Square 20 (E3)
|
|
||||||
0b00000000_00000010_00000100_00001000_01010000_00000000_01010000_00000000, // Square 21 (F3)
|
|
||||||
0b00000000_00000100_00001000_00010000_00100000_00000000_00100000_00000000, // Square 22 (G3)
|
|
||||||
0b00000000_00001000_00010000_00100000_01000000_00000000_01000000_00000000, // Square 23 (H3)
|
|
||||||
0b00000000_00001000_00000100_00000010_00000000_00000010_00000100_00000000, // Square 24 (A4)
|
|
||||||
0b00000000_00010000_00001000_00000100_00000000_00000100_00001000_00000000, // Square 25 (B4)
|
|
||||||
0b00000000_00100000_00010000_00001010_00000000_00001010_00010000_00000000, // Square 26 (C4)
|
|
||||||
0b00000000_01000000_00100010_00010100_00000000_00010100_00100010_00000000, // Square 27 (D4)
|
|
||||||
0b00000000_00000010_01000100_00101000_00000000_00101000_01000100_00000000, // Square 28 (E4)
|
|
||||||
0b00000000_00000100_00001000_01010000_00000000_01010000_00001000_00000000, // Square 29 (F4)
|
|
||||||
0b00000000_00001000_00010000_00100000_00000000_00100000_00010000_00000000, // Square 30 (G4)
|
|
||||||
0b00000000_00010000_00100000_01000000_00000000_01000000_00100000_00000000, // Square 31 (H4)
|
|
||||||
0b00000000_00000100_00000010_00000000_00000010_00000100_00001000_00000000, // Square 32 (A5)
|
|
||||||
0b00000000_00001000_00000100_00000000_00000100_00001000_00010000_00000000, // Square 33 (B5)
|
|
||||||
0b00000000_00010000_00001010_00000000_00001010_00010000_00100000_00000000, // Square 34 (C5)
|
|
||||||
0b00000000_00100010_00010100_00000000_00010100_00100010_01000000_00000000, // Square 35 (D5)
|
|
||||||
0b00000000_01000100_00101000_00000000_00101000_01000100_00000010_00000000, // Square 36 (E5)
|
|
||||||
0b00000000_00001000_01010000_00000000_01010000_00001000_00000100_00000000, // Square 37 (F5)
|
|
||||||
0b00000000_00010000_00100000_00000000_00100000_00010000_00001000_00000000, // Square 38 (G5)
|
|
||||||
0b00000000_00100000_01000000_00000000_01000000_00100000_00010000_00000000, // Square 39 (H5)
|
|
||||||
0b00000000_00000010_00000000_00000010_00000100_00001000_00010000_00000000, // Square 40 (A6)
|
|
||||||
0b00000000_00000100_00000000_00000100_00001000_00010000_00100000_00000000, // Square 41 (B6)
|
|
||||||
0b00000000_00001010_00000000_00001010_00010000_00100000_01000000_00000000, // Square 42 (C6)
|
|
||||||
0b00000000_00010100_00000000_00010100_00100010_01000000_00000000_00000000, // Square 43 (D6)
|
|
||||||
0b00000000_00101000_00000000_00101000_01000100_00000010_00000000_00000000, // Square 44 (E6)
|
|
||||||
0b00000000_01010000_00000000_01010000_00001000_00000100_00000010_00000000, // Square 45 (F6)
|
|
||||||
0b00000000_00100000_00000000_00100000_00010000_00001000_00000100_00000000, // Square 46 (G6)
|
|
||||||
0b00000000_01000000_00000000_01000000_00100000_00010000_00001000_00000000, // Square 47 (H6)
|
|
||||||
0b00000000_00000000_00000010_00000100_00001000_00010000_00100000_00000000, // Square 48 (A7)
|
|
||||||
0b00000000_00000000_00000100_00001000_00010000_00100000_01000000_00000000, // Square 49 (B7)
|
|
||||||
0b00000000_00000000_00001010_00010000_00100000_01000000_00000000_00000000, // Square 50 (C7)
|
|
||||||
0b00000000_00000000_00010100_00100010_01000000_00000000_00000000_00000000, // Square 51 (D7)
|
|
||||||
0b00000000_00000000_00101000_01000100_00000010_00000000_00000000_00000000, // Square 52 (E7)
|
|
||||||
0b00000000_00000000_01010000_00001000_00000100_00000010_00000000_00000000, // Square 53 (F7)
|
|
||||||
0b00000000_00000000_00100000_00010000_00001000_00000100_00000010_00000000, // Square 54 (G7)
|
|
||||||
0b00000000_00000000_01000000_00100000_00010000_00001000_00000100_00000000, // Square 55 (H7)
|
|
||||||
0b00000000_00000010_00000100_00001000_00010000_00100000_01000000_00000000, // Square 56 (A8)
|
|
||||||
0b00000000_00000100_00001000_00010000_00100000_01000000_00000000_00000000, // Square 57 (B8)
|
|
||||||
0b00000000_00001010_00010000_00100000_01000000_00000000_00000000_00000000, // Square 58 (C8)
|
|
||||||
0b00000000_00010100_00100010_01000000_00000000_00000000_00000000_00000000, // Square 59 (D8)
|
|
||||||
0b00000000_00101000_01000100_00000010_00000000_00000000_00000000_00000000, // Square 60 (E8)
|
|
||||||
0b00000000_01010000_00001000_00000100_00000010_00000000_00000000_00000000, // Square 61 (F8)
|
|
||||||
0b00000000_00100000_00010000_00001000_00000100_00000010_00000000_00000000, // Square 62 (G8)
|
|
||||||
0b00000000_01000000_00100000_00010000_00001000_00000100_00000010_00000000, // Square 63 (H8)
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const KING_ATTACKS: [u64; 64] = [
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00000011_00000010, // Square 0 (A1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00000111_00000101, // Square 1 (B1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00001110_00001010, // Square 2 (C1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00011100_00010100, // Square 3 (D1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00111000_00101000, // Square 4 (E1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_01110000_01010000, // Square 5 (F1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_11100000_10100000, // Square 6 (G1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000000_11000000_01000000, // Square 7 (H1)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000011_00000010_00000011, // Square 8 (A2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00000111_00000101_00000111, // Square 9 (B2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00001110_00001010_00001110, // Square 10 (C2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00011100_00010100_00011100, // Square 11 (D2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_00111000_00101000_00111000, // Square 12 (E2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_01110000_01010000_01110000, // Square 13 (F2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_11100000_10100000_11100000, // Square 14 (G2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000000_11000000_01000000_11000000, // Square 15 (H2)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000011_00000010_00000011_00000000, // Square 16 (A3)
|
|
||||||
0b00000000_00000000_00000000_00000000_00000111_00000101_00000111_00000000, // Square 17 (B3)
|
|
||||||
0b00000000_00000000_00000000_00000000_00001110_00001010_00001110_00000000, // Square 18 (C3)
|
|
||||||
0b00000000_00000000_00000000_00000000_00011100_00010100_00011100_00000000, // Square 19 (D3)
|
|
||||||
0b00000000_00000000_00000000_00000000_00111000_00101000_00111000_00000000, // Square 20 (E3)
|
|
||||||
0b00000000_00000000_00000000_00000000_01110000_01010000_01110000_00000000, // Square 21 (F3)
|
|
||||||
0b00000000_00000000_00000000_00000000_11100000_10100000_11100000_00000000, // Square 22 (G3)
|
|
||||||
0b00000000_00000000_00000000_00000000_11000000_01000000_11000000_00000000, // Square 23 (H3)
|
|
||||||
0b00000000_00000000_00000000_00000011_00000010_00000011_00000000_00000000, // Square 24 (A4)
|
|
||||||
0b00000000_00000000_00000000_00000111_00000101_00000111_00000000_00000000, // Square 25 (B4)
|
|
||||||
0b00000000_00000000_00000000_00001110_00001010_00001110_00000000_00000000, // Square 26 (C4)
|
|
||||||
0b00000000_00000000_00000000_00011100_00010100_00011100_00000000_00000000, // Square 27 (D4)
|
|
||||||
0b00000000_00000000_00000000_00111000_00101000_00111000_00000000_00000000, // Square 28 (E4)
|
|
||||||
0b00000000_00000000_00000000_01110000_01010000_01110000_00000000_00000000, // Square 29 (F4)
|
|
||||||
0b00000000_00000000_00000000_11100000_10100000_11100000_00000000_00000000, // Square 30 (G4)
|
|
||||||
0b00000000_00000000_00000000_11000000_01000000_11000000_00000000_00000000, // Square 31 (H4)
|
|
||||||
0b00000000_00000000_00000011_00000010_00000011_00000000_00000000_00000000, // Square 32 (A5)
|
|
||||||
0b00000000_00000000_00000111_00000101_00000111_00000000_00000000_00000000, // Square 33 (B5)
|
|
||||||
0b00000000_00000000_00001110_00001010_00001110_00000000_00000000_00000000, // Square 34 (C5)
|
|
||||||
0b00000000_00000000_00011100_00010100_00011100_00000000_00000000_00000000, // Square 35 (D5)
|
|
||||||
0b00000000_00000000_00111000_00101000_00111000_00000000_00000000_00000000, // Square 36 (E5)
|
|
||||||
0b00000000_00000000_01110000_01010000_01110000_00000000_00000000_00000000, // Square 37 (F5)
|
|
||||||
0b00000000_00000000_11100000_10100000_11100000_00000000_00000000_00000000, // Square 38 (G5)
|
|
||||||
0b00000000_00000000_11000000_01000000_11000000_00000000_00000000_00000000, // Square 39 (H5)
|
|
||||||
0b00000000_00000011_00000010_00000011_00000000_00000000_00000000_00000000, // Square 40 (A6)
|
|
||||||
0b00000000_00000111_00000101_00000111_00000000_00000000_00000000_00000000, // Square 41 (B6)
|
|
||||||
0b00000000_00001110_00001010_00001110_00000000_00000000_00000000_00000000, // Square 42 (C6)
|
|
||||||
0b00000000_00011100_00010100_00011100_00000000_00000000_00000000_00000000, // Square 43 (D6)
|
|
||||||
0b00000000_00111000_00101000_00111000_00000000_00000000_00000000_00000000, // Square 44 (E6)
|
|
||||||
0b00000000_01110000_01010000_01110000_00000000_00000000_00000000_00000000, // Square 45 (F6)
|
|
||||||
0b00000000_11100000_10100000_11100000_00000000_00000000_00000000_00000000, // Square 46 (G6)
|
|
||||||
0b00000000_11000000_01000000_11000000_00000000_00000000_00000000_00000000, // Square 47 (H6)
|
|
||||||
0b00000011_00000010_00000011_00000000_00000000_00000000_00000000_00000000, // Square 48 (A7)
|
|
||||||
0b00000111_00000101_00000111_00000000_00000000_00000000_00000000_00000000, // Square 49 (B7)
|
|
||||||
0b00001110_00001010_00001110_00000000_00000000_00000000_00000000_00000000, // Square 50 (C7)
|
|
||||||
0b00011100_00010100_00011100_00000000_00000000_00000000_00000000_00000000, // Square 51 (D7)
|
|
||||||
0b00111000_00101000_00111000_00000000_00000000_00000000_00000000_00000000, // Square 52 (E7)
|
|
||||||
0b01110000_01010000_01110000_00000000_00000000_00000000_00000000_00000000, // Square 53 (F7)
|
|
||||||
0b11100000_10100000_11100000_00000000_00000000_00000000_00000000_00000000, // Square 54 (G7)
|
|
||||||
0b11000000_01000000_11000000_00000000_00000000_00000000_00000000_00000000, // Square 55 (H7)
|
|
||||||
0b00000010_00000011_00000000_00000000_00000000_00000000_00000000_00000000, // Square 56 (A8)
|
|
||||||
0b00000101_00000111_00000000_00000000_00000000_00000000_00000000_00000000, // Square 57 (B8)
|
|
||||||
0b00001010_00001110_00000000_00000000_00000000_00000000_00000000_00000000, // Square 58 (C8)
|
|
||||||
0b00010100_00011100_00000000_00000000_00000000_00000000_00000000_00000000, // Square 59 (D8)
|
|
||||||
0b00101000_00111000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 60 (E8)
|
|
||||||
0b01010000_01110000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 61 (F8)
|
|
||||||
0b10100000_11100000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 62 (G8)
|
|
||||||
0b01000000_11000000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 63 (H8)
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const MAGICS_ROOK: [u64; 64] = [
|
|
||||||
0b10001010_10000000_00010000_01000000_00000000_10000000_00000000_00100000, // Square 0 (A1)
|
|
||||||
0b00000001_01000000_00000000_00100000_00000000_00010000_00000000_01000000, // Square 1 (B1)
|
|
||||||
0b00000010_10000000_00011000_10000000_10100000_00000001_01110000_00000001, // Square 2 (C1)
|
|
||||||
0b00000001_00000000_00001000_00010000_00000001_00000000_00000100_00100000, // Square 3 (D1)
|
|
||||||
0b00000010_00000000_00000010_00000000_00010000_00001000_00000100_00100000, // Square 4 (E1)
|
|
||||||
0b00000011_00000000_00011100_00000000_00000010_00000001_00000000_00001000, // Square 5 (F1)
|
|
||||||
0b10000100_10000000_00000000_10000000_00000010_00000000_00000001_00000000, // Square 6 (G1)
|
|
||||||
0b00100000_10000000_00001000_10000000_00000100_01000000_00101001_00000000, // Square 7 (H1)
|
|
||||||
0b00000000_00000000_10000000_00000000_10011000_00100000_01000000_00000000, // Square 8 (A2)
|
|
||||||
0b00100000_00100100_01000000_00010000_00000000_00100000_00000000_01000000, // Square 9 (B2)
|
|
||||||
0b00000001_00000000_10000000_00100000_00000000_10000000_00010000_00000000, // Square 10 (C2)
|
|
||||||
0b00000001_00100000_10000000_00001000_00000000_10000000_00010000_00000000, // Square 11 (D2)
|
|
||||||
0b00000010_00001000_10000000_10000000_10001000_00000000_00000100_00000000, // Square 12 (E2)
|
|
||||||
0b00000000_00000010_10000000_00100010_00000000_10000000_00000100_00000000, // Square 13 (F2)
|
|
||||||
0b00100010_00000000_10000000_00000001_00000000_00000010_00000000_10000000, // Square 14 (G2)
|
|
||||||
0b00001000_00000001_00000000_00000000_01100000_10000010_00010001_00000000, // Square 15 (H2)
|
|
||||||
0b00000000_10000000_00000100_01000000_00000110_01000010_00100000_00000000, // Square 16 (A3)
|
|
||||||
0b00000001_00000000_10000000_10000000_00100000_00000000_01000000_00000000, // Square 17 (B3)
|
|
||||||
0b00010010_00010000_10001010_00000000_00010000_00100000_01000010_00000000, // Square 18 (C3)
|
|
||||||
0b00000001_01000000_10000100_10000000_00010000_00000000_00001000_00000010, // Square 19 (D3)
|
|
||||||
0b00000100_10000001_10000010_10000000_00010100_00000000_00101000_00000000, // Square 20 (E3)
|
|
||||||
0b10000000_10010100_00000000_01000000_00000010_00000000_01000001_00000000, // Square 21 (F3)
|
|
||||||
0b01000000_00010000_00000100_00000000_00010000_00000001_00001000_00000010, // Square 22 (G3)
|
|
||||||
0b00000000_00000000_00000010_00000000_00001000_10000000_01100001_00000100, // Square 23 (H3)
|
|
||||||
0b00000001_00000000_01000000_00000000_10000000_00100000_10000000_00000000, // Square 24 (A4)
|
|
||||||
0b00100000_01000000_00000000_00100001_00100000_00001000_00010000_00000000, // Square 25 (B4)
|
|
||||||
0b00000000_00100001_00100000_00000110_10000000_00010000_00000000_10000001, // Square 26 (C4)
|
|
||||||
0b00000000_00100000_00010000_00000000_10000000_00001000_00000000_10000000, // Square 27 (D4)
|
|
||||||
0b00000000_00000010_00000000_00001010_00000000_00100000_00000100_00010000, // Square 28 (E4)
|
|
||||||
0b00000000_00000000_00000010_00000000_10000000_10000000_00000100_00000000, // Square 29 (F4)
|
|
||||||
0b00000000_10000000_00001000_10000100_00000000_00010000_00000001_00000010, // Square 30 (G4)
|
|
||||||
0b00000000_10000000_00000000_01000110_00000000_00000100_00101000_10000001, // Square 31 (H4)
|
|
||||||
0b01000000_01000000_00000000_10000000_01000000_10000000_00000000_00100000, // Square 32 (A5)
|
|
||||||
0b00000100_01000000_00000000_00110000_00000000_00100000_00001000_00000001, // Square 33 (B5)
|
|
||||||
0b00000000_00000100_00100000_00000000_00010001_00000000_01000101_00000000, // Square 34 (C5)
|
|
||||||
0b00000001_10001000_00000010_00000000_00010000_00010000_00000001_00000000, // Square 35 (D5)
|
|
||||||
0b00000000_00010100_10000000_00000100_00000001_10000000_00101000_00000000, // Square 36 (E5)
|
|
||||||
0b00100000_10000000_00000100_00000000_10000000_10000000_00000010_00000000, // Square 37 (F5)
|
|
||||||
0b00000001_00100100_00001000_00000010_00000100_00000000_00010000_00000001, // Square 38 (G5)
|
|
||||||
0b00000010_00000000_00000100_01100101_00000010_00000000_00000100_10000100, // Square 39 (H5)
|
|
||||||
0b00000100_10000000_01000000_00000000_10000000_00001000_10000000_00100000, // Square 40 (A6)
|
|
||||||
0b00010000_00000000_01000010_00100000_00010000_00000011_01000000_00000000, // Square 41 (B6)
|
|
||||||
0b00000000_00110000_00100000_00000001_00000000_00010001_00000000_01000000, // Square 42 (C6)
|
|
||||||
0b00000000_00000000_00010000_00000000_00100001_00000001_00000000_00001001, // Square 43 (D6)
|
|
||||||
0b00100000_00000010_00001000_00000001_00000000_00010001_00000000_00000100, // Square 44 (E6)
|
|
||||||
0b00000010_00000010_00000000_10000000_00000100_00000000_10000000_00000010, // Square 45 (F6)
|
|
||||||
0b00000000_00100000_00000010_00000000_00000100_00000001_00000001_00000000, // Square 46 (G6)
|
|
||||||
0b00100000_01001000_01000100_00000000_01000000_10000010_00000000_00000001, // Square 47 (H6)
|
|
||||||
0b00000001_00000001_00000000_00100010_00000000_01000000_10000010_00000000, // Square 48 (A7)
|
|
||||||
0b00000000_01000000_10000000_00100000_00000000_01000000_00010000_10000000, // Square 49 (B7)
|
|
||||||
0b01000000_00001000_00010100_00100000_00000100_01000001_00000001_00000000, // Square 50 (C7)
|
|
||||||
0b00000010_00000110_00001000_00100000_11000000_00010010_00000010_00000000, // Square 51 (D7)
|
|
||||||
0b00000000_00000001_00000000_00010000_00000100_00001000_00000001_00000000, // Square 52 (E7)
|
|
||||||
0b00000010_00001100_00000010_00000000_10000000_00000100_00000000_10000000, // Square 53 (F7)
|
|
||||||
0b00101001_00110101_01100001_00001000_00110000_00000010_00100100_00000000, // Square 54 (G7)
|
|
||||||
0b00000000_01000100_01000100_00000000_01000001_00000000_10010010_00000000, // Square 55 (H7)
|
|
||||||
0b00000010_10000000_00000000_00010000_01000000_10000000_00100001_00000001, // Square 56 (A8)
|
|
||||||
0b00100001_00000000_00011001_00000000_01000000_00000000_00100000_10000101, // Square 57 (B8)
|
|
||||||
0b10000000_11000000_00001000_01000001_00000000_00010000_00100000_00000001, // Square 58 (C8)
|
|
||||||
0b01000000_00100100_00001000_00010000_00000001_00000000_00000100_00100001, // Square 59 (D8)
|
|
||||||
0b00000000_00000010_00000000_00110000_10100000_00100100_01001000_01110010, // Square 60 (E8)
|
|
||||||
0b00000000_00010010_00000000_00010000_00001000_01000001_01000100_00000010, // Square 61 (F8)
|
|
||||||
0b00000010_00000000_01100001_00000100_10010000_00001010_00001000_00000100, // Square 62 (G8)
|
|
||||||
0b00000000_00000001_00000000_01000000_10000001_00000000_00100100_00000010, // Square 63 (H8)
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const MAGICS_BISHOP: [u64; 64] = [
|
|
||||||
0b00000000_01000000_00000100_00001000_01000100_01000000_01000000_10000100, // Square 0 (A1)
|
|
||||||
0b00000000_00100000_00000100_00100000_10001010_00000000_01000010_00001000, // Square 1 (B1)
|
|
||||||
0b00000000_00010000_00011001_00000000_01000001_00001000_00000010_00000010, // Square 2 (C1)
|
|
||||||
0b00000001_00001000_00000110_00001000_01000101_00000100_00100000_00010000, // Square 3 (D1)
|
|
||||||
0b00000101_10000001_00010000_01000001_10000000_10000000_00000010_00010000, // Square 4 (E1)
|
|
||||||
0b00100001_00010010_00001000_00000100_01000110_00100000_00000000_00010000, // Square 5 (F1)
|
|
||||||
0b00010000_10000000_10000010_00001000_00100000_00000110_00000010_00010000, // Square 6 (G1)
|
|
||||||
0b00000011_11000000_10000000_10000100_00010000_00100010_00000010_00000000, // Square 7 (H1)
|
|
||||||
0b00000000_00000100_00000101_00000100_00000100_01000100_00000100_00000100, // Square 8 (A2)
|
|
||||||
0b00000000_00000000_00000010_00010000_00000001_01000010_00000000_10001000, // Square 9 (B2)
|
|
||||||
0b00100100_11010000_00001000_00001000_00000001_00001000_00100001_00000010, // Square 10 (C2)
|
|
||||||
0b00000000_00000001_00000010_00001010_00001010_00000010_00000100_00000000, // Square 11 (D2)
|
|
||||||
0b00000000_00000000_00000100_00000011_00001000_00100000_00000100_00000010, // Square 12 (E2)
|
|
||||||
0b00000000_00000100_00000001_00010000_00000010_00010000_00001000_00000000, // Square 13 (F2)
|
|
||||||
0b00000100_00000001_01001000_01000001_00000100_00010000_01000000_00000101, // Square 14 (G2)
|
|
||||||
0b00001000_00000001_00000001_00000100_00000010_00000010_00000010_00000000, // Square 15 (H2)
|
|
||||||
0b00000000_01000000_00000010_00010000_11000011_10001000_00000001_00000000, // Square 16 (A3)
|
|
||||||
0b00000100_00000100_00000010_00100000_00100100_00010000_10000010_00000000, // Square 17 (B3)
|
|
||||||
0b00001000_00010000_00000001_10000010_00000000_00100000_01000001_00000010, // Square 18 (C3)
|
|
||||||
0b00000000_00000100_00000000_00101000_00000001_10100000_00100000_00000011, // Square 19 (D3)
|
|
||||||
0b00000000_10000101_00000100_00001000_00100000_00001000_00000100_00000000, // Square 20 (E3)
|
|
||||||
0b10000001_00000001_00000010_11001000_00001000_10001000_00000100_00000000, // Square 21 (F3)
|
|
||||||
0b00000000_00001110_10010000_00000100_00010000_10001000_01001000_00000000, // Square 22 (G3)
|
|
||||||
0b10000000_00000010_00000010_00000100_10000000_10000100_00000001_00000010, // Square 23 (H3)
|
|
||||||
0b00000010_00100000_00100000_00001000_01100101_00001001_00000010_00000001, // Square 24 (A4)
|
|
||||||
0b00100000_00010000_00010000_00001010_00000010_00000010_00010010_00000010, // Square 25 (B4)
|
|
||||||
0b00000001_01010010_00000100_10000100_00001000_00000010_00100100_00000001, // Square 26 (C4)
|
|
||||||
0b00000000_00100000_00001000_00000000_00000010_00001000_00010001_00010000, // Square 27 (D4)
|
|
||||||
0b01000000_00000001_00000000_00010000_00100001_00000000_01000000_00000000, // Square 28 (E4)
|
|
||||||
0b10000000_00000000_01000000_01000000_00001010_00000001_00010000_00000010, // Square 29 (F4)
|
|
||||||
0b00000000_11100100_00000000_01000000_10000001_00000001_00010000_00000010, // Square 30 (G4)
|
|
||||||
0b00000000_00011100_00000000_01000000_00000001_00000001_00100000_10000000, // Square 31 (H4)
|
|
||||||
0b10000000_00000100_00100000_00001001_01100010_10100000_00000010_00100000, // Square 32 (A5)
|
|
||||||
0b10000100_00100010_00010000_00000010_00001000_01010000_00000010_00000010, // Square 33 (B5)
|
|
||||||
0b00100000_00000000_01000000_00100010_00000000_00110000_00001100_00001000, // Square 34 (C5)
|
|
||||||
0b10000110_01000110_00000010_00000000_10000000_00001000_00000000_10000000, // Square 35 (D5)
|
|
||||||
0b10000000_00000010_00001010_00000010_00000000_00010000_00001000_00001000, // Square 36 (E5)
|
|
||||||
0b00100000_00010000_00000000_01001000_10000000_00010001_00010000_00000000, // Square 37 (F5)
|
|
||||||
0b01100010_00110000_00000000_10100000_10000000_00000001_00010100_00000000, // Square 38 (G5)
|
|
||||||
0b01000010_00000000_10001100_00000011_01000000_00100000_10010010_00000010, // Square 39 (H5)
|
|
||||||
0b00000010_00001001_00011000_10000010_01000000_00000000_00010000_00000000, // Square 40 (A6)
|
|
||||||
0b01000000_00000100_00001000_10101000_10000100_00000000_00011000_00000000, // Square 41 (B6)
|
|
||||||
0b00000000_00010001_00000100_00000000_10100110_00001000_00000100_00000000, // Square 42 (C6)
|
|
||||||
0b00011000_01000000_00000110_00001010_01000100_00000010_00001000_00000000, // Square 43 (D6)
|
|
||||||
0b00000000_10010000_00001000_00000001_00000100_00000000_00000000_01000001, // Square 44 (E6)
|
|
||||||
0b00000010_00000001_00000001_00010000_00000000_10000000_10000001_00000001, // Square 45 (F6)
|
|
||||||
0b00011010_00100010_00001000_00001000_00000101_00000100_11110000_10000000, // Square 46 (G6)
|
|
||||||
0b10000000_00010010_00000010_00000110_00000000_00100001_00010010_00010010, // Square 47 (H6)
|
|
||||||
0b00000101_00000000_10000110_00010000_00010001_00100100_00000000_00000000, // Square 48 (A7)
|
|
||||||
0b00000001_10000000_10000000_01100001_00001000_00100000_00001000_00000000, // Square 49 (B7)
|
|
||||||
0b01000000_00000000_00000010_00001110_00000001_00000100_00000000_01000100, // Square 50 (C7)
|
|
||||||
0b00110000_00000000_00000000_00100110_00010000_01000100_00000000_00001010, // Square 51 (D7)
|
|
||||||
0b00001000_00000010_00100100_00010001_00000010_00000010_00000000_00000010, // Square 52 (E7)
|
|
||||||
0b00000000_00100000_10010000_01100000_01100001_00100001_00000000_00000001, // Square 53 (F7)
|
|
||||||
0b01011010_10000100_10000100_00010000_00000100_00000001_00000011_00010000, // Square 54 (G7)
|
|
||||||
0b00000000_00000100_00000001_00001000_00000001_00000001_00011100_00000100, // Square 55 (H7)
|
|
||||||
0b00000000_00001010_00000001_00000001_00001001_01010000_00100010_00000000, // Square 56 (A8)
|
|
||||||
0b00000000_00000000_00000000_01001010_00000010_00000001_00100000_00000000, // Square 57 (B8)
|
|
||||||
0b01010000_00000010_00000001_00000001_00000000_10011000_10110000_00101000, // Square 58 (C8)
|
|
||||||
0b10000000_01000000_00000000_00101000_00010001_00000100_00001001_00000000, // Square 59 (D8)
|
|
||||||
0b00000000_00101000_00000000_00000000_00010000_00000010_00000010_00000100, // Square 60 (E8)
|
|
||||||
0b00000110_00000000_00000000_00100000_00100000_00101101_00000010_01000000, // Square 61 (F8)
|
|
||||||
0b10001001_00011000_10000100_01001000_01000010_00001000_00100010_00000000, // Square 62 (G8)
|
|
||||||
0b01000000_00010000_00000001_00010000_00101001_00000010_00000000_00100000, // Square 63 (H8)
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const RELEVANT_BITS_ROOK: [u8; 64] = [
|
|
||||||
12, 11, 11, 11, 11, 11, 11, 12,
|
|
||||||
11, 10, 10, 10, 10, 10, 10, 11,
|
|
||||||
11, 10, 10, 10, 10, 10, 10, 11,
|
|
||||||
11, 10, 10, 10, 10, 10, 10, 11,
|
|
||||||
11, 10, 10, 10, 10, 10, 10, 11,
|
|
||||||
11, 10, 10, 10, 10, 10, 10, 11,
|
|
||||||
11, 10, 10, 10, 10, 10, 10, 11,
|
|
||||||
12, 11, 11, 11, 11, 11, 11, 12,
|
|
||||||
];
|
|
||||||
pub const RELEVANT_BITS_BISHOP: [u8; 64] = [
|
|
||||||
6, 5, 5, 5, 5, 5, 5, 6,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 7, 7, 7, 7, 5, 5,
|
|
||||||
5, 5, 7, 9, 9, 7, 5, 5,
|
|
||||||
5, 5, 7, 9, 9, 7, 5, 5,
|
|
||||||
5, 5, 7, 7, 7, 7, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
6, 5, 5, 5, 5, 5, 5, 6,
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
static ROOK_ATTACKS: OnceLock<Box<[[u64; 4096]; 64]>> = OnceLock::new();
|
|
||||||
static BISHOP_ATTACKS: OnceLock<Box<[[u64; 512]; 64]>> = OnceLock::new();
|
|
||||||
|
|
||||||
|
|
||||||
// HILFSFUNKTION: Berechnet Turmzüge "langsam"
|
|
||||||
// Diese Funktion wird nur beim "Backen" der Tabellen verwendet.
|
|
||||||
fn calculate_rook_attacks_slowly(square: usize, blockers: u64) -> u64 {
|
|
||||||
let mut attacks = 0_u64;
|
|
||||||
let rank = square / 8;
|
|
||||||
let file = square % 8;
|
|
||||||
|
|
||||||
// 1. Nach Norden (rank +)
|
|
||||||
for r in (rank + 1)..=7 {
|
|
||||||
let target_sq = r * 8 + file;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break; // Wir treffen einen Blocker, stopp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Nach Süden (rank -)
|
|
||||||
for r in (0..rank).rev() {
|
|
||||||
let target_sq = r * 8 + file;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Nach Osten (file +)
|
|
||||||
for f in (file + 1)..=7 {
|
|
||||||
let target_sq = rank * 8 + f;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Nach Westen (file -)
|
|
||||||
for f in (0..file).rev() {
|
|
||||||
let target_sq = rank * 8 + f;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attacks
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_final_rook_attacks() -> Box<[[u64; 4096]; 64]> {
|
|
||||||
// Heap-Allokation (Dein Code war hier korrekt)
|
|
||||||
let mut v: Vec<[u64; 4096]> = Vec::with_capacity(64);
|
|
||||||
for _ in 0..64 {
|
|
||||||
v.push([0_u64; 4096]);
|
|
||||||
}
|
|
||||||
let mut final_rook_attacks: Box<[[u64; 4096]; 64]> = v.try_into().unwrap_or_else(|_| {
|
|
||||||
panic!("Vec to Box conversion failed.");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Haupt-Back-Schleife
|
|
||||||
for square_index in 0_usize..=63_usize {
|
|
||||||
let premask = PREMASKS_ROOK[square_index]; // [deine Quelle]
|
|
||||||
let magic = MAGICS_ROOK[square_index]; // [deine Quelle]
|
|
||||||
// ACHTUNG: Hier war ein Fehler in deinem Code, du hattest BISHOP statt ROOK
|
|
||||||
let relevant_bits = RELEVANT_BITS_ROOK[square_index]; // [deine Quelle]
|
|
||||||
let shift = 64 - relevant_bits;
|
|
||||||
|
|
||||||
// Schleife durch alle 2^n Blocker-Kombinationen
|
|
||||||
let mut blocker_combination = 0_u64;
|
|
||||||
loop {
|
|
||||||
// ---- HIER IST DIE KORREKTE LOGIK ----
|
|
||||||
|
|
||||||
// 1. Berechne die "echten" Züge für diese Blocker-Kombination (der langsame Weg)
|
|
||||||
let attack_squares = calculate_rook_attacks_slowly(square_index, blocker_combination);
|
|
||||||
|
|
||||||
// 2. Berechne den "magischen" Speicherort
|
|
||||||
let magic_index = (blocker_combination.wrapping_mul(magic)) >> shift;
|
|
||||||
let magic_index_as_usize = magic_index as usize;
|
|
||||||
|
|
||||||
// 3. Speichere die echten Züge an diesem magischen Ort
|
|
||||||
final_rook_attacks[square_index][magic_index_as_usize] = attack_squares;
|
|
||||||
|
|
||||||
// ---- ENDE DER LOGIK ----
|
|
||||||
|
|
||||||
// Gehe zur nächsten Blocker-Kombination (Dein Code war hier korrekt)
|
|
||||||
if blocker_combination == premask {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
blocker_combination = blocker_combination.wrapping_sub(premask) & premask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final_rook_attacks
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_rook_attacks() -> &'static Box<[[u64; 4096]; 64]> {
|
|
||||||
// get_or_init stellt sicher, dass generate_final_rook_attacks()
|
|
||||||
// nur beim allerersten Aufruf ausgeführt wird.
|
|
||||||
// Alle anderen Aufrufe geben sofort die fertige Tabelle zurück.
|
|
||||||
ROOK_ATTACKS.get_or_init(generate_final_rook_attacks)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HILFSFUNKTION: Berechnet Läuferzüge "langsam"
|
|
||||||
// Diese Funktion wird nur beim "Backen" der Tabellen verwendet.
|
|
||||||
fn calculate_bishop_attacks_slowly(square: usize, blockers: u64) -> u64 {
|
|
||||||
let mut attacks = 0_u64;
|
|
||||||
let rank = square / 8;
|
|
||||||
let file = square % 8;
|
|
||||||
|
|
||||||
// Temporäre Rank/File-Iteratoren
|
|
||||||
let (mut r, mut f);
|
|
||||||
|
|
||||||
// 1. Nach Nord-Osten (rank+, file+)
|
|
||||||
r = rank + 1;
|
|
||||||
f = file + 1;
|
|
||||||
while r <= 7 && f <= 7 {
|
|
||||||
let target_sq = r * 8 + f;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break; // Wir treffen einen Blocker, stopp
|
|
||||||
}
|
|
||||||
r += 1;
|
|
||||||
f += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Nach Süd-Osten (rank-, file+)
|
|
||||||
r = rank; // Start bei rank, da 0..rank fehlschlägt wenn rank = 0
|
|
||||||
f = file + 1;
|
|
||||||
while r > 0 && f <= 7 { // r > 0 (da r = rank-1 in der 1. Iteration)
|
|
||||||
r -= 1;
|
|
||||||
let target_sq = r * 8 + f;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
f += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Nach Süd-Westen (rank-, file-)
|
|
||||||
r = rank;
|
|
||||||
f = file;
|
|
||||||
while r > 0 && f > 0 { // r > 0 und f > 0
|
|
||||||
r -= 1;
|
|
||||||
f -= 1;
|
|
||||||
let target_sq = r * 8 + f;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Nach Nord-Westen (rank+, file-)
|
|
||||||
r = rank + 1;
|
|
||||||
f = file;
|
|
||||||
while r <= 7 && f > 0 { // f > 0
|
|
||||||
f -= 1;
|
|
||||||
let target_sq = r * 8 + f;
|
|
||||||
attacks |= 1_u64 << target_sq;
|
|
||||||
if (blockers >> target_sq) & 1 == 1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
r += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
attacks
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_final_bishop_attacks() -> Box<[[u64; 512]; 64]> {
|
|
||||||
// Heap-Allokation
|
|
||||||
// (Array ist kleiner: 512 statt 4096. Stack Overflow wäre hier unwahrscheinlich,
|
|
||||||
// aber wir bleiben konsistent mit der Turm-Logik.)
|
|
||||||
let mut v: Vec<[u64; 512]> = Vec::with_capacity(64);
|
|
||||||
for _ in 0..64 {
|
|
||||||
v.push([0_u64; 512]);
|
|
||||||
}
|
|
||||||
let mut final_bishop_attacks: Box<[[u64; 512]; 64]> = v.try_into().unwrap_or_else(|_| {
|
|
||||||
panic!("Vec to Box conversion failed for bishops.");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Haupt-Back-Schleife
|
|
||||||
for square_index in 0_usize..=63_usize {
|
|
||||||
// Verwende die BISHOP-Konstanten aus deiner tables.rs
|
|
||||||
let premask = PREMASKS_BISHOP[square_index];
|
|
||||||
let magic = MAGICS_BISHOP[square_index];
|
|
||||||
let relevant_bits = RELEVANT_BITS_BISHOP[square_index];
|
|
||||||
let shift = 64 - relevant_bits;
|
|
||||||
|
|
||||||
// Schleife durch alle 2^n Blocker-Kombinationen
|
|
||||||
let mut blocker_combination = 0_u64;
|
|
||||||
loop {
|
|
||||||
// 1. Berechne die "echten" Züge für diese Blocker-Kombination (der langsame Weg)
|
|
||||||
let attack_squares = calculate_bishop_attacks_slowly(square_index, blocker_combination);
|
|
||||||
|
|
||||||
// 2. Berechne den "magischen" Speicherort
|
|
||||||
let magic_index = (blocker_combination.wrapping_mul(magic)) >> shift;
|
|
||||||
let magic_index_as_usize = magic_index as usize;
|
|
||||||
|
|
||||||
// 3. Speichere die echten Züge an diesem magischen Ort
|
|
||||||
// (Stelle sicher, dass magic_index_as_usize < 512 ist,
|
|
||||||
// was durch korrekte Magics garantiert wird)
|
|
||||||
final_bishop_attacks[square_index][magic_index_as_usize] = attack_squares;
|
|
||||||
|
|
||||||
// Gehe zur nächsten Blocker-Kombination
|
|
||||||
if blocker_combination == premask {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
blocker_combination = blocker_combination.wrapping_sub(premask) & premask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final_bishop_attacks
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_bishop_attacks() -> &'static Box<[[u64; 512]; 64]> {
|
|
||||||
// get_or_init stellt sicher, dass generate_final_bishop_attacks()
|
|
||||||
// nur beim allerersten Aufruf ausgeführt wird.
|
|
||||||
// Alle anderen Aufrufe geben sofort die fertige Tabelle zurück.
|
|
||||||
BISHOP_ATTACKS.get_or_init(generate_final_bishop_attacks)
|
|
||||||
}
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
use std::ops::{Sub, Add};
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum Square {
|
|
||||||
A1 = 0,
|
|
||||||
B1 = 1,
|
|
||||||
C1 = 2,
|
|
||||||
D1 = 3,
|
|
||||||
E1 = 4,
|
|
||||||
F1 = 5,
|
|
||||||
G1 = 6,
|
|
||||||
H1 = 7,
|
|
||||||
A2 = 8,
|
|
||||||
B2 = 9,
|
|
||||||
C2 = 10,
|
|
||||||
D2 = 11,
|
|
||||||
E2 = 12,
|
|
||||||
F2 = 13,
|
|
||||||
G2 = 14,
|
|
||||||
H2 = 15,
|
|
||||||
A3 = 16,
|
|
||||||
B3 = 17,
|
|
||||||
C3 = 18,
|
|
||||||
D3 = 19,
|
|
||||||
E3 = 20,
|
|
||||||
F3 = 21,
|
|
||||||
G3 = 22,
|
|
||||||
H3 = 23,
|
|
||||||
A4 = 24,
|
|
||||||
B4 = 25,
|
|
||||||
C4 = 26,
|
|
||||||
D4 = 27,
|
|
||||||
E4 = 28,
|
|
||||||
F4 = 29,
|
|
||||||
G4 = 30,
|
|
||||||
H4 = 31,
|
|
||||||
A5 = 32,
|
|
||||||
B5 = 33,
|
|
||||||
C5 = 34,
|
|
||||||
D5 = 35,
|
|
||||||
E5 = 36,
|
|
||||||
F5 = 37,
|
|
||||||
G5 = 38,
|
|
||||||
H5 = 39,
|
|
||||||
A6 = 40,
|
|
||||||
B6 = 41,
|
|
||||||
C6 = 42,
|
|
||||||
D6 = 43,
|
|
||||||
E6 = 44,
|
|
||||||
F6 = 45,
|
|
||||||
G6 = 46,
|
|
||||||
H6 = 47,
|
|
||||||
A7 = 48,
|
|
||||||
B7 = 49,
|
|
||||||
C7 = 50,
|
|
||||||
D7 = 51,
|
|
||||||
E7 = 52,
|
|
||||||
F7 = 53,
|
|
||||||
G7 = 54,
|
|
||||||
H7 = 55,
|
|
||||||
A8 = 56,
|
|
||||||
B8 = 57,
|
|
||||||
C8 = 58,
|
|
||||||
D8 = 59,
|
|
||||||
E8 = 60,
|
|
||||||
F8 = 61,
|
|
||||||
G8 = 62,
|
|
||||||
H8 = 63,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const SQUARES: [Square; 64] = [
|
|
||||||
Square::A1, Square::B1, Square::C1, Square::D1, Square::E1, Square::F1, Square::G1, Square::H1,
|
|
||||||
Square::A2, Square::B2, Square::C2, Square::D2, Square::E2, Square::F2, Square::G2, Square::H2,
|
|
||||||
Square::A3, Square::B3, Square::C3, Square::D3, Square::E3, Square::F3, Square::G3, Square::H3,
|
|
||||||
Square::A4, Square::B4, Square::C4, Square::D4, Square::E4, Square::F4, Square::G4, Square::H4,
|
|
||||||
Square::A5, Square::B5, Square::C5, Square::D5, Square::E5, Square::F5, Square::G5, Square::H5,
|
|
||||||
Square::A6, Square::B6, Square::C6, Square::D6, Square::E6, Square::F6, Square::G6, Square::H6,
|
|
||||||
Square::A7, Square::B7, Square::C7, Square::D7, Square::E7, Square::F7, Square::G7, Square::H7,
|
|
||||||
Square::A8, Square::B8, Square::C8, Square::D8, Square::E8, Square::F8, Square::G8, Square::H8,
|
|
||||||
];
|
|
||||||
|
|
||||||
impl TryFrom<u8> for Square {
|
|
||||||
type Error = &'static str;
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
||||||
if value <= 63 {
|
|
||||||
Ok(unsafe { std::mem::transmute(value) })
|
|
||||||
} else {
|
|
||||||
Err("Square index out of bounds")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<u8> for Square {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: u8) -> Self::Output {
|
|
||||||
let new_val = (self as u8) + rhs;
|
|
||||||
new_val.try_into().expect("Square addition resulted in an invalid square")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub<u8> for Square {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn sub(self, rhs: u8) -> Self::Output {
|
|
||||||
let new_val = (self as u8).checked_sub(rhs)
|
|
||||||
.expect("Square subtraction resulted in an underflow");
|
|
||||||
|
|
||||||
new_val.try_into().expect("Square subtraction resulted in an invalid square")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Square {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lt(&self, other: &Self) -> bool {
|
|
||||||
(*self as u8) < (*other as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn le(&self, other: &Self) -> bool {
|
|
||||||
(*self as u8) <= (*other as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gt(&self, other: &Self) -> bool {
|
|
||||||
(*self as u8) > (*other as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ge(&self, other: &Self) -> bool {
|
|
||||||
(*self as u8) >= (*other as u8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Square {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
(*self as u8).cmp(&(*other as u8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::sliders::generate_bishop_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
/// Compares two move list strings ignoring the order of moves.
|
|
||||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
|
||||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
|
||||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
|
||||||
|
|
||||||
actual_moves.sort();
|
|
||||||
expected_moves.sort();
|
|
||||||
|
|
||||||
assert_eq!(actual_moves, expected_moves);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bishop_moves_single() {
|
|
||||||
let fen_standard = "8/8/8/1p1p4/2B5/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_bishop_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "c4b5 c4d5 c4b3 c4d3 c4a2 c4e2 c4f1");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bishop_moves_empty_board_center() {
|
|
||||||
// Läufer in der Mitte (e4) auf einem leeren Brett
|
|
||||||
let fen = "8/8/8/8/4B3/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_bishop_moves(&board, &mut list);
|
|
||||||
|
|
||||||
let expected = "e4d3 e4c2 e4b1 e4f5 e4g6 e4h7 e4d5 e4c6 e4b7 e4a8 e4f3 e4g2 e4h1";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bishop_moves_from_corner() {
|
|
||||||
// Läufer in der Ecke (a1) auf einem leeren Brett
|
|
||||||
let fen = "8/8/8/8/8/8/8/B7 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_bishop_moves(&board, &mut list);
|
|
||||||
|
|
||||||
let expected = "a1b2 a1c3 a1d4 a1e5 a1f6 a1g7 a1h8";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bishop_moves_friendly_blockers() {
|
|
||||||
// Läufer auf c1, blockiert von EIGENEN Bauern auf b2 und d2.
|
|
||||||
// Darf b2/d2 NICHT schlagen und nicht darüber springen.
|
|
||||||
let fen = "8/8/8/8/8/8/1P1P4/2B5 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_bishop_moves(&board, &mut list);
|
|
||||||
|
|
||||||
// Es sollten KEINE Züge generiert werden.
|
|
||||||
assert_moves_equal(&list.to_string(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bishop_moves_mixed_blockers_and_captures() {
|
|
||||||
let fen = "8/8/1p3P2/8/3B4/8/1p3P2/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_bishop_moves(&board, &mut list);
|
|
||||||
|
|
||||||
let expected = "d4c3 d4e3 d4b2 d4c5 d4b6 d4e5";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bishop_moves_black_turn() {
|
|
||||||
// Schwarzer Läufer auf c5, weiße Bauern auf b4 und d4.
|
|
||||||
let fen = "8/8/8/2b5/1P1P4/8/8/8 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_bishop_moves(&board, &mut list);
|
|
||||||
|
|
||||||
// Schlagzüge: b4, d4
|
|
||||||
// Ruhige Züge: b6, a7, d6, e7, f8
|
|
||||||
let expected = "c5b4 c5d4 c5b6 c5a7 c5d6 c5e7 c5f8";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
<<<<<<< HEAD
|
|
||||||
use chess_engine::board::*;
|
|
||||||
=======
|
|
||||||
use chess_engine::board::Board;
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_standard() {
|
|
||||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_standard).to_fen(), fen_standard);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_kiwipete() {
|
|
||||||
let fen_kiwipete = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_kiwipete).to_fen(), fen_kiwipete);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_en_passant() {
|
|
||||||
let fen_en_passant = "rnbqkbnr/pppppp1p/8/8/p7/4P3/PPPP1PPP/RNBQKBNR w KQkq e3 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_en_passant).to_fen(), fen_en_passant);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_castle() {
|
|
||||||
let fen_castle = "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2QK2R b - - 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_castle).to_fen(), fen_castle);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_just_kings() {
|
|
||||||
let fen_just_kings = "8/k7/8/8/8/8/7K/8 w - - 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_just_kings).to_fen(), fen_just_kings);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_high_move_values() {
|
|
||||||
let fen_high_move_values = "8/P1k5/K7/8/8/8/8/8 w - - 0 78";
|
|
||||||
assert_eq!(Board::from_fen(fen_high_move_values).to_fen(), fen_high_move_values);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_empty_count1() {
|
|
||||||
let fen_empty_count1 = "1n6/8/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_empty_count1).to_fen(), fen_empty_count1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fen_roundtrip_empty_count2() {
|
|
||||||
let fen_empty_count2 = "6n1/8/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
assert_eq!(Board::from_fen(fen_empty_count2).to_fen(), fen_empty_count2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_board_fen_state() {
|
|
||||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
<<<<<<< HEAD
|
|
||||||
assert_eq!(board.pieces[PieceType::Pawn as usize][Color::White as usize], 65280);
|
|
||||||
assert_eq!(board.pieces[PieceType::Pawn as usize][Color::Black as usize], 71776119061217280);
|
|
||||||
assert_eq!(board.pieces[PieceType::Knight as usize][Color::White as usize], 66);
|
|
||||||
assert_eq!(board.pieces[PieceType::Knight as usize][Color::Black as usize], 4755801206503243776);
|
|
||||||
assert_eq!(board.pieces[PieceType::Bishop as usize][Color::White as usize], 36);
|
|
||||||
assert_eq!(board.pieces[PieceType::Bishop as usize][Color::Black as usize], 2594073385365405696);
|
|
||||||
assert_eq!(board.pieces[PieceType::Rook as usize][Color::White as usize], 129);
|
|
||||||
assert_eq!(board.pieces[PieceType::Rook as usize][Color::Black as usize], 9295429630892703744);
|
|
||||||
assert_eq!(board.pieces[PieceType::Queen as usize][Color::White as usize], 8);
|
|
||||||
assert_eq!(board.pieces[PieceType::Queen as usize][Color::Black as usize], 576460752303423488);
|
|
||||||
assert_eq!(board.pieces[PieceType::King as usize][Color::White as usize], 16);
|
|
||||||
assert_eq!(board.pieces[PieceType::King as usize][Color::Black as usize], 1152921504606846976);
|
|
||||||
=======
|
|
||||||
assert_eq!(board.pawns[0], 65280);
|
|
||||||
assert_eq!(board.pawns[1], 71776119061217280);
|
|
||||||
assert_eq!(board.knights[0], 66);
|
|
||||||
assert_eq!(board.knights[1], 4755801206503243776);
|
|
||||||
assert_eq!(board.bishops[0], 36);
|
|
||||||
assert_eq!(board.bishops[1], 2594073385365405696);
|
|
||||||
assert_eq!(board.rooks[0], 129);
|
|
||||||
assert_eq!(board.rooks[1], 9295429630892703744);
|
|
||||||
assert_eq!(board.queens[0], 8);
|
|
||||||
assert_eq!(board.queens[1], 576460752303423488);
|
|
||||||
assert_eq!(board.kings[0], 16);
|
|
||||||
assert_eq!(board.kings[1], 1152921504606846976);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
|
|
||||||
assert_eq!(board.occupied[0], 65535);
|
|
||||||
assert_eq!(board.occupied[1], 18446462598732840960);
|
|
||||||
assert_eq!(board.all_occupied, 18446462598732906495);
|
|
||||||
|
|
||||||
assert_eq!(board.castling_rights, 15);
|
|
||||||
assert_eq!(board.en_passant_target, None);
|
|
||||||
assert_eq!(board.halfmove_clock, 0);
|
|
||||||
assert_eq!(board.fullmove_number, 1);
|
|
||||||
}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::non_sliders::generate_king_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
/// Compares two move list strings ignoring the order of moves.
|
|
||||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
|
||||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
|
||||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
|
||||||
|
|
||||||
actual_moves.sort();
|
|
||||||
expected_moves.sort();
|
|
||||||
|
|
||||||
assert_eq!(actual_moves, expected_moves);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_start_pos_blocked() {
|
|
||||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// King is completely blocked in the start position
|
|
||||||
assert_moves_equal(&list.to_string(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_center() {
|
|
||||||
let fen = "8/8/8/8/4K3/8/8/8 w - - 0 1"; // King on e4
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// 8 moves from e4
|
|
||||||
assert_moves_equal(&list.to_string(), "e4d3 e4d4 e4d5 e4e3 e4e5 e4f3 e4f4 e4f5");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_corner() {
|
|
||||||
let fen = "K7/8/8/8/8/8/8/8 w - - 0 1"; // King on a8
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// 3 moves from a8
|
|
||||||
assert_moves_equal(&list.to_string(), "a8a7 a8b7 a8b8");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_blocked_friendly() {
|
|
||||||
// King on d4, surrounded by friendly pawns
|
|
||||||
let fen = "8/8/8/3P1P2/3K4/3P1P2/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// d3, d5, f3, f5 are blocked.
|
|
||||||
// c3, c4, c5, e3, e4, e5 are free.
|
|
||||||
assert_moves_equal(&list.to_string(), "d4c3 d4c4 d4c5 d4e3 d4e4 d4e5");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_capture_and_blocked() {
|
|
||||||
// King on d4
|
|
||||||
// Friendly: c3, e5
|
|
||||||
// Enemy: c5, e3
|
|
||||||
let fen = "8/8/8/2p1P3/3K4/2P1p3/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// Blocked: c3, e5
|
|
||||||
// Captures: c5, e3
|
|
||||||
// Empty: c4, d3, d5, e4, f3, f4, f5
|
|
||||||
// Note: f3, f4, f5 are valid moves
|
|
||||||
assert_moves_equal(&list.to_string(), "d4c4 d4d3 d4d5 d4e4 d4c5 d4e3");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_black() {
|
|
||||||
let fen = "8/8/8/8/4k3/8/8/8 b - - 0 1"; // Black king on e4
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// 8 moves from e4
|
|
||||||
assert_moves_equal(&list.to_string(), "e4d3 e4d4 e4d5 e4e3 e4e5 e4f3 e4f4 e4f5");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_castling_white_all() {
|
|
||||||
// King on e1, rooks on a1, h1. All rights. No pieces between.
|
|
||||||
let fen = "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// 5 standard moves + 2 castling moves (e1g1, e1c1)
|
|
||||||
assert_moves_equal(&list.to_string(), "e1d1 e1d2 e1e2 e1f1 e1f2 O-O O-O-O");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_castling_black_all() {
|
|
||||||
// King on e8, rooks on a8, h8. All rights. No pieces between.
|
|
||||||
let fen = "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// 5 standard moves + 2 castling moves (e8g8, e8c8)
|
|
||||||
assert_moves_equal(&list.to_string(), "O-O O-O-O e8d8 e8e7 e8f8 e8d7 e8f7");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_castling_blocked_pieces_white() {
|
|
||||||
// White: Queenside blocked by knight
|
|
||||||
let fen = "r3k2r/8/8/8/8/8/8/RN2K2R w KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// Should only get Kingside castling (e1g1) and standard moves
|
|
||||||
assert_moves_equal(&list.to_string(), "e1d1 e1d2 e1e2 e1f1 e1f2 O-O");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_castling_blocked_pieces_black() {
|
|
||||||
// Black: Kingside blocked by bishop
|
|
||||||
let fen = "r3kb1r/8/8/8/8/8/8/R3K2R b KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "e8d8 e8d7 e8e7 e8f7 O-O-O");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_castling_no_rights() {
|
|
||||||
// Same as `test_king_moves_castling_white_all` but no castling rights
|
|
||||||
let fen = "r3k2r/8/8/8/8/8/8/R3K2R w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
// 5 standard moves, 0 castling
|
|
||||||
assert_moves_equal(&list.to_string(), "e1d1 e1d2 e1e2 e1f1 e1f2");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_king_moves_empty_board() {
|
|
||||||
let fen = "8/8/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_king_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "");
|
|
||||||
}
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::non_sliders::generate_knight_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
/// Compares two move list strings ignoring the order of moves.
|
|
||||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
|
||||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
|
||||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
|
||||||
|
|
||||||
actual_moves.sort();
|
|
||||||
expected_moves.sort();
|
|
||||||
|
|
||||||
assert_eq!(actual_moves, expected_moves);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_move_generation() {
|
|
||||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "b1a3 b1c3 g1f3 g1h3");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_move_generation_black() {
|
|
||||||
let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "b8a6 b8c6 g8f6 g8h6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_moves_center() {
|
|
||||||
let fen = "8/8/8/3N4/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
// 8 moves from d5
|
|
||||||
assert_moves_equal(&list.to_string(), "d5b4 d5b6 d5c3 d5c7 d5e3 d5e7 d5f4 d5f6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_moves_capture() {
|
|
||||||
// Black knight on e5, white pawn on d3
|
|
||||||
let fen = "8/8/8/4n3/8/3P4/8/8 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
// 8 moves, including capture on d3
|
|
||||||
assert_moves_equal(&list.to_string(), "e5c4 e5c6 e5d3 e5d7 e5f3 e5f7 e5g4 e5g6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_moves_blocked_friendly() {
|
|
||||||
// Knight on d4, some moves are blocked, some are not.
|
|
||||||
let fen = "8/8/3P1P2/3P1P2/3N4/3P1P2/3P1P2/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
// f3, f5, d3, d5, d6, f6 are blocked.
|
|
||||||
// c2, e2, b3, b5, c6, e6 are free.
|
|
||||||
assert_moves_equal(&list.to_string(), "d4c2 d4e2 d4b3 d4b5 d4c6 d4e6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_moves_corner() {
|
|
||||||
let fen = "N7/8/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
// 2 moves from a8
|
|
||||||
assert_moves_equal(&list.to_string(), "a8b6 a8c7");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_moves_capture_and_blocked() {
|
|
||||||
// White knights on b1 and g1.
|
|
||||||
// b1: a3 (friendly), c3 (friendly), d2 (enemy)
|
|
||||||
// g1: f3 (empty), h3 (empty), e2 (empty)
|
|
||||||
let fen = "8/8/8/8/8/P1P5/3p4/1N4NR w K - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "b1d2 g1e2 g1f3 g1h3");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_knight_moves_empty_board() {
|
|
||||||
let fen = "8/8/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_knight_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "");
|
|
||||||
}
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
use chess_engine::r#move::*;
|
|
||||||
use chess_engine::square::Square;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_quiet_move_white_pawn() {
|
|
||||||
// Test 1: Standard Quiet Move (White Pawn)
|
|
||||||
// (from: E2, to: E4)
|
|
||||||
// NOTE: This was MOVE_TYPE_FLAG_QUIET, but in the new system it's a specific flag.
|
|
||||||
// The algebraic notation is the same, so we test with the new specific flag.
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let m_quiet = Move::new(Square::E2, Square::E4, MOVE_FLAG_QUIET);
|
|
||||||
=======
|
|
||||||
let m_quiet = Move::new(Square::E2, Square::E4, MOVE_FLAG_DOUBLE_PAWN);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
assert_eq!(m_quiet.to_algebraic(), "e2e4");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_quiet_move_black_knight() {
|
|
||||||
// Test 2: Standard Quiet Move (Black Knight)
|
|
||||||
// (from: B8, to: C6)
|
|
||||||
let m_knight = Move::new(Square::B8, Square::C6, MOVE_FLAG_QUIET);
|
|
||||||
assert_eq!(m_knight.to_algebraic(), "b8c6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_en_passant_move() {
|
|
||||||
// Test 3: En Passant Move (Notation is same as quiet move)
|
|
||||||
// (from: E5, to: F6)
|
|
||||||
let m_ep = Move::new(Square::E5, Square::F6, MOVE_FLAG_EN_PASSANT);
|
|
||||||
assert_eq!(m_ep.to_algebraic(), "e5f6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_promotion_to_queen() {
|
|
||||||
// Test 4: Promotion to Queen (Push)
|
|
||||||
// (from: E7, to: E8)
|
|
||||||
let m_promo_q = Move::new(Square::E7, Square::E8, MOVE_FLAG_PROMO_Q);
|
|
||||||
assert_eq!(m_promo_q.to_algebraic(), "e7e8q");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_promotion_to_rook() {
|
|
||||||
// Test 5: Promotion to Rook (Push)
|
|
||||||
// (from: A7, to: A8)
|
|
||||||
let m_promo_r = Move::new(Square::A7, Square::A8, MOVE_FLAG_PROMO_R);
|
|
||||||
assert_eq!(m_promo_r.to_algebraic(), "a7a8r");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_promotion_to_bishop() {
|
|
||||||
// Test 6: Promotion to Bishop (Capture)
|
|
||||||
// (from: G2, to: H1)
|
|
||||||
let m_promo_b = Move::new(Square::G2, Square::H1, MOVE_FLAG_PROMO_CAP_B);
|
|
||||||
assert_eq!(m_promo_b.to_algebraic(), "g2h1b");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_promotion_to_knight() {
|
|
||||||
// Test 7: Promotion to Knight (Capture)
|
|
||||||
// (from: G7, to: F8)
|
|
||||||
let m_promo_n = Move::new(Square::G7, Square::F8, MOVE_FLAG_PROMO_CAP_N);
|
|
||||||
assert_eq!(m_promo_n.to_algebraic(), "g7f8n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_white_kingside_castling() {
|
|
||||||
// Test 8: White Kingside Castling
|
|
||||||
// (from: E1, to: G1)
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let m_castle_wk = Move::new(Square::E1, Square::G1, MOVE_FLAG_WK_CASTLE);
|
|
||||||
=======
|
|
||||||
let m_castle_wk = Move::new(Square::E1, Square::G1, MOVE_FLAG_KING_CASTLE);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
assert_eq!(m_castle_wk.to_algebraic(), "O-O");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_white_queenside_castling() {
|
|
||||||
// Test 9: White Queenside Castling
|
|
||||||
// (from: E1, to: C1)
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let m_castle_wq = Move::new(Square::E1, Square::C1, MOVE_FLAG_WQ_CASTLE);
|
|
||||||
=======
|
|
||||||
let m_castle_wq = Move::new(Square::E1, Square::C1, MOVE_FLAG_QUEEN_CASTLE);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
assert_eq!(m_castle_wq.to_algebraic(), "O-O-O");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_black_kingside_castling() {
|
|
||||||
// Test 10: Black Kingside Castling
|
|
||||||
// (from: E8, to: G8)
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let m_castle_bk = Move::new(Square::E8, Square::G8, MOVE_FLAG_BK_CASTLE);
|
|
||||||
=======
|
|
||||||
let m_castle_bk = Move::new(Square::E8, Square::G8, MOVE_FLAG_KING_CASTLE);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
assert_eq!(m_castle_bk.to_algebraic(), "O-O");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_black_queenside_castling() {
|
|
||||||
// Test 11: Black Queenside Castling
|
|
||||||
// (from: E8, to: C8)
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let m_castle_bq = Move::new(Square::E8, Square::C8, MOVE_FLAG_BQ_CASTLE);
|
|
||||||
=======
|
|
||||||
let m_castle_bq = Move::new(Square::E8, Square::C8, MOVE_FLAG_QUEEN_CASTLE);
|
|
||||||
>>>>>>> origin/master
|
|
||||||
assert_eq!(m_castle_bq.to_algebraic(), "O-O-O");
|
|
||||||
}
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::pawns::generate_pawn_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
/// Compares two move list strings ignoring the order of moves.
|
|
||||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
|
||||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
|
||||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
|
||||||
|
|
||||||
actual_moves.sort();
|
|
||||||
expected_moves.sort();
|
|
||||||
|
|
||||||
assert_eq!(actual_moves, expected_moves);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_start_pos() {
|
|
||||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a2a3 a2a4 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e2e3 e2e4 f2f3 f2f4 g2g3 g2g4 h2h3 h2h4");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_start_pos() {
|
|
||||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a7a6 a7a5 b7b6 b7b5 c7c6 c7c5 d7d6 d7d5 e7e6 e7e5 f7f6 f7f5 g7g6 g7g5 h7h6 h7h5");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_blocked_and_captures() {
|
|
||||||
// Black pawns on a7, c7, e7, g7. White pawns on b6, d6, f6.
|
|
||||||
let fen = "8/p1p1p1p1/1P1P1P2/8/8/8/8/8 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a7a6 a7a5 a7b6 c7c6 c7c5 c7b6 c7d6 e7e6 e7e5 e7d6 e7f6 g7g6 g7g5 g7f6");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_side_captures() {
|
|
||||||
// Test captures on A and H files (no wrap-around)
|
|
||||||
let fen = "8/8/8/8/8/1p4p1/P6P/8 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "b3b2 b3a2 g3g2 g3h2");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_white_side_captures() {
|
|
||||||
// Test captures on A and H files (no wrap-around)
|
|
||||||
let fen = "8/p6p/1P4P1/8/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "b6b7 b6a7 g6g7 g6h7");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_en_passant() {
|
|
||||||
// White just moved e2e4, en passant target is e3. Black pawn on d4.
|
|
||||||
let fen = "rnbqkbnr/ppp1pppp/8/8/3pP3/8/PPP2PPP/RNBQKBNR b KQkq e3 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a7a6 a7a5 b7b6 b7b5 c7c6 c7c5 d4d3 d4e3 e7e6 e7e5 f7f6 f7f5 g7g6 g7g5 h7h6 h7h5");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_white_en_passant() {
|
|
||||||
// Black just moved d7d5, en passant target is d6. White pawn on e5.
|
|
||||||
let fen = "rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a2a3 a2a4 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e5e6 e5d6 f2f3 f2f4 g2g3 g2g4 h2h3 h2h4");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_promotion() {
|
|
||||||
let fen = "8/8/8/8/8/8/p1p1p1p1/8 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(),
|
|
||||||
"a2a1q a2a1r a2a1b a2a1n c2c1q c2c1r c2c1b c2c1n e2e1q e2e1r e2e1b e2e1n g2g1q g2g1r g2g1b g2g1n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_white_promotion() {
|
|
||||||
let fen = "8/P1P1P1P1/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(),
|
|
||||||
"a7a8q a7a8r a7a8b a7a8n c7c8q c7c8r c7c8b c7c8n e7e8q e7e8r e7e8b e7e8n g7g8q g7g8r g7g8b g7g8n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_promotion_capture() {
|
|
||||||
// Black pawn on b2. White rooks on a1 and c1.
|
|
||||||
let fen = "8/8/8/8/8/8/1p6/R1R5 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(),
|
|
||||||
"b2b1q b2b1r b2b1b b2b1n b2a1q b2a1r b2a1b b2a1n b2c1q b2c1r b2c1b b2c1n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_white_promotion_capture() {
|
|
||||||
// White pawn on a7. Black rooks on b8 and d8.
|
|
||||||
let fen = "1r1r4/P7/8/8/8/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(),
|
|
||||||
"a7a8q a7a8r a7a8b a7a8n a7b8q a7b8r a7b8b a7b8n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_black_midgame_random() {
|
|
||||||
let fen = "r1bqkb1r/1p2pppp/p1n2n2/3p4/2BNP3/2N5/PPP2PPP/R1BQK2R b KQkq - 1 6";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a6a5 b7b6 b7b5 d5c4 d5e4 e7e6 e7e5 g7g6 g7g5 h7h6 h7h5");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pawn_moves_white_midgame_random() {
|
|
||||||
let fen = "r1bqk2r/2ppbppp/p1n2n2/1p2p3/B1P1P3/5N2/PP1P1PPP/RNBQR1K1 w kq - 0 7";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_pawn_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "a2a3 b2b3 b2b4 c4c5 c4b5 d2d3 d2d4 g2g3 g2g4 h2h3 h2h4");
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::generate_pseudo_legal_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
|
|
||||||
// "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" 7 3195901860 "false"
|
|
||||||
// "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -" 5 193690690 "false"
|
|
||||||
// "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -" 7 178633661 "false"
|
|
||||||
// "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1" 6 706045033 "false"
|
|
||||||
// "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8" 5 89941194 "false"
|
|
||||||
// "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10" 5 164075551 "false"
|
|
||||||
// "r7/4p3/5p1q/3P4/4pQ2/4pP2/6pp/R3K1kr w Q - 1 3" 5 11609488 "false"
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::sliders::generate_queen_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
/// Compares two move list strings ignoring the order of moves.
|
|
||||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
|
||||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
|
||||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
|
||||||
|
|
||||||
actual_moves.sort();
|
|
||||||
expected_moves.sort();
|
|
||||||
|
|
||||||
assert_eq!(actual_moves, expected_moves);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_queen_moves_single_rook() {
|
|
||||||
let fen_standard = "8/1Q2p3/8/8/8/8/6p1/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "b7a8 b7a7 b7a6 b7b8 b7b6 b7b5 b7b4 b7b3 b7b2 b7b1 b7c8 b7c7 b7c6 b7d7 b7e7 b7d5 b7e4 b7f3 b7g2");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_queen_center_open() {
|
|
||||||
// Queen in the center, open board, should generate 27 moves
|
|
||||||
let fen = "4k3/8/8/8/3Q4/8/8/4K3 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
let expected = "d4a1 d4b2 d4c3 d4e5 d4f6 d4g7 d4h8 \
|
|
||||||
d4a4 d4b4 d4c4 d4e4 d4f4 d4g4 d4h4 \
|
|
||||||
d4d1 d4d2 d4d3 d4d5 d4d6 d4d7 d4d8 \
|
|
||||||
d4a7 d4b6 d4c5 d4e3 d4f2 d4g1";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_queen_corner_blocked_friendly() {
|
|
||||||
// Queen in corner, completely blocked by friendly pieces
|
|
||||||
let fen = "rnbqkbnr/pppppppp/8/8/8/8/PP1PP1PP/QNBQKBNR w Kkq - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
assert_moves_equal(&list.to_string(), "d1a4 d1b3 d1c2");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_queen_multiple_captures_black() {
|
|
||||||
// Black queen on h8, with multiple white pieces to capture
|
|
||||||
let fen = "q3k3/P1P1P1P1/8/8/8/P1P1P1P1/8/4K3 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
let expected = "a8b8 a8c8 a8d8 a8a7 a8b7 a8c6 a8d5 a8e4 a8f3 a8g2 a8h1";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_multiple_queens() {
|
|
||||||
let fen = "4k3/8/8/8/8/8/8/Q3K2Q w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
let expected = "a1a2 a1a3 a1a4 a1a5 a1a6 a1a7 a1a8 a1b1 a1c1 a1d1 a1b2 a1c3 a1d4 a1e5 a1f6 a1g7 a1h8 \
|
|
||||||
h1h2 h1h3 h1h4 h1h5 h1h6 h1h7 h1h8 h1g1 h1f1 h1g2 h1f3 h1e4 h1d5 h1c6 h1b7 h1a8";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_queen_rook_only() {
|
|
||||||
// Queen on d4, bishop moves blocked by friendly pawns
|
|
||||||
let fen = "4k3/8/8/2P1P3/3Q4/2P1P3/8/4K3 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
let expected = "d4a4 d4b4 d4c4 d4e4 d4f4 d4g4 d4h4 \
|
|
||||||
d4d1 d4d2 d4d3 d4d5 d4d6 d4d7 d4d8";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_queen_bishop_only() {
|
|
||||||
// Queen on d4, rook moves blocked by friendly pawns
|
|
||||||
let fen = "4k3/8/8/3P4/2PQP3/3P4/8/4K3 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_queen_moves(&board, &mut list);
|
|
||||||
let expected = "d4a1 d4b2 d4c3 d4e5 d4f6 d4g7 d4h8 \
|
|
||||||
d4a7 d4b6 d4c5 d4e3 d4f2 d4g1";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
use chess_engine::board::Board;
|
|
||||||
use chess_engine::movegen::sliders::generate_rook_moves;
|
|
||||||
use chess_engine::r#move::MoveList;
|
|
||||||
|
|
||||||
/// Compares two move list strings ignoring the order of moves.
|
|
||||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
|
||||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
|
||||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
|
||||||
|
|
||||||
actual_moves.sort();
|
|
||||||
expected_moves.sort();
|
|
||||||
|
|
||||||
assert_eq!(actual_moves, expected_moves);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
<<<<<<< HEAD
|
|
||||||
fn test_rook_moves_single_rook() {
|
|
||||||
=======
|
|
||||||
fn test_rook_moves_1() {
|
|
||||||
>>>>>>> origin/master
|
|
||||||
let fen_standard = "8/8/8/2b5/2Rb4/2b5/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen_standard);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
<<<<<<< HEAD
|
|
||||||
// This FEN has a White Rook at c4, and Black Bishops at c5, d4, and c3.
|
|
||||||
// It should be able to capture all three and move left to a4/b4.
|
|
||||||
assert_moves_equal(&list.to_string(), "c4a4 c4b4 c4c3 c4c5 c4d4");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rook_moves_empty_board() {
|
|
||||||
let fen = "8/8/8/8/3R4/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
let expected = "d4d1 d4d2 d4d3 d4d5 d4d6 d4d7 d4d8 d4a4 d4b4 d4c4 d4e4 d4f4 d4g4 d4h4";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rook_moves_corner_blocked_black() {
|
|
||||||
let fen = "r6k/1p6/8/8/8/8/8/K7 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
// Black rook at a8. Friendly king at h8, friendly pawn at b7.
|
|
||||||
// Rook can move down the a-file and right along the 8th rank, stopping before h8.
|
|
||||||
let expected = "a8a7 a8a6 a8a5 a8a4 a8a3 a8a2 a8a1 a8b8 a8c8 a8d8 a8e8 a8f8 a8g8";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rook_moves_double_rooks_friendly_block() {
|
|
||||||
let fen = "8/8/8/8/R3R3/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
// Rooks at a4 and e4. They block each other horizontally.
|
|
||||||
// Rook a4 moves a1-a8 and b4, c4, d4.
|
|
||||||
// Rook e4 moves e1-e8, f4, g4, h4 AND d4, c4, b4.
|
|
||||||
let expected = "a4a1 a4a2 a4a3 a4a5 a4a6 a4a7 a4a8 a4b4 a4c4 a4d4 \
|
|
||||||
e4e1 e4e2 e4e3 e4e5 e4e6 e4e7 e4e8 e4f4 e4g4 e4h4 \
|
|
||||||
e4d4 e4c4 e4b4";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rook_moves_capture_stops_movegen() {
|
|
||||||
let fen = "r7/P7/8/8/8/8/8/8 b - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
// Black rook at a8, White pawn at a7.
|
|
||||||
// The rook can capture at a7, but cannot move past it.
|
|
||||||
// It can still move horizontally.
|
|
||||||
let expected = "a8a7 a8b8 a8c8 a8d8 a8e8 a8f8 a8g8 a8h8";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rook_moves_completely_blocked_friendly() {
|
|
||||||
let fen = "8/8/8/1P6/PRP5/1P6/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
// White rook at b4.
|
|
||||||
// Blocked by P(b5), P(b3), P(a4), P(c4).
|
|
||||||
// Should have 0 moves.
|
|
||||||
assert_moves_equal(&list.to_string(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rook_moves_ignores_absolute_pin() {
|
|
||||||
let fen = "r3k3/8/8/8/R3K3/8/8/8 w - - 0 1";
|
|
||||||
let board = Board::from_fen(fen);
|
|
||||||
let mut list = MoveList::new();
|
|
||||||
generate_rook_moves(&board, &mut list);
|
|
||||||
// White rook at a4 is absolutely pinned to King at e4 by Black rook at a8.
|
|
||||||
// A pseudo-legal generator should *ignore* the pin.
|
|
||||||
// It should generate vertical moves (including capture at a8)
|
|
||||||
// and horizontal moves (stopping before the friendly King at e4).
|
|
||||||
let expected = "a4a1 a4a2 a4a3 a4a5 a4a6 a4a7 a4a8 a4b4 a4c4 a4d4";
|
|
||||||
assert_moves_equal(&list.to_string(), expected);
|
|
||||||
}
|
|
||||||
=======
|
|
||||||
// King is completely blocked in the start position
|
|
||||||
assert_moves_equal(&list.to_string(), "");
|
|
||||||
}
|
|
||||||
>>>>>>> origin/master
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue