@@ -26,6 +26,8 @@ pub struct BoardMap {
2626 white_kingside_rook_moved : bool ,
2727 white_king_pos : Position ,
2828 black_king_pos : Position ,
29+ white_occupancy : u64 ,
30+ black_occupancy : u64 ,
2931}
3032
3133impl Default for BoardMap {
@@ -43,6 +45,8 @@ impl Default for BoardMap {
4345 white_kingside_rook_moved : false ,
4446 white_king_pos : [ 0 , 0 ] ,
4547 black_king_pos : [ 0 , 0 ] ,
48+ white_occupancy : 0 ,
49+ black_occupancy : 0 ,
4650 }
4751 }
4852}
@@ -80,6 +84,13 @@ impl BoardMap {
8084 let pos = [ index / 8 , index % 8 ] ;
8185 board. squares [ pos[ 0 ] ] [ pos[ 1 ] ] = Piece ( color | rank) ;
8286
87+ let bit = 1u64 << index;
88+ if color == WHITE {
89+ board. white_occupancy |= bit;
90+ } else {
91+ board. black_occupancy |= bit;
92+ }
93+
8394 // track king position
8495 if rank == KING {
8596 if color == WHITE {
@@ -824,13 +835,25 @@ impl BoardMap {
824835 promotion,
825836 ..
826837 } = position_move;
838+
839+ let from_bit = 1u64 << ( from[ 0 ] * 8 + from[ 1 ] ) ;
840+ let to_bit = 1u64 << ( to[ 0 ] * 8 + to[ 1 ] ) ;
841+
827842 if en_passant {
828843 let shift = if self . get_piece ( from) . get_color ( ) == PieceColor :: Black {
829844 1
830845 } else {
831846 -1
832847 } ;
833848 let to_step = [ ( to[ 0 ] as isize - shift) as usize , to[ 1 ] ] ;
849+ let ep_bit = 1u64 << ( to_step[ 0 ] * 8 + to_step[ 1 ] ) ;
850+
851+ // remove captured pawn from occupancy
852+ if self . get_piece ( from) . get_color ( ) == PieceColor :: White {
853+ self . black_occupancy ^= ep_bit;
854+ } else {
855+ self . white_occupancy ^= ep_bit;
856+ }
834857 self . set_piece ( to_step, 0 ) ;
835858 }
836859
@@ -887,17 +910,51 @@ impl BoardMap {
887910 // kingside castle - move rook from h-file to f-file
888911 let rook_from = [ from[ 0 ] , 7 ] ;
889912 let rook_to = [ from[ 0 ] , 5 ] ;
913+ let rook_from_bit = 1u64 << ( rook_from[ 0 ] * 8 + rook_from[ 1 ] ) ;
914+ let rook_to_bit = 1u64 << ( rook_to[ 0 ] * 8 + rook_to[ 1 ] ) ;
915+ if piece. get_color ( ) == PieceColor :: White {
916+ self . white_occupancy ^= rook_from_bit;
917+ self . white_occupancy |= rook_to_bit;
918+ } else {
919+ self . black_occupancy ^= rook_from_bit;
920+ self . black_occupancy |= rook_to_bit;
921+ }
890922 self . set_piece ( rook_to, self . get_piece ( rook_from) . 0 ) ;
891923 self . set_piece ( rook_from, 0 ) ;
892924 } else if from[ 1 ] == 4 && to[ 1 ] == 2 {
893925 // queenside castle - move rook from a-file to d-file
894926 let rook_from = [ from[ 0 ] , 0 ] ;
895927 let rook_to = [ from[ 0 ] , 3 ] ;
928+ let rook_from_bit = 1u64 << ( rook_from[ 0 ] * 8 + rook_from[ 1 ] ) ;
929+ let rook_to_bit = 1u64 << ( rook_to[ 0 ] * 8 + rook_to[ 1 ] ) ;
930+ if piece. get_color ( ) == PieceColor :: White {
931+ self . white_occupancy ^= rook_from_bit;
932+ self . white_occupancy |= rook_to_bit;
933+ } else {
934+ self . black_occupancy ^= rook_from_bit;
935+ self . black_occupancy |= rook_to_bit;
936+ }
896937 self . set_piece ( rook_to, self . get_piece ( rook_from) . 0 ) ;
897938 self . set_piece ( rook_from, 0 ) ;
898939 }
899940 }
900941
942+ let target_piece = self . get_piece ( to) ;
943+ if piece. get_color ( ) == PieceColor :: White {
944+ self . white_occupancy ^= from_bit;
945+ self . white_occupancy |= to_bit;
946+
947+ if target_piece. is_piece ( ) {
948+ self . black_occupancy ^= to_bit;
949+ }
950+ } else {
951+ self . black_occupancy ^= from_bit;
952+ self . black_occupancy |= to_bit;
953+ if target_piece. is_piece ( ) {
954+ self . white_occupancy ^= to_bit;
955+ }
956+ }
957+
901958 if promotion {
902959 let color = match self . get_piece ( from) . get_color ( ) {
903960 PieceColor :: Black => BLACK ,
@@ -929,24 +986,60 @@ impl BoardMap {
929986 ..
930987 } = piece_move;
931988
989+ let from_bit = 1u64 << ( from[ 0 ] * 8 + from[ 1 ] ) ;
990+ let to_bit = 1u64 << ( to[ 0 ] * 8 + to[ 1 ] ) ;
991+
932992 // undo castling rook movement if this was a castling move
933993 let piece = self . get_piece ( to) ;
934994 if let Some ( PieceType :: King ) = piece. get_type ( ) {
935995 if from[ 1 ] == 4 && to[ 1 ] == 6 {
936996 // undo kingside castle - move rook back from f-file to h-file
937997 let rook_from = [ from[ 0 ] , 5 ] ;
938998 let rook_to = [ from[ 0 ] , 7 ] ;
999+ let rook_from_bit = 1u64 << ( rook_from[ 0 ] * 8 + rook_from[ 1 ] ) ;
1000+ let rook_to_bit = 1u64 << ( rook_to[ 0 ] * 8 + rook_to[ 1 ] ) ;
1001+ if piece. get_color ( ) == PieceColor :: White {
1002+ self . white_occupancy ^= rook_from_bit;
1003+ self . white_occupancy |= rook_to_bit;
1004+ } else {
1005+ self . black_occupancy ^= rook_from_bit;
1006+ self . black_occupancy |= rook_to_bit;
1007+ }
9391008 self . set_piece ( rook_to, self . get_piece ( rook_from) . 0 ) ;
9401009 self . set_piece ( rook_from, 0 ) ;
9411010 } else if from[ 1 ] == 4 && to[ 1 ] == 2 {
9421011 // undo queenside castle - move rook back from d-file to a-file
9431012 let rook_from = [ from[ 0 ] , 3 ] ;
9441013 let rook_to = [ from[ 0 ] , 0 ] ;
1014+ let rook_from_bit = 1u64 << ( rook_from[ 0 ] * 8 + rook_from[ 1 ] ) ;
1015+ let rook_to_bit = 1u64 << ( rook_to[ 0 ] * 8 + rook_to[ 1 ] ) ;
1016+ if piece. get_color ( ) == PieceColor :: White {
1017+ self . white_occupancy ^= rook_from_bit;
1018+ self . white_occupancy |= rook_to_bit;
1019+ } else {
1020+ self . black_occupancy ^= rook_from_bit;
1021+ self . black_occupancy |= rook_to_bit;
1022+ }
9451023 self . set_piece ( rook_to, self . get_piece ( rook_from) . 0 ) ;
9461024 self . set_piece ( rook_from, 0 ) ;
9471025 }
9481026 }
9491027
1028+ if piece. get_color ( ) == PieceColor :: White {
1029+ self . white_occupancy ^= to_bit;
1030+ self . white_occupancy |= from_bit;
1031+
1032+ if last_piece != 0 {
1033+ self . black_occupancy |= to_bit;
1034+ }
1035+ } else {
1036+ self . black_occupancy ^= to_bit;
1037+ self . black_occupancy |= from_bit;
1038+ if last_piece != 0 {
1039+ self . white_occupancy |= to_bit;
1040+ }
1041+ }
1042+
9501043 self . set_piece ( from, self . get_piece ( to) . 0 ) ;
9511044 self . set_piece ( to, last_piece) ;
9521045
@@ -959,6 +1052,13 @@ impl BoardMap {
9591052 -1
9601053 } ;
9611054 let captured_pawn_pos = [ ( to[ 0 ] as isize - shift) as usize , to[ 1 ] ] ;
1055+ let ep_bit = 1u64 << ( captured_pawn_pos[ 0 ] * 8 + captured_pawn_pos[ 1 ] ) ;
1056+ // Restore captured pawn in occupancy
1057+ if moving_piece. get_color ( ) == PieceColor :: White {
1058+ self . black_occupancy |= ep_bit;
1059+ } else {
1060+ self . white_occupancy |= ep_bit;
1061+ }
9621062 // restore the captured pawn (it was the opponent's pawn with en-passant flag)
9631063 let opponent_color = if moving_piece. get_color ( ) == PieceColor :: Black {
9641064 WHITE
@@ -971,33 +1071,48 @@ impl BoardMap {
9711071 /// generates all moves based on active color.
9721072 pub fn gen_all_legal_moves ( & self ) -> Vec < PositionMove > {
9731073 let mut legal_moves = vec ! [ ] ;
974- for rank in 0 ..8 {
975- for file in 0 ..8 {
976- let piece = self . squares [ rank] [ file] ;
977- if piece. is_piece ( ) && piece. get_color ( ) == self . active_color {
978- let from_move = [ rank, file] ;
979- let to_moves = self . gen_legal_positions ( [ rank, file] ) ;
980- let moves = to_moves
981- . iter ( )
982- . map ( |& to| PositionMove :: new ( from_move, to) )
983- . collect :: < Vec < _ > > ( ) ;
984- legal_moves. extend ( moves) ;
985- }
986- }
1074+
1075+ let mut active_bits = if self . active_color == PieceColor :: White {
1076+ self . white_occupancy
1077+ } else {
1078+ self . black_occupancy
1079+ } ;
1080+
1081+ while active_bits != 0 {
1082+ let square_idx = active_bits. trailing_zeros ( ) as usize ;
1083+ active_bits ^= 1u64 << square_idx; // Clear the bit
1084+
1085+ let from_move = [ square_idx / 8 , square_idx % 8 ] ;
1086+ let to_moves = self . gen_legal_positions ( from_move) ;
1087+ let moves = to_moves
1088+ . iter ( )
1089+ . map ( |& to| PositionMove :: new ( from_move, to) )
1090+ . collect :: < Vec < _ > > ( ) ;
1091+ legal_moves. extend ( moves) ;
9871092 }
1093+
9881094 legal_moves
9891095 }
9901096 pub fn gen_all_opponent_positions ( & self ) -> Vec < Position > {
9911097 let mut opponent_positions = vec ! [ ] ;
992- for rank in 0 ..8 {
993- for file in 0 ..8 {
994- let piece = self . squares [ rank] [ file] ;
995- if piece. is_piece ( ) && piece. get_color ( ) != self . active_color {
996- let positions = self . gen_to_positions ( [ rank, file] ) ;
997- opponent_positions. extend ( positions) ;
998- }
999- }
1098+
1099+ // Use bitboard to iterate only over opponent pieces
1100+ let mut opponent_bits = if self . active_color == PieceColor :: White {
1101+ self . black_occupancy
1102+ } else {
1103+ self . white_occupancy
1104+ } ;
1105+
1106+ // Iterate through set bits (opponent pieces)
1107+ while opponent_bits != 0 {
1108+ let square_idx = opponent_bits. trailing_zeros ( ) as usize ;
1109+ opponent_bits ^= 1u64 << square_idx; // Clear the bit
1110+
1111+ let pos = [ square_idx / 8 , square_idx % 8 ] ;
1112+ let positions = self . gen_to_positions ( pos) ;
1113+ opponent_positions. extend ( positions) ;
10001114 }
1115+
10011116 opponent_positions
10021117 }
10031118 pub fn is_en_passant ( & self , from : Position , to : Position ) -> bool {
0 commit comments