summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAargh Rai <aargh.rai+git@gmail.com>2026-07-18 14:02:18 +0530
committerAargh Rai <aargh.rai+git@gmail.com>2026-07-18 14:04:14 +0530
commit9395e857db95481f6e2494d3a841632be0ff97c8 (patch)
treedfaa6ab66ea5dd083c060a5dba0cf41ed9cb754c
parentc34b4c1b036058b2906556850cc4ded6ececcf89 (diff)
fixed moved gen & adding messages on asserts
-rwxr-xr-x.gitignore1
-rw-r--r--Plan.md100
-rw-r--r--src/engine/moves.c31
-rw-r--r--src/uci/response.c2
-rw-r--r--src/uci/state.c4
5 files changed, 28 insertions, 110 deletions
diff --git a/.gitignore b/.gitignore
index 1db406c..ec795c3 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.direnv
build
*.o
generated
diff --git a/Plan.md b/Plan.md
deleted file mode 100644
index a300420..0000000
--- a/Plan.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Gacrux: Pseudo-Legal to Legal Move Conversion Plan
-
-## Current State
-- Move generators produce **pseudo-legal** moves (follow piece movement rules but ignore checks/pins)
-- `position_make_move()` has multiple bugs
-- No attack detection or legal move filtering exists
-- Perft test conditions are inverted
-
-## Phase 1: Fix Existing Bugs
-
-### `src/engine/moves.c` — `position_make_move()`
-1. **Lines 94, 100**: Add missing semicolons after `assert(0)`
-2. **Lines 54-55**: Black long castle modifies `WHITE_ROOK` → should be `BLACK_ROOK`
-3. **Lines 71-73**: Black short castle modifies `WHITE_KING`/`WHITE_ROOK` → should be `BLACK_KING`/`BLACK_ROOK`
-4. **Lines 96, 98**: `move.from` (u8) compared against `u64` bitboard constants → use square indices 63 and 56
-5. **Missing turn toggle**: `position->turn` never flips after a move
-
-### `test_perft_starting_position`
-6. **Lines 169-176**: `==` → `!=` (test currently passes when counts are wrong)
-
-## Phase 2: Attack Detection
-
-Create `src/engine/moves/attack.c` with:
-```c
-bool square_attacked(position_t position, square_t square, u8 by_color);
-```
-
-Checks if any piece of `by_color` attacks `square`:
-- **Pawn attacks**: Check diagonally forward for enemy pawns
-- **Knight attacks**: Use existing `knight_moves[64]` lookup
-- **King attacks**: Use existing `920078ULL` pattern
-- **Sliding attacks**: Walk rays from target square (for now, ray-walking)
-
-## Phase 3: Legal Move Filtering
-
-Modify `get_moves()` (or add `get_legal_moves()`) to:
-1. Generate all pseudo-legal moves
-2. For each move, make it on a copy of the position
-3. Find the friendly king in the resulting position
-4. Check if the friendly king is attacked by the opponent
-5. If attacked → remove the move (swap with last, decrement length)
-
-**Castling pre-checks** (in `king.c`):
-- King not currently in check
-- Squares king passes through are not attacked
-- No pieces between king and rook
-
-## Phase 4: Magic Bitboards (Performance Optimization)
-
-Replace ray-walking with O(1) magic lookups for sliding piece attacks.
-
-### Data Structure
-```c
-typedef struct {
- bitboard_t mask; // relevant occupancy bits (excludes edges)
- bitboard_t *attacks; // pointer into attack table
- bitboard_t magic; // the magic multiplier
- int shift; // 64 - popcount(mask)
-} magic_t;
-```
-
-### Attack Tables
-- `rook_attacks[0x19000]` (~100KB)
-- `bishop_attacks[0x1480]` (~5KB)
-
-### Index Computation
-```c
-unsigned index = ((occupied & magic.mask) * magic.magic) >> magic.shift;
-return magic.attacks[index];
-```
-
-### Initialization
-At startup, for each square:
-1. Compute mask (pseudo-attacks minus edges)
-2. Enumerate all subsets of the mask
-3. Compute true attacks via ray-walking (reference)
-4. Find magic number via PRNG search
-
-### Usage
-```c
-// Move generation
-bitboard_t attacks = get_rook_attacks(from_square, all_occupied);
-attacks &= ~friendly_pieces;
-
-// Attack detection
-bool square_attacked(...) {
- if (get_rook_attacks(sq, occ) & (enemy_rooks | enemy_queens)) return true;
- if (get_bishop_attacks(sq, occ) & (enemy_bishops | enemy_queens)) return true;
- // ...
-}
-```
-
-## Implementation Order
-1. Fix bugs (Phase 1)
-2. Add `square_attacked()` with ray-walking
-3. Add legal move filtering
-4. Fix castling legality
-5. Verify perft d0-d7
-6. Uncomment + verify Kiwipete perft
-7. Add magic bitboards (Phase 4)
diff --git a/src/engine/moves.c b/src/engine/moves.c
index 0c923a1..6f96109 100644
--- a/src/engine/moves.c
+++ b/src/engine/moves.c
@@ -76,7 +76,7 @@ int find_piece_on_square(position_t* p, int square) {
if ((p->bitboards[BLACK_BISHOP] >> square) & 1) return BLACK_BISHOP;
if ((p->bitboards[BLACK_KNIGHT] >> square) & 1) return BLACK_KNIGHT;
if ((p->bitboards[BLACK_PAWN] >> square) & 1) return BLACK_PAWN;
- assert(0);
+ assert(0 && "Failed to find the piece on the square");
}
void position_make_move(position_t* position, move_t move) {
@@ -140,24 +140,40 @@ void position_make_move(position_t* position, move_t move) {
}
if (move.flags & MOVE_PROMOTE_Q) {
+ if (move.flags & MOVE_CAPTURE) {
+ int to_remove_piece_type = find_piece_on_square(position, move.to);
+ position->bitboards[to_remove_piece_type] &= ~((bitboard_t)1 << move.to);
+ }
int q_type = position->turn == WHITE_TURN ? WHITE_QUEEN : BLACK_QUEEN;
position->bitboards[q_type] |= (bitboard_t)1 << move.to;
position->turn = !position->turn;
return;
}
if (move.flags & MOVE_PROMOTE_R) {
+ if (move.flags & MOVE_CAPTURE) {
+ int to_remove_piece_type = find_piece_on_square(position, move.to);
+ position->bitboards[to_remove_piece_type] &= ~((bitboard_t)1 << move.to);
+ }
int q_type = position->turn == WHITE_TURN ? WHITE_ROOK : BLACK_ROOK;
position->bitboards[q_type] |= (bitboard_t)1 << move.to;
position->turn = !position->turn;
return;
}
if (move.flags & MOVE_PROMOTE_B) {
+ if (move.flags & MOVE_CAPTURE) {
+ int to_remove_piece_type = find_piece_on_square(position, move.to);
+ position->bitboards[to_remove_piece_type] &= ~((bitboard_t)1 << move.to);
+ }
int q_type = position->turn == WHITE_TURN ? WHITE_BISHOP : BLACK_BISHOP;
position->bitboards[q_type] |= (bitboard_t)1 << move.to;
position->turn = !position->turn;
return;
}
if (move.flags & MOVE_PROMOTE_N) {
+ if (move.flags & MOVE_CAPTURE) {
+ int to_remove_piece_type = find_piece_on_square(position, move.to);
+ position->bitboards[to_remove_piece_type] &= ~((bitboard_t)1 << move.to);
+ }
int q_type = position->turn == WHITE_TURN ? WHITE_KNIGHT : BLACK_KNIGHT;
position->bitboards[q_type] |= (bitboard_t)1 << move.to;
position->turn = !position->turn;
@@ -206,6 +222,7 @@ int count_positions(position_t position, int depth) {
moves_t moves;
moves_init(&moves);
get_legal_moves(&moves, position);
+
int count = 0;
for (int i = 0; i < moves.length; i++) {
position_t copy = position;
@@ -221,6 +238,7 @@ void perft_divide(position_t position, int depth) {
moves_t moves;
moves_init(&moves);
get_legal_moves(&moves, position);
+
int nodes = 0;
for (int i = 0; i < moves.length; i++) {
position_t copy = position;
@@ -281,12 +299,11 @@ bool test_perft_position3() {
d = count_positions(position, 3); if (d != 2812) return false;
d = count_positions(position, 4); if (d != 43238) return false;
d = count_positions(position, 5); if (d != 674624) return false;
- perft_divide(position, 6);
- d = count_positions(position, 6);
- printf("%d\n", d);
- if (d != 11030083) return false;
- d = count_positions(position, 7); if (d != 178633661) return false;
- d = count_positions(position, 8); if (d != 3009794393) return false;
+ d = count_positions(position, 6); if (d != 11030083) return false;
+
+ // my move gen too slow to verify this
+ // d = count_positions(position, 7); if (d != 178633661) return false;
+ // d = count_positions(position, 8); if (d != 3009794393) return false;
return true;
}
diff --git a/src/uci/response.c b/src/uci/response.c
index da46cb7..ff89f8d 100644
--- a/src/uci/response.c
+++ b/src/uci/response.c
@@ -78,7 +78,7 @@ void handle_idle(uci_state_t *state, uci_cmd_t cmd) {
return;
}
state->position = fen.position;
- } else { assert(0); }
+ } else { assert(0 && "Invalid argument for position command"); }
if (cmd.args_count >= k) return;
assert(strcmp(uci_cmd_get_arg(cmd, k++), "moves") == 0);
diff --git a/src/uci/state.c b/src/uci/state.c
index ac043ed..012d951 100644
--- a/src/uci/state.c
+++ b/src/uci/state.c
@@ -104,7 +104,7 @@ void print_setting(option_setting_t setting) {
printf("string default %s\n", setting.data.string_default);
} else if (OPTION_BUTTON == setting.type) {
printf("button\n");
- } else { assert(0); }
+ } else { assert(0 && "Failed to print the options"); }
}
void uci_state_init(uci_state_t *state) {
@@ -207,7 +207,7 @@ void apply_option(uci_state_t *state, char *name, char *buffer) {
memcpy(setting.value.string->data, buffer, setting.value.string->length);
} else if (OPTION_BUTTON == setting.type) {
*setting.value.button = true;
- } else { assert(0); }
+ } else { assert(0 && "Failed to apply the option"); }
memcpy(state->option_settings + i, &setting, sizeof(setting));
return;